diff --git a/BUILD.gn b/BUILD.gn index 3c4534f..4ffa9a8ce 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -758,7 +758,6 @@ ":chrome_official_builder_no_unittests", "//base:base_unittests", "//chrome/test:browser_tests", - "//chrome/test:sync_integration_tests", "//ipc:ipc_tests", "//media:media_unittests", "//media/midi:midi_unittests",
diff --git a/DEPS b/DEPS index b057a45..9544515 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # 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': '227fee38565ad52dff45c6619c28c6b6990cea5d', + 'v8_revision': '71c1795aea7573672dd264568357c0f49afc7321', # 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. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '827db14d7f3d0085253b686587717361ffbcad1b', + 'pdfium_revision': '66568bcd683dd7b18672cb3aebca4487e9203519', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # 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': '67894d267da3cd26af31413ec51764f5baabee26', + 'catapult_revision': '9c9ac13a2b028b9aa24257dc9e669eda29a301ea', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -199,7 +199,7 @@ Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0', 'src/third_party/webgl/src': - Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '40d75ac0e565191d93ff3c4e8fd19f8b2df7f617', + Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f7157c2751220a8f0def9f3f7f6ff37392ac83f0', 'src/third_party/webdriver/pylib': Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd', @@ -484,10 +484,10 @@ Var('chromium_git') + '/external/mockito/mockito.git' + '@' + 'de83ad4598ad4cf5ea53c69a8a8053780b04b850', 'src/third_party/netty-tcnative/src': - Var('chromium_git') + '/external/netty-tcnative.git' + '@' + '2a25ec75d6889d32594a6f8b4d42962c15255d76', + Var('chromium_git') + '/external/netty-tcnative.git' + '@' + '5b46a8ef4a39c39c576fcdaaf718b585d75df463', 'src/third_party/netty4/src': - Var('chromium_git') + '/external/netty4.git' + '@' + 'e0f26303b4ce635365be19414d0ac81f2ef6ba3c', + Var('chromium_git') + '/external/netty4.git' + '@' + 'cc4420b13bb4eeea5b1cf4f93b2755644cd3b120', 'src/third_party/robolectric/robolectric': Var('chromium_git') + '/external/robolectric.git' + '@' + '2a0b6ba221c14f3371813a676ce06143353e448d', @@ -505,7 +505,7 @@ Var('chromium_git') + '/external/github.com/kennethreitz/requests.git' + '@' + 'f172b30356d821d180fa4ecfa3e71c7274a32de4', 'src/third_party/custom_tabs_client/src': - Var('chromium_git') + '/external/github.com/GoogleChrome/custom-tabs-client.git' + '@' + '3c95e2dda9b292653ff13454f093e5ff136814d2', + Var('chromium_git') + '/external/github.com/GoogleChrome/custom-tabs-client.git' + '@' + '4889dd9d552d24f08584dde29f639c0da4ea0f12', 'src/third_party/gvr-android-sdk/src': Var('chromium_git') + '/external/github.com/googlevr/gvr-android-sdk.git' + '@' + '8d1395957283ee13ebe2bc672ba24e5ca4ec343f',
diff --git a/ash/mus/move_event_handler.cc b/ash/mus/move_event_handler.cc index 6c89fa9f..0051d49 100644 --- a/ash/mus/move_event_handler.cc +++ b/ash/mus/move_event_handler.cc
@@ -10,6 +10,7 @@ #include "ui/aura/mus/window_manager_delegate.h" #include "ui/aura/window.h" #include "ui/base/class_property.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/hit_test.h" #include "ui/events/event.h" @@ -28,26 +29,26 @@ namespace mus { namespace { -ui::mojom::CursorType CursorForWindowComponent(int window_component) { +ui::CursorType CursorForWindowComponent(int window_component) { switch (window_component) { case HTBOTTOM: - return ui::mojom::CursorType::kSouthResize; + return ui::CursorType::kSouthResize; case HTBOTTOMLEFT: - return ui::mojom::CursorType::kSouthWestResize; + return ui::CursorType::kSouthWestResize; case HTBOTTOMRIGHT: - return ui::mojom::CursorType::kSouthEastResize; + return ui::CursorType::kSouthEastResize; case HTLEFT: - return ui::mojom::CursorType::kWestResize; + return ui::CursorType::kWestResize; case HTRIGHT: - return ui::mojom::CursorType::kEastResize; + return ui::CursorType::kEastResize; case HTTOP: - return ui::mojom::CursorType::kNorthResize; + return ui::CursorType::kNorthResize; case HTTOPLEFT: - return ui::mojom::CursorType::kNorthWestResize; + return ui::CursorType::kNorthWestResize; case HTTOPRIGHT: - return ui::mojom::CursorType::kNorthEastResize; + return ui::CursorType::kNorthEastResize; default: - return ui::mojom::CursorType::kNull; + return ui::CursorType::kNull; } } @@ -122,7 +123,8 @@ const int hit_test_location = wm_window_->GetNonClientComponent(event->location()); window_manager_client_->SetNonClientCursor( - wm_window_->aura_window(), CursorForWindowComponent(hit_test_location)); + wm_window_->aura_window(), + ui::CursorData(CursorForWindowComponent(hit_test_location))); } WorkspaceEventHandlerMus* workspace_event_handler =
diff --git a/ash/system/brightness/tray_brightness_unittest.cc b/ash/system/brightness/tray_brightness_unittest.cc index 4819859..e1f4e08 100644 --- a/ash/system/brightness/tray_brightness_unittest.cc +++ b/ash/system/brightness/tray_brightness_unittest.cc
@@ -9,13 +9,13 @@ #include "ash/shell.h" #include "ash/system/tray/system_tray_delegate.h" #include "ash/system/tray/system_tray_item.h" -#include "ash/test/ash_test.h" +#include "ash/test/ash_test_base.h" #include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ui/views/view.h" namespace ash { -class TrayBrightnessTest : public AshTest { +class TrayBrightnessTest : public test::AshTestBase { public: TrayBrightnessTest() {} ~TrayBrightnessTest() override {}
diff --git a/ash/system/date/date_view_unittest.cc b/ash/system/date/date_view_unittest.cc index 7d5d510e..ea6df969 100644 --- a/ash/system/date/date_view_unittest.cc +++ b/ash/system/date/date_view_unittest.cc
@@ -4,13 +4,13 @@ #include "ash/system/date/date_view.h" -#include "ash/test/ash_test.h" +#include "ash/test/ash_test_base.h" #include "ui/views/controls/label.h" namespace ash { namespace tray { -class TimeViewTest : public AshTest { +class TimeViewTest : public test::AshTestBase { public: TimeViewTest() {} ~TimeViewTest() override {}
diff --git a/ash/system/screen_security/screen_tray_item_unittest.cc b/ash/system/screen_security/screen_tray_item_unittest.cc index 5c7d9d2..122c478 100644 --- a/ash/system/screen_security/screen_tray_item_unittest.cc +++ b/ash/system/screen_security/screen_tray_item_unittest.cc
@@ -10,7 +10,7 @@ #include "ash/system/tray/system_tray.h" #include "ash/system/tray/system_tray_notifier.h" #include "ash/system/tray/tray_item_view.h" -#include "ash/test/ash_test.h" +#include "ash/test/ash_test_base.h" #include "base/callback.h" #include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" @@ -36,7 +36,7 @@ ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE)); } -class ScreenTrayItemTest : public AshTest { +class ScreenTrayItemTest : public test::AshTestBase { public: ScreenTrayItemTest() : tray_item_(NULL), stop_callback_hit_count_(0) {} ~ScreenTrayItemTest() override {} @@ -47,7 +47,7 @@ int stop_callback_hit_count() const { return stop_callback_hit_count_; } void SetUp() override { - AshTest::SetUp(); + AshTestBase::SetUp(); TrayItemView::DisableAnimationsForTest(); } @@ -192,7 +192,7 @@ EXPECT_FALSE(tray_item->tray_view()->visible()); std::vector<SystemTrayItem*> tray_items = - AshTest::GetPrimarySystemTray()->GetTrayItems(); + test::AshTestBase::GetPrimarySystemTray()->GetTrayItems(); EXPECT_NE(std::find(tray_items.begin(), tray_items.end(), tray_item), tray_items.end()); @@ -200,16 +200,16 @@ EXPECT_TRUE(tray_item->tray_view()->visible()); // The default view should be created in a new bubble. - AshTest::GetPrimarySystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); + test::AshTestBase::GetPrimarySystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); EXPECT_TRUE(tray_item->default_view()); - AshTest::GetPrimarySystemTray()->CloseSystemBubble(); + test::AshTestBase::GetPrimarySystemTray()->CloseSystemBubble(); EXPECT_FALSE(tray_item->default_view()); test->StopSession(); EXPECT_FALSE(tray_item->tray_view()->visible()); // The default view should not be visible because session is stopped. - AshTest::GetPrimarySystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); + test::AshTestBase::GetPrimarySystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); EXPECT_FALSE(tray_item->default_view()->visible()); }
diff --git a/ash/system/tray/hover_highlight_view.cc b/ash/system/tray/hover_highlight_view.cc index e96272b6..9df8b65 100644 --- a/ash/system/tray/hover_highlight_view.cc +++ b/ash/system/tray/hover_highlight_view.cc
@@ -57,11 +57,13 @@ void HoverHighlightView::SetSubText(const base::string16& sub_text) { DCHECK(text_label_); + DCHECK(!sub_text.empty()); if (!sub_text_label_) { sub_text_label_ = TrayPopupUtils::CreateDefaultLabel(); tri_view_->AddView(TriView::Container::CENTER, sub_text_label_); } + TrayPopupItemStyle sub_style(TrayPopupItemStyle::FontStyle::CAPTION); sub_style.set_color_style(TrayPopupItemStyle::ColorStyle::INACTIVE); sub_style.SetupLabel(sub_text_label_); @@ -117,7 +119,8 @@ style.SetupLabel(text_label_); tri_view_->AddView(TriView::Container::CENTER, text_label_); - SetSubText(sub_text); + if (!sub_text.empty()) + SetSubText(sub_text); tri_view_->SetContainerVisible(TriView::Container::END, false);
diff --git a/ash/system/tray/hover_highlight_view.h b/ash/system/tray/hover_highlight_view.h index 4283c53..6c60bfc 100644 --- a/ash/system/tray/hover_highlight_view.h +++ b/ash/system/tray/hover_highlight_view.h
@@ -69,8 +69,8 @@ // Hide or show the right view. void SetRightViewVisible(bool visible); - // Sets text for the sub label. Precondition for this function is that - // |text_label_| is non-null. + // Sets the text of |sub_text_label_| to |sub_text|. Prior to calling this + // function, |text_label_| must not be null and |sub_text| must not be empty. void SetSubText(const base::string16& sub_text); // Allows view to expand its height. Size of unexapandable view is fixed and
diff --git a/ash/wm/ash_focus_rules.cc b/ash/wm/ash_focus_rules.cc index ac4d9a8..21f7f023 100644 --- a/ash/wm/ash_focus_rules.cc +++ b/ash/wm/ash_focus_rules.cc
@@ -13,7 +13,9 @@ #include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm_window.h" +#include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" +#include "ui/events/event.h" namespace ash { namespace wm { @@ -33,13 +35,9 @@ //////////////////////////////////////////////////////////////////////////////// // AshFocusRules, public: -AshFocusRules::AshFocusRules() {} +AshFocusRules::AshFocusRules() = default; -AshFocusRules::~AshFocusRules() {} - -bool AshFocusRules::IsWindowConsideredActivatable(aura::Window* window) const { - return ash::IsWindowConsideredActivatable(WmWindow::Get(window)); -} +AshFocusRules::~AshFocusRules() = default; //////////////////////////////////////////////////////////////////////////////// // AshFocusRules, ::wm::FocusRules: @@ -73,6 +71,19 @@ return true; } +bool AshFocusRules::CanFocusWindow(aura::Window* window, + const ui::Event* event) const { + if (!window) + return true; + + if (event && (event->IsMouseEvent() || event->IsGestureEvent()) && + !window->GetProperty(aura::client::kActivateOnPointerKey)) { + return false; + } + + return BaseFocusRules::CanFocusWindow(window, event); +} + aura::Window* AshFocusRules::GetNextActivatableWindow( aura::Window* ignore) const { DCHECK(ignore); @@ -141,7 +152,7 @@ !window_state->IsMinimized()) return *i; } - return NULL; + return nullptr; } } // namespace wm
diff --git a/ash/wm/ash_focus_rules.h b/ash/wm/ash_focus_rules.h index 97546cd..75f5f4f 100644 --- a/ash/wm/ash_focus_rules.h +++ b/ash/wm/ash_focus_rules.h
@@ -18,10 +18,6 @@ AshFocusRules(); ~AshFocusRules() override; - // Tests if the given |window| can be activated, ignoring the system modal - // dialog state. - bool IsWindowConsideredActivatable(aura::Window* window) const; - private: // ::wm::BaseFocusRules: bool IsToplevelWindow(aura::Window* window) const override; @@ -29,6 +25,8 @@ bool IsWindowConsideredVisibleForActivation( aura::Window* window) const override; bool CanActivateWindow(aura::Window* window) const override; + bool CanFocusWindow(aura::Window* window, + const ui::Event* event) const override; aura::Window* GetNextActivatableWindow(aura::Window* ignore) const override; aura::Window* GetTopmostWindowToActivateForContainerIndex(
diff --git a/ash/wm/mru_window_tracker_unittest.cc b/ash/wm/mru_window_tracker_unittest.cc index 9463941f..97364ca 100644 --- a/ash/wm/mru_window_tracker_unittest.cc +++ b/ash/wm/mru_window_tracker_unittest.cc
@@ -6,20 +6,22 @@ #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/test/ash_test.h" +#include "ash/test/ash_test_base.h" #include "ash/wm/window_state.h" +#include "ash/wm/window_state_aura.h" +#include "ash/wm/window_util.h" #include "ash/wm_window.h" #include "ui/base/hit_test.h" namespace ash { -class MruWindowTrackerTest : public AshTest { +class MruWindowTrackerTest : public test::AshTestBase { public: MruWindowTrackerTest() {} ~MruWindowTrackerTest() override {} - std::unique_ptr<WindowOwner> CreateTestWindow() { - return AshTest::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); + std::unique_ptr<aura::Window> CreateTestWindow() { + return AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); } MruWindowTracker* mru_window_tracker() { @@ -32,75 +34,66 @@ // Basic test that the activation order is tracked. TEST_F(MruWindowTrackerTest, Basic) { - std::unique_ptr<WindowOwner> w1_owner(CreateTestWindow()); - WmWindow* w1 = w1_owner->window(); - std::unique_ptr<WindowOwner> w2_owner(CreateTestWindow()); - WmWindow* w2 = w2_owner->window(); - std::unique_ptr<WindowOwner> w3_owner(CreateTestWindow()); - WmWindow* w3 = w3_owner->window(); - w3->Activate(); - w2->Activate(); - w1->Activate(); + std::unique_ptr<aura::Window> w1(CreateTestWindow()); + std::unique_ptr<aura::Window> w2(CreateTestWindow()); + std::unique_ptr<aura::Window> w3(CreateTestWindow()); + wm::ActivateWindow(w3.get()); + wm::ActivateWindow(w2.get()); + wm::ActivateWindow(w1.get()); WmWindow::Windows window_list = mru_window_tracker()->BuildMruWindowList(); ASSERT_EQ(3u, window_list.size()); - EXPECT_EQ(w1, window_list[0]); - EXPECT_EQ(w2, window_list[1]); - EXPECT_EQ(w3, window_list[2]); + EXPECT_EQ(w1.get(), window_list[0]->aura_window()); + EXPECT_EQ(w2.get(), window_list[1]->aura_window()); + EXPECT_EQ(w3.get(), window_list[2]->aura_window()); } // Test that minimized windows are not treated specially. TEST_F(MruWindowTrackerTest, MinimizedWindowsAreLru) { - std::unique_ptr<WindowOwner> w1_owner(CreateTestWindow()); - WmWindow* w1 = w1_owner->window(); - std::unique_ptr<WindowOwner> w2_owner(CreateTestWindow()); - WmWindow* w2 = w2_owner->window(); - std::unique_ptr<WindowOwner> w3_owner(CreateTestWindow()); - WmWindow* w3 = w3_owner->window(); - std::unique_ptr<WindowOwner> w4_owner(CreateTestWindow()); - WmWindow* w4 = w4_owner->window(); - std::unique_ptr<WindowOwner> w5_owner(CreateTestWindow()); - WmWindow* w5 = w5_owner->window(); - std::unique_ptr<WindowOwner> w6_owner(CreateTestWindow()); - WmWindow* w6 = w6_owner->window(); - w6->Activate(); - w5->Activate(); - w4->Activate(); - w3->Activate(); - w2->Activate(); - w1->Activate(); + std::unique_ptr<aura::Window> w1(CreateTestWindow()); + std::unique_ptr<aura::Window> w2(CreateTestWindow()); + std::unique_ptr<aura::Window> w3(CreateTestWindow()); + std::unique_ptr<aura::Window> w4(CreateTestWindow()); + std::unique_ptr<aura::Window> w5(CreateTestWindow()); + std::unique_ptr<aura::Window> w6(CreateTestWindow()); + wm::ActivateWindow(w6.get()); + wm::ActivateWindow(w5.get()); + wm::ActivateWindow(w4.get()); + wm::ActivateWindow(w3.get()); + wm::ActivateWindow(w2.get()); + wm::ActivateWindow(w1.get()); - w1->GetWindowState()->Minimize(); - w4->GetWindowState()->Minimize(); - w5->GetWindowState()->Minimize(); + wm::GetWindowState(w1.get())->Minimize(); + wm::GetWindowState(w4.get())->Minimize(); + wm::GetWindowState(w5.get())->Minimize(); // By minimizing the first window, we activate w2 which will move it to the // front of the MRU queue. - EXPECT_TRUE(w2->IsActive()); + EXPECT_TRUE(wm::IsActiveWindow(w2.get())); WmWindow::Windows window_list = mru_window_tracker()->BuildMruWindowList(); - EXPECT_EQ(w2, window_list[0]); - EXPECT_EQ(w1, window_list[1]); - EXPECT_EQ(w3, window_list[2]); - EXPECT_EQ(w4, window_list[3]); - EXPECT_EQ(w5, window_list[4]); - EXPECT_EQ(w6, window_list[5]); + EXPECT_EQ(w2.get(), window_list[0]->aura_window()); + EXPECT_EQ(w1.get(), window_list[1]->aura_window()); + EXPECT_EQ(w3.get(), window_list[2]->aura_window()); + EXPECT_EQ(w4.get(), window_list[3]->aura_window()); + EXPECT_EQ(w5.get(), window_list[4]->aura_window()); + EXPECT_EQ(w6.get(), window_list[5]->aura_window()); } // Tests that windows being dragged are only in the WindowList once. TEST_F(MruWindowTrackerTest, DraggedWindowsInListOnlyOnce) { - std::unique_ptr<WindowOwner> w1_owner(CreateTestWindow()); - WmWindow* w1 = w1_owner->window(); - w1->Activate(); + std::unique_ptr<aura::Window> w1(CreateTestWindow()); + wm::ActivateWindow(w1.get()); // Start dragging the window. - w1->GetWindowState()->CreateDragDetails( + wm::GetWindowState(w1.get())->CreateDragDetails( gfx::Point(), HTRIGHT, aura::client::WINDOW_MOVE_SOURCE_TOUCH); // The dragged window should only be in the list once. WmWindow::Windows window_list = mru_window_tracker()->BuildWindowListIgnoreModal(); - EXPECT_EQ(1, std::count(window_list.begin(), window_list.end(), w1)); + EXPECT_EQ(1, std::count(window_list.begin(), window_list.end(), + WmWindow::Get(w1.get()))); } } // namespace ash
diff --git a/ash/wm/window_manager_unittest.cc b/ash/wm/window_manager_unittest.cc index 38667af..4183276 100644 --- a/ash/wm/window_manager_unittest.cc +++ b/ash/wm/window_manager_unittest.cc
@@ -8,6 +8,7 @@ #include "ash/test/ash_test_base.h" #include "ash/test/test_activation_delegate.h" #include "ash/wm/window_util.h" +#include "ui/aura/client/aura_constants.h" #include "ui/aura/client/cursor_client_observer.h" #include "ui/aura/client/focus_client.h" #include "ui/aura/env.h" @@ -349,6 +350,45 @@ } } +// Tests that Set window property |kActivateOnPointerKey| to false could +// properly ignore pointer window activation. +TEST_F(WindowManagerTest, ActivateOnPointerWindowProperty) { + // Create two test windows, window1 and window2. + aura::test::TestWindowDelegate wd; + std::unique_ptr<aura::Window> w1( + CreateTestWindowInShellWithDelegate(&wd, -1, gfx::Rect(10, 10, 50, 50))); + std::unique_ptr<aura::Window> w2( + CreateTestWindowInShellWithDelegate(&wd, -2, gfx::Rect(70, 70, 50, 50))); + + // Activate window1. + wm::ActivateWindow(w1.get()); + EXPECT_TRUE(wm::IsActiveWindow(w1.get())); + EXPECT_FALSE(wm::IsActiveWindow(w2.get())); + + // Set window2 not pointer activatable. + w2->SetProperty(aura::client::kActivateOnPointerKey, false); + // Mouse click on window2. + ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), w2.get()); + generator.ClickLeftButton(); + // Window2 should not become active. + EXPECT_FALSE(wm::IsActiveWindow(w2.get())); + EXPECT_TRUE(wm::IsActiveWindow(w1.get())); + + // Gesture a tap at window2. + generator.GestureTapAt(w2->bounds().CenterPoint()); + // Window2 should not become active. + EXPECT_FALSE(wm::IsActiveWindow(w2.get())); + EXPECT_TRUE(wm::IsActiveWindow(w1.get())); + + // Set window2 now pointer activatable. + w2->SetProperty(aura::client::kActivateOnPointerKey, true); + // Mouse click on window2. + generator.ClickLeftButton(); + // Window2 should become active. + EXPECT_TRUE(wm::IsActiveWindow(w2.get())); + EXPECT_FALSE(wm::IsActiveWindow(w1.get())); +} + TEST_F(WindowManagerTest, PanelActivation) { aura::test::TestWindowDelegate wd; std::unique_ptr<aura::Window> w1(
diff --git a/build/android/pylib/results/presentation/test_results_presentation.py b/build/android/pylib/results/presentation/test_results_presentation.py index d7e2b5a..07f30c2 100755 --- a/build/android/pylib/results/presentation/test_results_presentation.py +++ b/build/android/pylib/results/presentation/test_results_presentation.py
@@ -306,6 +306,7 @@ return '%s/%s/%s' % (server_url, bucket, dest) + def main(): parser = argparse.ArgumentParser() parser.add_argument('--json-file', help='Path of json file.') @@ -347,16 +348,21 @@ if ((args.build_properties is None) == (args.build_number is None or args.builder_name is None)): raise parser.error('Exactly one of build_perperties or ' - '(build_number or builder_names) should be given.') + '(build_number or builder_name) should be given.') if (args.build_number is None) != (args.builder_name is None): raise parser.error('args.build_number and args.builder_name ' - 'has to be be given together' - 'or not given at all.') + 'has to be be given together' + 'or not given at all.') - if (len(args.positional) == 0) == (args.json_file is None): + if len(args.positional) == 0 and args.json_file is None: + if args.output_json: + with open(args.output_json, 'w') as f: + json.dump({}, f) + return + elif len(args.positional) != 0 and args.json_file: raise parser.error('Exactly one of args.positional and ' - 'args.json_file should be given.') + 'args.json_file should be given.') if args.build_properties: build_properties = json.loads(args.build_properties)
diff --git a/build/check_gn_headers.py b/build/check_gn_headers.py index be1e797a..73f1593 100755 --- a/build/check_gn_headers.py +++ b/build/check_gn_headers.py
@@ -76,7 +76,12 @@ all_headers = set() for _target, properties in gn['targets'].iteritems(): - for f in properties.get('sources', []): + sources = properties.get('sources', []) + public = properties.get('public', []) + # Exclude '"public": "*"'. + if type(public) is list: + sources += public + for f in sources: if f.endswith('.h') or f.endswith('.hh'): if f.startswith('//'): f = f[2:] # Strip the '//' prefix.
diff --git a/build/check_gn_headers_unittest.py b/build/check_gn_headers_unittest.py index f62fe62..892fa66 100755 --- a/build/check_gn_headers_unittest.py +++ b/build/check_gn_headers_unittest.py
@@ -38,8 +38,14 @@ "//:All": { }, "//:base": { + "public": [ "//base/p.h" ], "sources": [ "//base/a.cc", "//base/a.h", "//base/b.hh" ], "visibility": [ "*" ] + }, + "//:star_public": { + "public": "*", + "sources": [ "//base/c.h" ], + "visibility": [ "*" ] } } } @@ -88,6 +94,8 @@ expected = set([ 'base/a.h', 'base/b.hh', + 'base/c.h', + 'base/p.h', ]) self.assertEquals(headers, expected)
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc index 6e8cf704..177b6b2 100644 --- a/cc/layers/scrollbar_layer_unittest.cc +++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -753,6 +753,7 @@ scroll_layer->element_id())); scroll_layer->SetBounds(gfx::Size(20, 20)); + scroll_layer->ShowScrollbars(); scroll_layer->SetForceRenderSurfaceForTesting(true); layer_tree_host_->UpdateLayers(); host_impl->CreatePendingTree();
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 5d38bf5..1e4d4fd 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -340,6 +340,8 @@ tile_manager_.TakeImagesToInvalidateOnSyncTree()); if (CommitToActiveTree()) { + active_tree_->HandleScrollbarShowRequestsFromMain(); + // We have to activate animations here or "IsActive()" is true on the layers // but the animations aren't activated yet so they get ignored by // UpdateDrawProperties. @@ -3283,8 +3285,9 @@ DistributeScrollDelta(scroll_state); - active_tree_->SetCurrentlyScrollingNode( - scroll_state->current_native_scrolling_node()); + ScrollNode* current_scrolling_node = + scroll_state->current_native_scrolling_node(); + active_tree_->SetCurrentlyScrollingNode(current_scrolling_node); did_lock_scrolling_layer_ = scroll_state->delta_consumed_for_scroll_sequence(); @@ -3292,6 +3295,8 @@ bool did_scroll_y = scroll_state->caused_scroll_y(); bool did_scroll_content = did_scroll_x || did_scroll_y; if (did_scroll_content) { + ShowScrollbarsForImplScroll(current_scrolling_node->element_id); + // If we are scrolling with an active scroll handler, forward latency // tracking information to the main thread so the delay introduced by the // handler is accounted for. @@ -3352,6 +3357,7 @@ if (!changed) return; + ShowScrollbarsForImplScroll(OuterViewportScrollLayer()->element_id()); client_->SetNeedsCommitOnImplThread(); // After applying the synchronous input handler's scroll offset, tell it what // we ended up with. @@ -4153,6 +4159,7 @@ const gfx::ScrollOffset& scroll_offset) { if (list_type == ElementListType::ACTIVE) { SetTreeLayerScrollOffsetMutated(element_id, active_tree(), scroll_offset); + ShowScrollbarsForImplScroll(element_id); } else { SetTreeLayerScrollOffsetMutated(element_id, pending_tree(), scroll_offset); SetTreeLayerScrollOffsetMutated(element_id, recycle_tree(), scroll_offset); @@ -4305,4 +4312,12 @@ has_scrolled_by_touch_ = true; } +void LayerTreeHostImpl::ShowScrollbarsForImplScroll(ElementId element_id) { + if (!element_id) + return; + if (ScrollbarAnimationController* animation_controller = + ScrollbarAnimationControllerForElementId(element_id)) + animation_controller->DidScrollUpdate(); +} + } // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index e7b3f61..b6a6be40 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h
@@ -709,6 +709,7 @@ void UpdateScrollSourceInfo(bool is_wheel_scroll); bool IsScrolledBy(LayerImpl* child, ScrollNode* ancestor); + void ShowScrollbarsForImplScroll(ElementId element_id); using UIResourceMap = std::unordered_map<UIResourceId, UIResourceData>; UIResourceMap ui_resource_map_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 995afae..f4ba45c 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -2919,8 +2919,10 @@ LayerImpl* root = host_impl_->active_tree()->InnerViewportContainerLayer(); scrollbar->SetScrollElementId(scroll->element_id()); root->test_properties()->AddChild(std::move(scrollbar)); + scroll->set_needs_show_scrollbars(true); host_impl_->active_tree()->BuildPropertyTreesForTesting(); host_impl_->active_tree()->DidBecomeActive(); + host_impl_->active_tree()->HandleScrollbarShowRequestsFromMain(); DrawFrame(); // SetScrollElementId will initialize the scrollbar which will cause it to @@ -3056,8 +3058,8 @@ host_impl_->DidFinishImplFrame(); } - // Setting the scroll offset outside a scroll should also cause the - // scrollbar to appear and to schedule a scrollbar animation. + // Setting the scroll offset outside a scroll should not cause the + // scrollbar to appear or schedule a scrollbar animation. if (host_impl_->active_tree() ->property_trees() ->scroll_tree.UpdateScrollOffsetBaseForTesting( @@ -3067,57 +3069,9 @@ host_impl_->InnerViewportScrollLayer()->id()); EXPECT_FALSE(did_request_next_frame_); EXPECT_FALSE(did_request_redraw_); - if (expecting_animations) { - EXPECT_EQ(base::TimeDelta::FromMilliseconds(20), - requested_animation_delay_); - EXPECT_FALSE(animation_task_.Equals(base::Closure())); - requested_animation_delay_ = base::TimeDelta(); - animation_task_ = base::Closure(); - } else { - EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); - EXPECT_TRUE(animation_task_.Equals(base::Closure())); - } - - if (expecting_animations) { - // Scrolling should have stopped the animation, so we should not be - // getting redraws. - begin_frame_args = - CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 5, fake_now); - host_impl_->WillBeginImplFrame(begin_frame_args); - host_impl_->Animate(); - EXPECT_FALSE(did_request_next_frame_); - did_request_next_frame_ = false; - EXPECT_FALSE(did_request_redraw_); - did_request_redraw_ = false; - host_impl_->DidFinishImplFrame(); - } - - // For Andrdoid, scrollbar animation is not triggered unnecessarily. - // For Aura Overlay Scrollbar, scrollbar appears even if scroll offset did - // not change. - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::WHEEL); - host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(5, 0)).get()); - EXPECT_FALSE(did_request_next_frame_); - EXPECT_TRUE(did_request_redraw_); - did_request_redraw_ = false; EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); EXPECT_TRUE(animation_task_.Equals(base::Closure())); - host_impl_->ScrollEnd(EndState().get()); - EXPECT_FALSE(did_request_next_frame_); - EXPECT_FALSE(did_request_redraw_); - if (animator == LayerTreeSettings::AURA_OVERLAY) { - EXPECT_EQ(base::TimeDelta::FromMilliseconds(20), - requested_animation_delay_); - EXPECT_FALSE(animation_task_.Equals(base::Closure())); - requested_animation_delay_ = base::TimeDelta(); - animation_task_ = base::Closure(); - } else { - EXPECT_EQ(base::TimeDelta(), requested_animation_delay_); - EXPECT_TRUE(animation_task_.Equals(base::Closure())); - } - // Changing page scale triggers scrollbar animation. host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f); host_impl_->active_tree()->SetPageScaleOnActiveTree(1.1f); @@ -3267,6 +3221,7 @@ scrollbar->SetScrollElementId(scroll->element_id()); container->test_properties()->AddChild(std::move(scrollbar)); host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); + scroll->set_needs_show_scrollbars(true); host_impl_->pending_tree()->BuildPropertyTreesForTesting(); host_impl_->ActivateSyncTree(); @@ -3407,20 +3362,11 @@ EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForElementId( root_scroll->element_id())); - // Changing one of the viewport layers should result in a scrollbar animation - // update. + // Scrolling the viewport should result in a scrollbar animation update. animation_task_ = base::Closure(); - host_impl_->active_tree() - ->InnerViewportContainerLayer() - ->SetViewportBoundsDelta(gfx::Vector2dF(10, 10)); - EXPECT_FALSE(animation_task_.Equals(base::Closure())); - animation_task_ = base::Closure(); - host_impl_->active_tree()->OuterViewportScrollLayer()->SetCurrentScrollOffset( - gfx::ScrollOffset(10, 10)); - EXPECT_FALSE(animation_task_.Equals(base::Closure())); - animation_task_ = base::Closure(); - host_impl_->active_tree()->InnerViewportScrollLayer()->SetCurrentScrollOffset( - gfx::ScrollOffset(10, 10)); + host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL); + host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(10, 10)).get()); + host_impl_->ScrollEnd(EndState().get()); EXPECT_FALSE(animation_task_.Equals(base::Closure())); animation_task_ = base::Closure(); @@ -3446,9 +3392,8 @@ // update. animation_task_ = base::Closure(); child_clip_ptr->SetBounds(gfx::Size(200, 200)); - EXPECT_FALSE(animation_task_.Equals(base::Closure())); - animation_task_ = base::Closure(); - child_ptr->SetCurrentScrollOffset(gfx::ScrollOffset(10, 10)); + child_ptr->set_needs_show_scrollbars(true); + host_impl_->active_tree()->HandleScrollbarShowRequestsFromMain(); EXPECT_FALSE(animation_task_.Equals(base::Closure())); animation_task_ = base::Closure(); @@ -12242,6 +12187,7 @@ // Capture scrollbar_1, then move mouse to scrollbar_2's layer, should post an // event to fade out scrollbar_1. + scrollbar_1_animation_controller->DidScrollUpdate(); animation_task_ = base::Closure(); host_impl_->MouseDown();
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 0461219ab..4082462 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -242,51 +242,23 @@ clip_size.Scale(1 / current_page_scale_factor()); } - bool scrollbar_needs_animation = false; - bool clip_layer_size_did_change = false; - bool scroll_layer_size_did_change = false; bool y_offset_did_change = false; for (auto* scrollbar : ScrollbarsFor(scroll_layer->element_id())) { if (scrollbar->orientation() == HORIZONTAL) { - scrollbar_needs_animation |= scrollbar->SetCurrentPos(current_offset.x()); - clip_layer_size_did_change |= - scrollbar->SetClipLayerLength(clip_size.width()); - scroll_layer_size_did_change |= - scrollbar->SetScrollLayerLength(scroll_size.width()); + scrollbar->SetCurrentPos(current_offset.x()); + scrollbar->SetClipLayerLength(clip_size.width()); + scrollbar->SetScrollLayerLength(scroll_size.width()); } else { - scrollbar_needs_animation |= y_offset_did_change |= - scrollbar->SetCurrentPos(current_offset.y()); - clip_layer_size_did_change |= - scrollbar->SetClipLayerLength(clip_size.height()); - scroll_layer_size_did_change |= - scrollbar->SetScrollLayerLength(scroll_size.height()); + y_offset_did_change = scrollbar->SetCurrentPos(current_offset.y()); + scrollbar->SetClipLayerLength(clip_size.height()); + scrollbar->SetScrollLayerLength(scroll_size.height()); } - scrollbar_needs_animation |= - scrollbar->SetVerticalAdjust(clip_layer->ViewportBoundsDelta().y()); + scrollbar->SetVerticalAdjust(clip_layer->ViewportBoundsDelta().y()); } - scrollbar_needs_animation |= - (clip_layer_size_did_change || scroll_layer_size_did_change); - if (y_offset_did_change && IsViewportLayerId(scroll_layer_id)) TRACE_COUNTER_ID1("cc", "scroll_offset_y", scroll_layer->id(), current_offset.y()); - - if (scrollbar_needs_animation) { - ScrollbarAnimationController* controller = - layer_tree_host_impl_->ScrollbarAnimationControllerForElementId( - scroll_layer->element_id()); - if (!controller) - return; - - // TODO(chaopeng) clip_layer_size_did_change should call DidResize after - // crbug.com/701810 got fixed. - if (scroll_layer_size_did_change) { - controller->DidResize(); - } else { - controller->DidScrollUpdate(); - } - } } RenderSurfaceImpl* LayerTreeImpl::RootRenderSurface() const { @@ -494,10 +466,10 @@ target_tree->has_ever_been_drawn_ = false; // Note: this needs to happen after SetPropertyTrees. - target_tree->ShowScrollbars(); + target_tree->HandleScrollbarShowRequestsFromMain(); } -void LayerTreeImpl::ShowScrollbars() { +void LayerTreeImpl::HandleScrollbarShowRequestsFromMain() { LayerTreeHostCommon::CallFunctionForEveryLayer(this, [this]( LayerImpl* layer) { if (!layer->needs_show_scrollbars()) @@ -930,6 +902,13 @@ set_needs_update_draw_properties(); DidUpdateScrollState(inner_viewport_scroll_layer_id_); + + if (IsActiveTree() && layer_tree_host_impl_->ViewportMainScrollLayer()) { + if (ScrollbarAnimationController* controller = + layer_tree_host_impl_->ScrollbarAnimationControllerForElementId( + OuterViewportScrollLayer()->element_id())) + controller->DidScrollUpdate(); + } } void LayerTreeImpl::SetDeviceScaleFactor(float device_scale_factor) {
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index 9dbaa2c..4a3f3ab9 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h
@@ -464,6 +464,7 @@ void ClearLayerList(); void BuildLayerListForTesting(); + void HandleScrollbarShowRequestsFromMain(); void InvalidateRegionForImages(const ImageIdFlatSet& images_to_invalidate); @@ -476,7 +477,6 @@ float max_page_scale_factor); bool IsViewportLayerId(int id) const; void UpdateScrollbars(int scroll_layer_id, int clip_layer_id); - void ShowScrollbars(); void DidUpdatePageScale(); void PushBrowserControls(const float* top_controls_shown_ratio); bool ClampBrowserControlsShownRatio();
diff --git a/chrome/VERSION b/chrome/VERSION index 92ea6e4..7570bad 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=60 MINOR=0 -BUILD=3083 +BUILD=3084 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 7f384aa..f3b72f5 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -372,6 +372,7 @@ "//third_party/android_tools:android_support_v7_mediarouter_java", "//third_party/android_tools:android_support_v7_recyclerview_java", "//third_party/cacheinvalidation:cacheinvalidation_javalib", + "//third_party/custom_tabs_client:custom_tabs_support_java", "//third_party/hamcrest:hamcrest_java", "//ui/android:ui_java", "//url/mojo:url_mojom_gurl_java",
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml index 96a72c3..5f50da2f 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml
@@ -605,6 +605,21 @@ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" > </activity> + <!-- Activities for Browser Actions --> + {% if channel in ['default'] %} + <activity android:name="org.chromium.chrome.browser.browseractions.BrowserActionActivity" + android:theme="@style/FullscreenTransparentActivityTheme" + android:exported="true" + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"> + <intent-filter> + <action android:name="android.support.customtabs.browseractions.browser_action_open" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:scheme="http" /> + <data android:scheme="https" /> + </intent-filter> + </activity> + {% endif %} + <!-- Service for Broadcasting a Physical Web URL --> <service android:name="org.chromium.chrome.browser.physicalweb.PhysicalWebBroadcastService"
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS index 9ffefe4..ec8e03e 100644 --- a/chrome/android/java/DEPS +++ b/chrome/android/java/DEPS
@@ -17,6 +17,7 @@ "+components/web_contents_delegate_android", "+components/web_restrictions", "+content/public/android/java", + "+device/geolocation/android/java", "+services/service_manager/public/java", ]
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml index e21804f00..02c215b 100644 --- a/chrome/android/java/res/values-v17/styles.xml +++ b/chrome/android/java/res/values-v17/styles.xml
@@ -59,6 +59,15 @@ <item name="windowNoTitle">true</item> </style> + <style name="FullscreenTransparentActivityTheme" parent="Theme.AppCompat.Light.NoActionBar" > + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowContentOverlay">@null</item> + <item name="android:windowIsFloating">true</item> + <item name="android:colorBackgroundCacheHint">@null</item> + <item name="android:windowIsTranslucent">true</item> + <item name="windowNoTitle">true</item> + </style> + <style name="FullscreenWhiteActivityTheme" parent="FullscreenWhite"> <item name="windowActionBar">false</item> </style>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java new file mode 100644 index 0000000..2ba8475 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java
@@ -0,0 +1,128 @@ +// 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. + +package org.chromium.chrome.browser.browseractions; + +import android.app.PendingIntent; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.support.customtabs.browseractions.BrowserActionItem; +import android.support.customtabs.browseractions.BrowserActionsIntent; + +import org.chromium.base.Log; +import org.chromium.base.annotations.SuppressFBWarnings; +import org.chromium.chrome.browser.IntentHandler; +import org.chromium.chrome.browser.UrlConstants; +import org.chromium.chrome.browser.init.AsyncInitializationActivity; +import org.chromium.chrome.browser.util.IntentUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * A transparent {@link AsyncInitializationActivity} that displays the browser action context menu. + */ +public class BrowserActionActivity extends AsyncInitializationActivity { + private static final String TAG = "BrowserActions"; + + private int mType; + private Uri mUri; + private String mCreatorPackageName; + private List<BrowserActionItem> mActions = new ArrayList<>(); + + @Override + protected void setContentView() { + openContextMenu(); + } + + @Override + @SuppressFBWarnings("URF_UNREAD_FIELD") + protected boolean isStartedUpCorrectly(Intent intent) { + if (intent == null + || !BrowserActionsIntent.ACTION_BROWSER_ACTIONS_OPEN.equals(intent.getAction())) { + return false; + } + mUri = Uri.parse(IntentHandler.getUrlFromIntent(intent)); + mType = IntentUtils.safeGetIntExtra( + intent, BrowserActionsIntent.EXTRA_TYPE, BrowserActionsIntent.URL_TYPE_NONE); + mCreatorPackageName = BrowserActionsIntent.getCreatorPackageName(intent); + ArrayList<Bundle> bundles = IntentUtils.getParcelableArrayListExtra( + intent, BrowserActionsIntent.EXTRA_MENU_ITEMS); + if (bundles != null) { + parseBrowserActionItems(bundles); + } + if (mUri == null) { + Log.e(TAG, "Missing url"); + return false; + } else if (!UrlConstants.HTTP_SCHEME.equals(mUri.getScheme()) + && !UrlConstants.HTTPS_SCHEME.equals(mUri.getScheme())) { + Log.e(TAG, "Url should only be HTTP or HTTPS scheme"); + return false; + } else if (mCreatorPackageName == null) { + Log.e(TAG, "Missing creator's pacakge name"); + return false; + } else if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + Log.e(TAG, "Intent should not be started with FLAG_ACTIVITY_NEW_TASK"); + return false; + } else if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0) { + Log.e(TAG, "Intent should not be started with FLAG_ACTIVITY_NEW_DOCUMENT"); + return false; + } else { + return true; + } + } + + /** + * Opens a Browser Actions context menu based on the parsed data. + */ + public void openContextMenu() { + return; + } + + @Override + protected boolean shouldDelayBrowserStartup() { + return true; + } + + @Override + public boolean shouldStartGpuProcess() { + return true; + } + + /** + * Gets custom item list for browser action menu. + * @param bundles Data for custom items from {@link BrowserActionsIntent}. + */ + private void parseBrowserActionItems(ArrayList<Bundle> bundles) { + for (int i = 0; i < bundles.size(); i++) { + Bundle bundle = bundles.get(i); + String title = IntentUtils.safeGetString(bundle, BrowserActionsIntent.KEY_TITLE); + PendingIntent action = + IntentUtils.safeGetParcelable(bundle, BrowserActionsIntent.KEY_ACTION); + Bitmap icon = IntentUtils.safeGetParcelable(bundle, BrowserActionsIntent.KEY_ICON); + if (title != null && action != null) { + BrowserActionItem item = new BrowserActionItem(title, action); + if (icon != null) { + item.setIcon(icon); + } + mActions.add(item); + } else if (title != null) { + Log.e(TAG, "Missing action for item: " + i); + } else if (action != null) { + Log.e(TAG, "Missing title for item: " + i); + } else { + Log.e(TAG, "Missing title and action for item: " + i); + } + } + } + + /** + * Callback when Browser Actions menu dialog is shown. + */ + private void onMenuShown() { + beginLoadingLibrary(); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java index 0cf871e3..673908f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -40,6 +40,7 @@ import org.chromium.chrome.browser.sync.SyncController; import org.chromium.components.signin.AccountManagerHelper; import org.chromium.content.common.ContentSwitches; +import org.chromium.device.geolocation.LocationProviderFactory; import org.chromium.printing.PrintDocumentAdapterWrapper; import org.chromium.printing.PrintingControllerImpl; import org.chromium.ui.PhotoPickerListener; @@ -131,6 +132,9 @@ UniqueIdentificationGeneratorFactory.registerGenerator(SyncController.GENERATOR_ID, new UuidBasedUniqueIdentificationGenerator( application, SESSIONS_UUID_PREF_KEY), false); + + // Indicate that we can use the GMS location provider. + LocationProviderFactory.useGmsCoreLocationProvider(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java index d432ee3f..bda7caa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
@@ -232,6 +232,12 @@ private void configureSettingsButton(RemoteViews bigView) { if (mSettingsAction == null) { + bigView.setViewVisibility(R.id.origin_settings_icon, View.GONE); + int rightPadding = + dpToPx(BUTTON_ICON_PADDING_DP, mContext.getResources().getDisplayMetrics()); + int leftPadding = + Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? rightPadding : 0; + bigView.setViewPadding(R.id.origin, leftPadding, 0, rightPadding, 0); return; } bigView.setOnClickPendingIntent(R.id.origin, mSettingsAction.intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java index 6035b0cb..2eb51fec 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
@@ -504,16 +504,6 @@ NotificationSystemStatusUtil.determineAppNotificationStatus(context), NotificationSystemStatusUtil.APP_NOTIFICATIONS_STATUS_BOUNDARY); - // Set up a pending intent for going to the settings screen for |origin|. - Intent settingsIntent = PreferencesLauncher.createIntentForSettingsPage( - context, SingleWebsitePreferences.class.getName()); - settingsIntent.setData(makeIntentData(notificationId, origin, -1 /* actionIndex */)); - settingsIntent.putExtra(Preferences.EXTRA_SHOW_FRAGMENT_ARGUMENTS, - SingleWebsitePreferences.createFragmentArgsForSite(origin)); - - PendingIntent pendingSettingsIntent = PendingIntent.getActivity(context, - PENDING_INTENT_REQUEST_CODE, settingsIntent, PendingIntent.FLAG_UPDATE_CURRENT); - PendingIntent clickIntent = makePendingIntent(context, NotificationConstants.ACTION_CLICK_NOTIFICATION, notificationId, origin, profileId, incognito, tag, webApkPackage, -1 /* actionIndex */); @@ -555,19 +545,6 @@ } } - // If action buttons are displayed, there isn't room for the full Site Settings button - // label and icon, so abbreviate it. This has the unfortunate side-effect of unnecessarily - // abbreviating it on Android Wear also (crbug.com/576656). If custom layouts are enabled, - // the label and icon provided here only affect Android Wear, so don't abbreviate them. - boolean abbreviateSiteSettings = actions.length > 0 && !useCustomLayouts(hasImage); - int settingsIconId = abbreviateSiteSettings ? 0 : R.drawable.settings_cog; - CharSequence settingsTitle = abbreviateSiteSettings - ? res.getString(R.string.notification_site_settings_button) - : res.getString(R.string.page_info_site_settings_button); - // If the settings button is displayed together with the other buttons it has to be the last - // one, so add it after the other actions. - notificationBuilder.addSettingsAction(settingsIconId, settingsTitle, pendingSettingsIntent); - // The Android framework applies a fallback vibration pattern for the sound when the device // is in vibrate mode, there is no custom pattern, and the vibration default has been // disabled. To truly prevent vibration, provide a custom empty pattern. @@ -581,6 +558,31 @@ String platformTag = makePlatformTag(notificationId, origin, tag); if (webApkPackage.isEmpty()) { + // Set up a pending intent for going to the settings screen for |origin|. + Intent settingsIntent = PreferencesLauncher.createIntentForSettingsPage( + context, SingleWebsitePreferences.class.getName()); + settingsIntent.setData(makeIntentData(notificationId, origin, -1 /* actionIndex */)); + settingsIntent.putExtra(Preferences.EXTRA_SHOW_FRAGMENT_ARGUMENTS, + SingleWebsitePreferences.createFragmentArgsForSite(origin)); + + PendingIntent pendingSettingsIntent = PendingIntent.getActivity(context, + PENDING_INTENT_REQUEST_CODE, settingsIntent, PendingIntent.FLAG_UPDATE_CURRENT); + + // If action buttons are displayed, there isn't room for the full Site Settings button + // label and icon, so abbreviate it. This has the unfortunate side-effect of + // unnecessarily abbreviating it on Android Wear also (crbug.com/576656). If custom + // layouts are enabled, the label and icon provided here only affect Android Wear, so + // don't abbreviate them. + boolean abbreviateSiteSettings = actions.length > 0 && !useCustomLayouts(hasImage); + int settingsIconId = abbreviateSiteSettings ? 0 : R.drawable.settings_cog; + CharSequence settingsTitle = abbreviateSiteSettings + ? res.getString(R.string.notification_site_settings_button) + : res.getString(R.string.page_info_site_settings_button); + // If the settings button is displayed together with the other buttons it has to be the + // last one, so add it after the other actions. + notificationBuilder.addSettingsAction( + settingsIconId, settingsTitle, pendingSettingsIntent); + mNotificationManager.notify(platformTag, PLATFORM_ID, notificationBuilder.build()); NotificationUmaTracker.getInstance().onNotificationShown( NotificationUmaTracker.SITES, ChannelDefinitions.CHANNEL_ID_SITES);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java index 6254f67a..1f42cf90 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java
@@ -38,7 +38,6 @@ @Nullable final LayoutManagerChrome mLayoutManager; final BottomSheet mBottomSheet; - final View mFadingBackgroundView; final String mTitle; private boolean mShowOverviewOnClose; @@ -59,7 +58,6 @@ mTab = tab; mTabModelSelector = tabModelSelector; mLayoutManager = layoutManager; - mFadingBackgroundView = mTab.getActivity().getFadingBackgroundView(); mBottomSheet = mTab.getActivity().getBottomSheet(); mTitle = context.getResources().getString(R.string.button_new_tab); @@ -89,7 +87,7 @@ @Override public void onHidden(Tab tab) { - mFadingBackgroundView.setEnabled(true); + mTab.getActivity().getFadingBackgroundView().setEnabled(true); if (!mTab.isClosing()) mShowOverviewOnClose = false; } @@ -142,7 +140,7 @@ public void destroy() { // The next tab will be selected before this one is destroyed. If the currently selected // tab is a Chrome Home new tab page, the FadingBackgroundView should not be enabled. - mFadingBackgroundView.setEnabled( + mTab.getActivity().getFadingBackgroundView().setEnabled( !isTabChromeHomeNewTabPage(mTabModelSelector.getCurrentTab())); if (mLayoutManager != null) { @@ -152,7 +150,9 @@ } private void onNewTabPageShown() { - mFadingBackgroundView.setEnabled(false); + if (mTab.getActivity().getFadingBackgroundView() != null) { + mTab.getActivity().getFadingBackgroundView().setEnabled(false); + } // This method may be called when an NTP is selected due to the user switching tab models. // In this case, we do not want the bottom sheet to open. Unfortunately, without observing
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java index 1b1bf9a9..78c296f6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java
@@ -56,6 +56,7 @@ /** The maximum number of milliseconds to wait for a connection to READY_TO_PAY service. */ private static final long SERVICE_CONNECTION_TIMEOUT_MS = 1000; + private static final String EXTRA_ID = "id"; private static final String EXTRA_MERCHANT_NAME = "merchantName"; private static final String EXTRA_METHOD_NAME = "methodName"; private static final String EXTRA_METHOD_NAMES = "methodNames"; @@ -146,8 +147,8 @@ public void onServiceDisconnected(ComponentName name) {} }; - mIsReadyToPayIntent.putExtras(buildExtras( - null, origin, iframeOrigin, certificateChain, methodDataMap, null, null, null)); + mIsReadyToPayIntent.putExtras(buildExtras(null, null, origin, iframeOrigin, + certificateChain, methodDataMap, null, null, null)); try { if (!ContextUtils.getApplicationContext().bindService( mIsReadyToPayIntent, mServiceConnection, Context.BIND_AUTO_CREATE)) { @@ -243,7 +244,7 @@ } @Override - public void invokePaymentApp(final String merchantName, final String origin, + public void invokePaymentApp(final String id, final String merchantName, final String origin, final String iframeOrigin, final byte[][] certificateChain, final Map<String, PaymentMethodData> methodDataMap, final PaymentItem total, final List<PaymentItem> displayItems, @@ -252,8 +253,8 @@ mInstrumentDetailsCallback = callback; if (!mIsIncognito) { - launchPaymentApp(merchantName, origin, iframeOrigin, certificateChain, methodDataMap, - total, displayItems, modifiers); + launchPaymentApp(id, merchantName, origin, iframeOrigin, certificateChain, + methodDataMap, total, displayItems, modifiers); return; } @@ -270,7 +271,7 @@ new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - launchPaymentApp(merchantName, origin, iframeOrigin, + launchPaymentApp(id, merchantName, origin, iframeOrigin, certificateChain, methodDataMap, total, displayItems, modifiers); } @@ -291,10 +292,10 @@ .show(); } - private void launchPaymentApp(String merchantName, String origin, String iframeOrigin, - byte[][] certificateChain, Map<String, PaymentMethodData> methodDataMap, - PaymentItem total, List<PaymentItem> displayItems, - Map<String, PaymentDetailsModifier> modifiers) { + private void launchPaymentApp(String id, String merchantName, String origin, + String iframeOrigin, byte[][] certificateChain, + Map<String, PaymentMethodData> methodDataMap, PaymentItem total, + List<PaymentItem> displayItems, Map<String, PaymentDetailsModifier> modifiers) { assert mMethodNames.containsAll(methodDataMap.keySet()); assert mInstrumentDetailsCallback != null; @@ -309,20 +310,21 @@ return; } - mPayIntent.putExtras(buildExtras(merchantName, origin, iframeOrigin, certificateChain, + mPayIntent.putExtras(buildExtras(id, merchantName, origin, iframeOrigin, certificateChain, methodDataMap, total, displayItems, modifiers)); if (!window.showIntent(mPayIntent, this, R.string.payments_android_app_error)) { notifyErrorInvokingPaymentApp(); } } - private static Bundle buildExtras(@Nullable String merchantName, String origin, - String iframeOrigin, @Nullable byte[][] certificateChain, + private static Bundle buildExtras(@Nullable String id, @Nullable String merchantName, + String origin, String iframeOrigin, @Nullable byte[][] certificateChain, Map<String, PaymentMethodData> methodDataMap, @Nullable PaymentItem total, @Nullable List<PaymentItem> displayItems, @Nullable Map<String, PaymentDetailsModifier> modifiers) { Bundle extras = new Bundle(); + if (id != null) extras.putString(EXTRA_ID, id); if (merchantName != null) extras.putString(EXTRA_MERCHANT_NAME, merchantName); extras.putString(EXTRA_ORIGIN, origin); extras.putString(EXTRA_IFRAME_ORIGIN, iframeOrigin);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java index 8557299c..f4510ea 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
@@ -81,8 +81,8 @@ } @Override - public void invokePaymentApp(String unusedMerchantName, String unusedOrigin, - String unusedIFrameOrigin, byte[][] unusedCertificateChain, + public void invokePaymentApp(String unusedRequestId, String unusedMerchantName, + String unusedOrigin, String unusedIFrameOrigin, byte[][] unusedCertificateChain, Map<String, PaymentMethodData> unusedMethodDataMap, PaymentItem unusedTotal, List<PaymentItem> unusedDisplayItems, Map<String, PaymentDetailsModifier> unusedModifiers,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentInstrument.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentInstrument.java index 952a98e3..2bb0092 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentInstrument.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentInstrument.java
@@ -73,6 +73,7 @@ * * The callback will be invoked with the resulting payment details or error. * + * @param id The unique identifier of the PaymentRequest. * @param merchantName The name of the merchant. * @param origin The origin of this merchant. * @param iframeOrigin The origin of the iframe that invoked PaymentRequest. @@ -86,10 +87,11 @@ * @param modifiers The relevant payment details modifiers. * @param callback The object that will receive the instrument details. */ - public abstract void invokePaymentApp(String merchantName, String origin, String iframeOrigin, - @Nullable byte[][] certificateChain, Map<String, PaymentMethodData> methodDataMap, - PaymentItem total, List<PaymentItem> displayItems, - Map<String, PaymentDetailsModifier> modifiers, InstrumentDetailsCallback callback); + public abstract void invokePaymentApp(String id, String merchantName, String origin, + String iframeOrigin, @Nullable byte[][] certificateChain, + Map<String, PaymentMethodData> methodDataMap, PaymentItem total, + List<PaymentItem> displayItems, Map<String, PaymentDetailsModifier> modifiers, + InstrumentDetailsCallback callback); /** * Cleans up any resources held by the payment instrument. For example, closes server
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index 954e4c9..8cb5b57 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -300,6 +300,7 @@ */ private SectionInformation mUiShippingOptions; + private String mId; private Map<String, PaymentMethodData> mMethodData; private boolean mRequestShipping; private boolean mRequestPayerName; @@ -457,6 +458,7 @@ disconnectFromClientWithDebugMessage("Missing total"); return; } + mId = details.id; PaymentAppFactory.getInstance().create(mWebContents, Collections.unmodifiableSet(mMethodData.keySet()), this /* callback */); @@ -1225,7 +1227,7 @@ } } - instrument.invokePaymentApp(mMerchantName, mSchemelessOriginForPaymentApp, + instrument.invokePaymentApp(mId, mMerchantName, mSchemelessOriginForPaymentApp, mSchemelessIFrameOriginForPaymentApp, mCertificateChain, Collections.unmodifiableMap(methodData), mRawTotal, mRawLineItems, Collections.unmodifiableMap(modifiers), this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentInstrument.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentInstrument.java index 0d698bd4..bdd2c2f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentInstrument.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentInstrument.java
@@ -56,7 +56,7 @@ } @Override - public void invokePaymentApp(String merchantName, String origin, String iframeOrigin, + public void invokePaymentApp(String id, String merchantName, String origin, String iframeOrigin, byte[][] unusedCertificateChain, Map<String, PaymentMethodData> methodData, PaymentItem total, List<PaymentItem> displayItems, Map<String, PaymentDetailsModifier> modifiers, InstrumentDetailsCallback callback) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java index 9d6131f..6875659 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -89,7 +89,7 @@ activity.getBottomSheet().addObserver(new EmptyBottomSheetObserver() { @Override public void onSheetOpened() { - mRecyclerView.scrollTo(0, 0); + mRecyclerView.scrollToPosition(0); // TODO(https://crbug.com/689962) Ensure this call does not discard all suggestions // every time the sheet is opened.
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 12248dc0..05ed6d9 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
@@ -350,6 +350,8 @@ private VrShellDelegate(ChromeActivity activity, VrClassesWrapper wrapper) { mActivity = activity; mVrClassesWrapper = wrapper; + // If an activity isn't resumed at the point, it must have been paused. + mPaused = ApplicationStatus.getStateForActivity(activity) != ActivityState.RESUMED; updateVrSupportLevel(); mNativeVrShellDelegate = nativeInit(); Choreographer choreographer = Choreographer.getInstance(); @@ -375,6 +377,8 @@ break; case ActivityState.PAUSED: if (activity == mActivity) pauseVr(); + // Other activities should only pause while we're paused due to Android lifecycle. + assert mPaused; break; case ActivityState.RESUMED: assert !mInVr;
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index ba6966a..fcd4ce20 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -120,6 +120,7 @@ "java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetProvider.java", "java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetProxy.java", "java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java", + "java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java", "java/src/org/chromium/chrome/browser/browsing_data/UrlFilters.java", "java/src/org/chromium/chrome/browser/childaccounts/ChildAccountFeedbackReporter.java", "java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java", @@ -1489,6 +1490,7 @@ "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFieldTrialTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java", + "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsAndFreeShippingTest.java", "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteEmailTest.java", @@ -1635,6 +1637,7 @@ "junit/src/org/chromium/chrome/browser/DisableHistogramsRule.java", "junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java", "junit/src/org/chromium/chrome/browser/SSLClientCertificateRequestTest.java", + "junit/src/org/chromium/chrome/browser/browseractions/BrowserActionActivityTest.java", "junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java", "junit/src/org/chromium/chrome/browser/compositor/CompositorSurfaceManagerTest.java", "junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInternalStateTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java new file mode 100644 index 0000000..fe63e2f --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java
@@ -0,0 +1,54 @@ +// 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. + +package org.chromium.chrome.browser.payments; + +import android.content.DialogInterface; +import android.support.test.filters.MediumTest; + +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.autofill.AutofillTestHelper; +import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; +import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +/** + * A payment integration test for verifying the PaymentResponse contains the + * free-form identifier specified in PaymentDetailsInit. + */ +public class PaymentRequestIdTest extends PaymentRequestTestBase { + public PaymentRequestIdTest() { + super("payment_request_id_test.html"); + } + + @Override + public void onMainActivityStarted() + throws InterruptedException, ExecutionException, TimeoutException { + AutofillTestHelper helper = new AutofillTestHelper(); + String billingAddressId = helper.setProfile(new AutofillProfile("", "https://example.com", + true, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", + "US", "555-555-5555", "", "en-US")); + helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe", + "4111111111111111", "1111", "12", "2050", "visa", R.drawable.pr_visa, + billingAddressId, "" /* serverId */)); + } + + /** + * Submit the payment information without shipping address or shipping options to the merchant + * when the user clicks "Pay." + */ + @MediumTest + @Feature({"Payments"}) + public void testPaymentResponse() + throws InterruptedException, ExecutionException, TimeoutException { + triggerUIAndWait(mReadyToPay); + clickAndWait(R.id.button_primary, mReadyForUnmaskInput); + setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", mReadyToUnmask); + clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, mDismissed); + expectResultContains(new String[] {"my_payment_id"}); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java index c0100504..02bae87 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
@@ -1013,10 +1013,10 @@ } @Override - public void invokePaymentApp(String merchantName, String origin, String iframeOrigin, - byte[][] certificateChain, Map<String, PaymentMethodData> methodData, - PaymentItem total, List<PaymentItem> displayItems, - Map<String, PaymentDetailsModifier> modifiers, + public void invokePaymentApp(String id, String merchantName, String origin, + String iframeOrigin, byte[][] certificateChain, + Map<String, PaymentMethodData> methodData, PaymentItem total, + List<PaymentItem> displayItems, Map<String, PaymentDetailsModifier> modifiers, InstrumentDetailsCallback detailsCallback) { detailsCallback.onInstrumentDetailsReady( mMethodName, "{\"transaction\": 1337}");
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/browseractions/BrowserActionActivityTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/browseractions/BrowserActionActivityTest.java new file mode 100644 index 0000000..6d71290 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/browseractions/BrowserActionActivityTest.java
@@ -0,0 +1,103 @@ +// 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. + +package org.chromium.chrome.browser.browseractions; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doAnswer; + +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.support.customtabs.browseractions.BrowserActionsIntent; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.util.Feature; +import org.chromium.testing.local.LocalRobolectricTestRunner; + +/** + * Unit tests for BrowserActionActivity. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class BrowserActionActivityTest { + private static final String HTTP_SCHEME_TEST_URL = "http://www.example.com"; + private static final String HTTPS_SCHEME_TEST_URL = "https://www.example.com"; + private static final String CHROME_SCHEME_TEST_URL = "chrome://example"; + private static final String CONTENT_SCHEME_TEST_URL = "content://example"; + + private BrowserActionActivity mActivity = new BrowserActionActivity(); + private Context mContext; + + @Mock + private PendingIntent mPendingIntent; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + Answer<String> answer = new Answer<String>() { + @Override + public String answer(InvocationOnMock invocation) { + return "some.other.app.package.name"; + } + }; + doAnswer(answer).when(mPendingIntent).getCreatorPackage(); + } + + @Test + @Feature({"BrowserActions"}) + public void testStartedUpCorrectly() { + assertFalse(mActivity.isStartedUpCorrectly(null)); + assertFalse(mActivity.isStartedUpCorrectly(new Intent())); + + Intent mIntent = createBaseBrowserActionsIntent(HTTP_SCHEME_TEST_URL); + assertTrue(mActivity.isStartedUpCorrectly(mIntent)); + + mIntent = createBaseBrowserActionsIntent(HTTP_SCHEME_TEST_URL); + mIntent.removeExtra(BrowserActionsIntent.EXTRA_APP_ID); + assertFalse(mActivity.isStartedUpCorrectly(mIntent)); + + mIntent = createBaseBrowserActionsIntent(HTTPS_SCHEME_TEST_URL); + assertTrue(mActivity.isStartedUpCorrectly(mIntent)); + + mIntent = createBaseBrowserActionsIntent(CHROME_SCHEME_TEST_URL); + assertFalse(mActivity.isStartedUpCorrectly(mIntent)); + + mIntent = createBaseBrowserActionsIntent(CONTENT_SCHEME_TEST_URL); + assertFalse(mActivity.isStartedUpCorrectly(mIntent)); + + mIntent = createBaseBrowserActionsIntent(HTTP_SCHEME_TEST_URL); + mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + assertFalse(mActivity.isStartedUpCorrectly(mIntent)); + + mIntent = createBaseBrowserActionsIntent(HTTP_SCHEME_TEST_URL); + mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + assertFalse(mActivity.isStartedUpCorrectly(mIntent)); + } + + /** + * Creates a simple Intent for Browser Actions which contains a url, the {@link + * BrowserActionsIntent.ACTION_BROWSER_ACTIONS_OPEN} action and source package name. + * @param url The url for the data of the Intent. + * @return The simple Intent for Browser Actions. + */ + private Intent createBaseBrowserActionsIntent(String url) { + return new BrowserActionsIntent.Builder(mContext, Uri.parse(url)) + .build() + .getIntent() + .putExtra(BrowserActionsIntent.EXTRA_APP_ID, mPendingIntent); + } +}
diff --git a/chrome/android/webapk/shell_apk/AndroidManifest.xml b/chrome/android/webapk/shell_apk/AndroidManifest.xml index 5854c1e..a9dc831a 100644 --- a/chrome/android/webapk/shell_apk/AndroidManifest.xml +++ b/chrome/android/webapk/shell_apk/AndroidManifest.xml
@@ -31,12 +31,6 @@ <data android:scheme="{{{scope_url_scheme}}}" android:host="{{{scope_url_host}}}" android:pathPrefix="{{{scope_url_path}}}"></data> </intent-filter> </activity> - <activity android:name="org.chromium.webapk.shell_apk.NotificationSettingsLauncherActivity"> - <intent-filter> - <action android:name="android.intent.action.MAIN"/> - <category android:name="android.intent.category.NOTIFICATION_PREFERENCES"/> - </intent-filter> - </activity> <meta-data android:name="org.chromium.webapk.shell_apk.shellApkVersion" android:value="{{{shell_apk_version}}}" /> <meta-data android:name="org.chromium.webapk.shell_apk.runtimeHost" android:value="{{{runtime_host}}}" /> <meta-data android:name="org.chromium.webapk.shell_apk.startUrl" android:value="{{{start_url}}}" />
diff --git a/chrome/android/webapk/shell_apk/BUILD.gn b/chrome/android/webapk/shell_apk/BUILD.gn index 5958254b..2a9adc89 100644 --- a/chrome/android/webapk/shell_apk/BUILD.gn +++ b/chrome/android/webapk/shell_apk/BUILD.gn
@@ -112,7 +112,6 @@ "src/org/chromium/webapk/shell_apk/DexLoader.java", "src/org/chromium/webapk/shell_apk/HostBrowserClassLoader.java", "src/org/chromium/webapk/shell_apk/MainActivity.java", - "src/org/chromium/webapk/shell_apk/NotificationSettingsLauncherActivity.java", "src/org/chromium/webapk/shell_apk/WebApkSandboxedProcessService.java", "src/org/chromium/webapk/shell_apk/WebApkSandboxedProcessService0.java", "src/org/chromium/webapk/shell_apk/WebApkSandboxedProcessService1.java",
diff --git a/chrome/android/webapk/shell_apk/shell_apk_version.gni b/chrome/android/webapk/shell_apk/shell_apk_version.gni index 718adb4..c4d66ff 100644 --- a/chrome/android/webapk/shell_apk/shell_apk_version.gni +++ b/chrome/android/webapk/shell_apk/shell_apk_version.gni
@@ -6,7 +6,7 @@ # (including AndroidManifest.xml) is updated. This version should be incremented # prior to uploading a new ShellAPK to the WebAPK Minting Server. # Does not affect Chrome.apk -template_shell_apk_version = 3 +template_shell_apk_version = 4 # The ShellAPK version expected by Chrome. Chrome will try to update the WebAPK # if the WebAPK's ShellAPK version is less than |expected_shell_apk_version|.
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/NotificationSettingsLauncherActivity.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/NotificationSettingsLauncherActivity.java deleted file mode 100644 index fd405f2..0000000 --- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/NotificationSettingsLauncherActivity.java +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2016 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. - -package org.chromium.webapk.shell_apk; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; - -/** - * Forwards NOTIFICATION_PREFERENCES intent to host browser. - */ -public class NotificationSettingsLauncherActivity extends Activity { - - @Override - public void onCreate(Bundle savedInstance) { - super.onCreate(savedInstance); - - String hostPackage = WebApkUtils.getHostBrowserPackageName(this); - Intent intent = getIntent(); - intent.setPackage(hostPackage); - intent.setComponent(null); - startActivity(intent); - finish(); - } -}
diff --git a/chrome/browser/android/offline_pages/offline_page_request_job.cc b/chrome/browser/android/offline_pages/offline_page_request_job.cc index 40edfd4f..570e255 100644 --- a/chrome/browser/android/offline_pages/offline_page_request_job.cc +++ b/chrome/browser/android/offline_pages/offline_page_request_job.cc
@@ -639,13 +639,6 @@ return false; } -int OfflinePageRequestJob::GetResponseCode() const { - if (!fake_headers_for_redirect_) - return URLRequestFileJob::GetResponseCode(); - - return net::URLRequestRedirectJob::REDIRECT_302_FOUND; -} - void OfflinePageRequestJob::OnOpenComplete(int result) { UMA_HISTOGRAM_SPARSE_SLOWLY("OfflinePages.RequestJob.OpenFileErrorCode", -result);
diff --git a/chrome/browser/android/offline_pages/offline_page_request_job.h b/chrome/browser/android/offline_pages/offline_page_request_job.h index 15aa31c4..500af977 100644 --- a/chrome/browser/android/offline_pages/offline_page_request_job.h +++ b/chrome/browser/android/offline_pages/offline_page_request_job.h
@@ -91,7 +91,6 @@ void GetResponseInfo(net::HttpResponseInfo* info) override; void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override; bool CopyFragmentOnRedirect(const GURL& location) const override; - int GetResponseCode() const override; // net::URLRequestFileJob overrides: void OnOpenComplete(int result) override;
diff --git a/chrome/browser/android/vr_shell/ui_elements/ui_element.h b/chrome/browser/android/vr_shell/ui_elements/ui_element.h index 5d1d6eea..e46ebf2 100644 --- a/chrome/browser/android/vr_shell/ui_elements/ui_element.h +++ b/chrome/browser/android/vr_shell/ui_elements/ui_element.h
@@ -113,9 +113,6 @@ // Valid IDs are non-negative. int id = -1; - // Name string for debugging and testing purposes. - std::string name; - // If a non-negative parent ID is specified, applicable transformations // are applied relative to the parent, rather than absolutely. int parent_id = -1;
diff --git a/chrome/browser/android/vr_shell/ui_scene.cc b/chrome/browser/android/vr_shell/ui_scene.cc index 6744fe6..82984bb 100644 --- a/chrome/browser/android/vr_shell/ui_scene.cc +++ b/chrome/browser/android/vr_shell/ui_scene.cc
@@ -146,10 +146,18 @@ return !GetHeadLockedElements().empty(); } +void UiScene::SetBackgroundColor(const vr::Colorf& color) { + background_color_ = color; +} + const vr::Colorf& UiScene::GetBackgroundColor() const { return background_color_; } +void UiScene::SetBackgroundDistance(float distance) { + background_distance_ = distance; +} + float UiScene::GetBackgroundDistance() const { return background_distance_; }
diff --git a/chrome/browser/android/vr_shell/ui_scene.h b/chrome/browser/android/vr_shell/ui_scene.h index a70a3c0..56077e05 100644 --- a/chrome/browser/android/vr_shell/ui_scene.h +++ b/chrome/browser/android/vr_shell/ui_scene.h
@@ -62,8 +62,11 @@ std::vector<const UiElement*> GetHeadLockedElements() const; bool HasVisibleHeadLockedElements() const; + void SetBackgroundColor(const vr::Colorf& color); const vr::Colorf& GetBackgroundColor() const; + void SetBackgroundDistance(float distance); float GetBackgroundDistance() const; + bool GetWebVrRenderingEnabled() const; void OnGLInitialized();
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.cc b/chrome/browser/android/vr_shell/ui_scene_manager.cc index 29434a3..4cbeae4 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager.cc +++ b/chrome/browser/android/vr_shell/ui_scene_manager.cc
@@ -19,16 +19,26 @@ static constexpr int kWarningTimeoutSeconds = 30; static constexpr float kWarningDistance = 0.7; static constexpr float kWarningAngleRadians = 16.3 * M_PI / 180.0; - static constexpr float kPermanentWarningHeight = 0.226; static constexpr float kPermanentWarningWidth = 0.078; static constexpr float kTransientWarningHeight = 0.512; static constexpr float kTransientWarningWidth = 0.160; -static constexpr float kContentHeight = 2.4; -static constexpr float kContentWidth = 1.6; +static constexpr float kContentWidth = 2.4; +static constexpr float kContentHeight = 1.6; static constexpr float kContentDistance = 2.5; static constexpr float kContentVerticalOffset = -0.26; +static constexpr float kBackplaneSize = 1000.0; +static constexpr float kBackgroundDistanceMultiplier = 1.414; + +static constexpr float kSceneSize = 25.0; +static constexpr float kSceneHeight = 4.0; +static constexpr int kFloorGridlineCount = 40; +static constexpr vr::Colorf kBackgroundHorizonColor = {0.57, 0.57, 0.57, 1.0}; +static constexpr vr::Colorf kBackgroundCenterColor = {0.48, 0.48, 0.48, 1.0}; + +// Tiny distance to offset textures that should appear in the same plane. +static constexpr float kTextureOffset = 0.01; } // namespace @@ -36,15 +46,20 @@ : scene_(scene), weak_ptr_factory_(this) { std::unique_ptr<UiElement> element; - // For now, use an ID range that does not conflict with the HTML UI. - int id = 1000; + CreateBackground(); + CreateContentQuad(); + CreateSecurityWarnings(); +} - // Permanent WebVR security warning. +UiSceneManager::~UiSceneManager() {} + +void UiSceneManager::CreateSecurityWarnings() { + std::unique_ptr<UiElement> element; + // TODO(mthiesse): Programatically compute the proper texture size for these // textured UI elements. element = base::MakeUnique<PermanentSecurityWarning>(512); - element->id = id++; - element->name = "Permanent security warning"; + element->id = AllocateId(); element->fill = vr_shell::Fill::NONE; element->size = {kPermanentWarningWidth, kPermanentWarningHeight, 1}; element->scale = {kWarningDistance, kWarningDistance, 1}; @@ -57,10 +72,8 @@ permanent_security_warning_ = element.get(); scene_->AddUiElement(std::move(element)); - // Transient WebVR security warning. element = base::MakeUnique<TransientSecurityWarning>(1024); - element->id = id++; - element->name = "Transient security warning"; + element->id = AllocateId(); element->fill = vr_shell::Fill::NONE; element->size = {kTransientWarningWidth, kTransientWarningHeight, 1}; element->scale = {kWarningDistance, kWarningDistance, 1}; @@ -70,20 +83,86 @@ element->lock_to_fov = true; transient_security_warning_ = element.get(); scene_->AddUiElement(std::move(element)); +} - // Main web content quad. +void UiSceneManager::CreateContentQuad() { + std::unique_ptr<UiElement> element; + element = base::MakeUnique<UiElement>(); - element->id = id++; - element->name = "Content"; + element->id = AllocateId(); element->fill = vr_shell::Fill::CONTENT; element->size = {kContentWidth, kContentHeight, 1}; element->translation = {0, kContentVerticalOffset, -kContentDistance}; element->visible = false; main_content_ = element.get(); + browser_ui_elements_.push_back(element.get()); scene_->AddUiElement(std::move(element)); + + // Place an invisible but hittable plane behind the content quad, to keep the + // reticle roughly planar with the content if near content. + element = base::MakeUnique<UiElement>(); + element->id = AllocateId(); + element->fill = vr_shell::Fill::NONE; + element->size = {kBackplaneSize, kBackplaneSize, 1.0}; + element->translation = {0.0, 0.0, -kTextureOffset}; + element->parent_id = main_content_->id; + browser_ui_elements_.push_back(element.get()); + scene_->AddUiElement(std::move(element)); + + // Limit reticle distance to a sphere based on content distance. + scene_->SetBackgroundDistance(main_content_->translation.z() * + -kBackgroundDistanceMultiplier); } -UiSceneManager::~UiSceneManager() {} +void UiSceneManager::CreateBackground() { + std::unique_ptr<UiElement> element; + + // Floor. + element = base::MakeUnique<UiElement>(); + element->id = AllocateId(); + element->size = {kSceneSize, kSceneSize, 1.0}; + element->translation = {0.0, -kSceneHeight / 2, 0.0}; + element->rotation = {1.0, 0.0, 0.0, -M_PI / 2.0}; + element->fill = vr_shell::Fill::OPAQUE_GRADIENT; + element->edge_color = kBackgroundHorizonColor; + element->center_color = kBackgroundCenterColor; + element->draw_phase = 0; + browser_ui_elements_.push_back(element.get()); + scene_->AddUiElement(std::move(element)); + + // Ceiling. + element = base::MakeUnique<UiElement>(); + element->id = AllocateId(); + element->fill = vr_shell::Fill::OPAQUE_GRADIENT; + element->size = {kSceneSize, kSceneSize, 1.0}; + element->translation = {0.0, kSceneHeight / 2, 0.0}; + element->rotation = {1.0, 0.0, 0.0, M_PI / 2}; + element->fill = vr_shell::Fill::OPAQUE_GRADIENT; + element->edge_color = kBackgroundHorizonColor; + element->center_color = kBackgroundCenterColor; + element->draw_phase = 0; + browser_ui_elements_.push_back(element.get()); + scene_->AddUiElement(std::move(element)); + + // Floor grid. + element = base::MakeUnique<UiElement>(); + element->id = AllocateId(); + element->fill = vr_shell::Fill::GRID_GRADIENT; + element->size = {kSceneSize, kSceneSize, 1.0}; + element->translation = {0.0, -kSceneHeight / 2 + kTextureOffset, 0.0}; + element->rotation = {1.0, 0.0, 0.0, -M_PI / 2}; + element->fill = vr_shell::Fill::GRID_GRADIENT; + element->center_color = kBackgroundHorizonColor; + vr::Colorf edge_color = kBackgroundHorizonColor; + edge_color.a = 0.0; + element->edge_color = edge_color; + element->gridline_count = kFloorGridlineCount; + element->draw_phase = 0; + browser_ui_elements_.push_back(element.get()); + scene_->AddUiElement(std::move(element)); + + scene_->SetBackgroundColor(kBackgroundHorizonColor); +} base::WeakPtr<UiSceneManager> UiSceneManager::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); @@ -91,7 +170,12 @@ void UiSceneManager::SetWebVRMode(bool web_vr) { web_vr_mode_ = web_vr; - main_content_->visible = !web_vr_mode_; + + // Make all VR scene UI elements visible if not in WebVR. + for (UiElement* element : browser_ui_elements_) { + element->visible = !web_vr_mode_; + } + ConfigureSecurityWarnings(); } @@ -117,4 +201,8 @@ transient_security_warning_->visible = false; } +int UiSceneManager::AllocateId() { + return next_available_id_++; +} + } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.h b/chrome/browser/android/vr_shell/ui_scene_manager.h index 62f2f98..72a8ab3 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager.h +++ b/chrome/browser/android/vr_shell/ui_scene_manager.h
@@ -26,9 +26,13 @@ void SetWebVRMode(bool web_vr); private: + void CreateSecurityWarnings(); + void CreateContentQuad(); + void CreateBackground(); + void ConfigureSecurityWarnings(); void OnSecurityWarningTimer(); - void OnGLInitialized(); + int AllocateId(); UiScene* scene_; @@ -40,6 +44,10 @@ bool web_vr_mode_ = false; bool secure_origin_ = false; + int next_available_id_ = 1; + + std::vector<UiElement*> browser_ui_elements_; + base::OneShotTimer security_warning_timer_; base::WeakPtrFactory<UiSceneManager> weak_ptr_factory_;
diff --git a/chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc b/chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc index 7a560a276..b9281da 100644 --- a/chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc +++ b/chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc
@@ -14,7 +14,9 @@ #include "chrome/test/base/testing_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/personal_data_manager.h" +#include "components/autofill/core/common/autofill_pref_names.h" #include "components/infobars/core/confirm_infobar_delegate.h" +#include "components/prefs/pref_service.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -54,7 +56,10 @@ void TearDown() override; protected: - std::unique_ptr<ConfirmInfoBarDelegate> CreateDelegate(bool is_uploading); + std::unique_ptr<ConfirmInfoBarDelegate> CreateDelegate( + bool is_uploading, + prefs::PreviousSaveCreditCardPromptUserDecision + previous_save_credit_card_prompt_user_decision); std::unique_ptr<TestPersonalDataManager> personal_data_; @@ -80,6 +85,10 @@ personal_data_.reset(new TestPersonalDataManager()); personal_data_->set_database(autofill_client->GetDatabase()); personal_data_->SetPrefService(profile()->GetPrefs()); + + profile()->GetPrefs()->SetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE); } void AutofillSaveCardInfoBarDelegateMobileTest::TearDown() { @@ -88,7 +97,10 @@ } std::unique_ptr<ConfirmInfoBarDelegate> -AutofillSaveCardInfoBarDelegateMobileTest::CreateDelegate(bool is_uploading) { +AutofillSaveCardInfoBarDelegateMobileTest::CreateDelegate( + bool is_uploading, + prefs::PreviousSaveCreditCardPromptUserDecision + previous_save_credit_card_prompt_user_decision) { base::HistogramTester histogram_tester; CreditCard credit_card; std::unique_ptr<base::DictionaryValue> legal_message; @@ -97,11 +109,25 @@ is_uploading, credit_card, std::move(legal_message), base::Bind(base::IgnoreResult( &TestPersonalDataManager::SaveImportedCreditCard), - base::Unretained(personal_data_.get()), credit_card))); + base::Unretained(personal_data_.get()), credit_card), + profile()->GetPrefs())); std::string destination = is_uploading ? ".Server" : ".Local"; - histogram_tester.ExpectUniqueSample("Autofill.CreditCardInfoBar" - + destination, - AutofillMetrics::INFOBAR_SHOWN, 1); + std::string previous_response; + switch (previous_save_credit_card_prompt_user_decision) { + case prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED: + previous_response = ".PreviouslyAccepted"; + break; + case prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED: + previous_response = ".PreviouslyDenied"; + break; + default: + EXPECT_EQ(previous_save_credit_card_prompt_user_decision, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE); + break; + } + histogram_tester.ExpectUniqueSample( + "Autofill.CreditCardInfoBar" + destination + previous_response, + AutofillMetrics::INFOBAR_SHOWN, 1); return delegate; } @@ -111,8 +137,9 @@ // Accept the infobar. { - std::unique_ptr<ConfirmInfoBarDelegate> infobar( - CreateDelegate(/* is_uploading= */ false)); + std::unique_ptr<ConfirmInfoBarDelegate> infobar(CreateDelegate( + /* is_uploading= */ false, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE)); EXPECT_CALL(*personal_data_, SaveImportedCreditCard(_)); base::HistogramTester histogram_tester; @@ -123,35 +150,41 @@ // Cancel the infobar. { - std::unique_ptr<ConfirmInfoBarDelegate> infobar( - CreateDelegate(/* is_uploading= */ false)); + std::unique_ptr<ConfirmInfoBarDelegate> infobar(CreateDelegate( + /* is_uploading= */ false, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED)); base::HistogramTester histogram_tester; EXPECT_TRUE(infobar->Cancel()); - histogram_tester.ExpectUniqueSample("Autofill.CreditCardInfoBar.Local", - AutofillMetrics::INFOBAR_DENIED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CreditCardInfoBar.Local.PreviouslyAccepted", + AutofillMetrics::INFOBAR_DENIED, 1); } // Dismiss the infobar. { - std::unique_ptr<ConfirmInfoBarDelegate> infobar( - CreateDelegate(/* is_uploading= */ false)); + std::unique_ptr<ConfirmInfoBarDelegate> infobar(CreateDelegate( + /* is_uploading= */ false, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED)); base::HistogramTester histogram_tester; infobar->InfoBarDismissed(); - histogram_tester.ExpectUniqueSample("Autofill.CreditCardInfoBar.Local", - AutofillMetrics::INFOBAR_DENIED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CreditCardInfoBar.Local.PreviouslyDenied", + AutofillMetrics::INFOBAR_DENIED, 1); } // Ignore the infobar. { - std::unique_ptr<ConfirmInfoBarDelegate> infobar( - CreateDelegate(/* is_uploading= */ false)); + std::unique_ptr<ConfirmInfoBarDelegate> infobar(CreateDelegate( + /* is_uploading= */ false, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED)); base::HistogramTester histogram_tester; infobar.reset(); - histogram_tester.ExpectUniqueSample("Autofill.CreditCardInfoBar.Local", - AutofillMetrics::INFOBAR_IGNORED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CreditCardInfoBar.Local.PreviouslyDenied", + AutofillMetrics::INFOBAR_IGNORED, 1); } } @@ -161,8 +194,9 @@ // Accept the infobar. { - std::unique_ptr<ConfirmInfoBarDelegate> infobar( - CreateDelegate(/* is_uploading= */ true)); + std::unique_ptr<ConfirmInfoBarDelegate> infobar(CreateDelegate( + /* is_uploading= */ true, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE)); EXPECT_CALL(*personal_data_, SaveImportedCreditCard(_)); base::HistogramTester histogram_tester; @@ -173,35 +207,41 @@ // Cancel the infobar. { - std::unique_ptr<ConfirmInfoBarDelegate> infobar( - CreateDelegate(/* is_uploading= */ true)); + std::unique_ptr<ConfirmInfoBarDelegate> infobar(CreateDelegate( + /* is_uploading= */ true, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED)); base::HistogramTester histogram_tester; EXPECT_TRUE(infobar->Cancel()); - histogram_tester.ExpectUniqueSample("Autofill.CreditCardInfoBar.Server", - AutofillMetrics::INFOBAR_DENIED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CreditCardInfoBar.Server.PreviouslyAccepted", + AutofillMetrics::INFOBAR_DENIED, 1); } // Dismiss the infobar. { - std::unique_ptr<ConfirmInfoBarDelegate> infobar( - CreateDelegate(/* is_uploading= */ true)); + std::unique_ptr<ConfirmInfoBarDelegate> infobar(CreateDelegate( + /* is_uploading= */ true, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED)); base::HistogramTester histogram_tester; infobar->InfoBarDismissed(); - histogram_tester.ExpectUniqueSample("Autofill.CreditCardInfoBar.Server", - AutofillMetrics::INFOBAR_DENIED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CreditCardInfoBar.Server.PreviouslyDenied", + AutofillMetrics::INFOBAR_DENIED, 1); } // Ignore the infobar. { - std::unique_ptr<ConfirmInfoBarDelegate> infobar( - CreateDelegate(/* is_uploading= */ true)); + std::unique_ptr<ConfirmInfoBarDelegate> infobar(CreateDelegate( + /* is_uploading= */ true, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED)); base::HistogramTester histogram_tester; infobar.reset(); - histogram_tester.ExpectUniqueSample("Autofill.CreditCardInfoBar.Server", - AutofillMetrics::INFOBAR_IGNORED, 1); + histogram_tester.ExpectUniqueSample( + "Autofill.CreditCardInfoBar.Server.PreviouslyDenied", + AutofillMetrics::INFOBAR_IGNORED, 1); } }
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc index 6a46751a..f3ab8b7a2 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager.cc +++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -1004,7 +1004,7 @@ void ArcSessionManager::OnSendFeedbackClicked() { DCHECK(support_host_); - chrome::OpenFeedbackDialog(nullptr); + chrome::OpenFeedbackDialog(nullptr, chrome::kFeedbackSourceArcApp); } void ArcSessionManager::SetArcSessionRunnerForTesting(
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc index 00c1c9e..fbe85e25 100644 --- a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc +++ b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
@@ -300,6 +300,19 @@ content::RunAllPendingInMessageLoop(); } + void SetupTether() { + chromeos::NetworkStateHandler* network_state_handler = + chromeos::NetworkHandler::Get()->network_state_handler(); + network_state_handler->SetTetherTechnologyState( + chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); + network_state_handler->AddTetherNetworkState( + "tetherGuid1", "tetherName1", "tetherCarrier1", + 50 /* battery_percentage */, 75 /* signal_strength */); + network_state_handler->AddTetherNetworkState( + "tetherGuid2", "tetherName2", "tetherCarrier2", + 75 /* battery_percentage */, 100 /* signal_strength */); + } + void AddService(const std::string& service_path, const std::string& name, const std::string& type, @@ -851,6 +864,31 @@ EXPECT_TRUE(RunNetworkingSubtest("getGlobalPolicy")) << message_; } +IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, + Tether_GetTetherNetworks) { + SetupTether(); + EXPECT_TRUE(RunNetworkingSubtest("getTetherNetworks")) << message_; +} + +IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, + Tether_GetTetherNetworkProperties) { + SetupTether(); + EXPECT_TRUE(RunNetworkingSubtest("getTetherNetworkProperties")) << message_; +} + +IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, + Tether_GetTetherNetworkManagedProperties) { + SetupTether(); + EXPECT_TRUE(RunNetworkingSubtest("getTetherNetworkManagedProperties")) + << message_; +} + +IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, + Tether_GetTetherNetworkState) { + SetupTether(); + EXPECT_TRUE(RunNetworkingSubtest("getTetherNetworkState")) << message_; +} + // Tests subset of networking API for the networking API alias - to verify that // using API methods and event does not cause access exceptions (due to // missing permissions).
diff --git a/chrome/browser/feedback/show_feedback_page.cc b/chrome/browser/feedback/show_feedback_page.cc index d3e0cd8..d3091ba 100644 --- a/chrome/browser/feedback/show_feedback_page.cc +++ b/chrome/browser/feedback/show_feedback_page.cc
@@ -4,10 +4,12 @@ #include <string> +#include "base/metrics/histogram_macros.h" #include "chrome/browser/extensions/api/feedback_private/feedback_private_api.h" #include "chrome/browser/feedback/feedback_dialog_utils.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/webui/md_feedback/md_feedback_dialog_controller.h" #include "chrome/common/chrome_switches.h" @@ -15,6 +17,7 @@ namespace chrome { void ShowFeedbackPage(Browser* browser, + FeedbackSource source, const std::string& description_template, const std::string& category_tag) { GURL page_url; @@ -29,6 +32,10 @@ return; } + // Record an UMA histogram to know the most frequent feedback request source. + UMA_HISTOGRAM_ENUMERATION("Feedback.RequestSource", source, + kFeedbackSourceCount); + if (::switches::MdFeedbackEnabled()) { MdFeedbackDialogController::GetInstance()->Show(profile); return;
diff --git a/chrome/browser/resources/settings/device_page/display.html b/chrome/browser/resources/settings/device_page/display.html index a3d4928..b0dea45 100644 --- a/chrome/browser/resources/settings/device_page/display.html +++ b/chrome/browser/resources/settings/device_page/display.html
@@ -40,10 +40,6 @@ margin: 10px 0; } - .title-text { - margin-top: 10px; - } - .settings-box > paper-button:first-child { -webkit-padding-start: 0 } @@ -57,9 +53,9 @@ } </style> <div class="settings-box first layout vertical self-stretch"> - <div class="title-text layout self-start"> + <h2 class="layout self-start"> $i18n{displayArrangementTitle} - </div> + </h2> <div class="secondary layout self-start" hidden="[[!hasMultipleDisplays_(displays)]]"> $i18n{displayArrangementText}
diff --git a/chrome/browser/resources/settings/device_page/pointers.html b/chrome/browser/resources/settings/device_page/pointers.html index ef0c121..97743b2 100644 --- a/chrome/browser/resources/settings/device_page/pointers.html +++ b/chrome/browser/resources/settings/device_page/pointers.html
@@ -53,12 +53,14 @@ <!-- Subsection title only appears if both mouse and touchpad exist. --> <h2 hidden$="[[!hasMouse]]">$i18n{touchpadTitle}</h2> <div class$="[[getSubsectionClass_(hasMouse, hasTouchpad)]]"> - <div class="settings-box block first"> - <settings-toggle-button id="enableTapToClick" + <div class="settings-box first"> + <settings-toggle-button id="enableTapToClick" class="start" pref="{{prefs.settings.touchpad.enable_tap_to_click}}" label="$i18n{touchpadTapToClickEnabledLabel}"> </settings-toggle-button> - <settings-toggle-button id="enableTapDragging" + </div> + <div class="settings-box"> + <settings-toggle-button id="enableTapDragging" class="start" pref="{{prefs.settings.touchpad.enable_tap_dragging}}" label="$i18n{tapDraggingLabel}"> </settings-toggle-button>
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage_search.html b/chrome/browser/resources/settings/settings_page/settings_subpage_search.html index c3aacac..7b88464a 100644 --- a/chrome/browser/resources/settings/settings_page/settings_subpage_search.html +++ b/chrome/browser/resources/settings/settings_page/settings_subpage_search.html
@@ -1,4 +1,5 @@ <link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field_behavior.html"> +<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> @@ -7,7 +8,7 @@ <dom-module id="settings-subpage-search"> <template> - <style> + <style include="cr-hidden-style"> :host { --subpage-search-underline: { margin-bottom: -2px;
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html index 0564325..d962b62f 100644 --- a/chrome/browser/resources/settings/site_settings/site_list.html +++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -3,6 +3,7 @@ <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> <link rel="import" href="../i18n_setup.html"> @@ -17,7 +18,7 @@ <dom-module id="site-list"> <template> - <style include="settings-shared"> + <style include="settings-shared iron-flex"> .selectable { -webkit-user-select: text; }
diff --git a/chrome/browser/safe_browsing/srt_prompt_controller.cc b/chrome/browser/safe_browsing/srt_prompt_controller.cc index 75bdfa0..02727a78 100644 --- a/chrome/browser/safe_browsing/srt_prompt_controller.cc +++ b/chrome/browser/safe_browsing/srt_prompt_controller.cc
@@ -4,9 +4,6 @@ #include "chrome/browser/safe_browsing/srt_prompt_controller.h" -#include <initializer_list> - -#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" namespace safe_browsing { @@ -15,49 +12,16 @@ // Some dummy strings to be displayed in the Cleaner dialog while iterating on // the dialog's UX design and work on the Chrome<->Cleaner IPC is ongoing. -constexpr char kMainTextIntroduction[] = - "Have you seen unusual startup pages or strange search results? Chrome has " - "detected the following kinds of programs on your computer that may be " - "causing the problem:"; -constexpr char kMainTextActionExplanation[] = - "Chrome can remove the detected programs, which should stop the strange " - "behavior."; -constexpr char kUnwantedSoftwareCategory1[] = "1 Browser hijacker"; -constexpr char kUnwantedSoftwareCategory2[] = "2 Ad Injectors"; - -constexpr char kDetailsSectionSettingsResetExplanation[] = - "Chrome will reset the following settings:"; -constexpr char kDetailsSectionSetting1[] = "Default search engine"; -constexpr char kDetailsSectionSetting2[] = "Startup pages"; -constexpr char kDetailsSectionSetting3[] = "Homepage"; -constexpr char kDetailsSectionSetting4[] = "Shortcuts"; -constexpr char kDetailsSectionSetting5[] = - "All extensions (these can be enabled again later)"; -constexpr char kDetailsSectionActionExplanation[] = - "The following files will be removed:"; -constexpr char kDetailsSectionPoweredBy[] = "Powered by: <ESET logo>"; - -constexpr char kDummyDirectory[] = - "C:\\Documents and Settings\\JohnDoe\\Local Settings\\Application Data" - "\\IAmNotWanted\\application\\"; -constexpr char kDummyFilename1[] = "somefile.dll"; -constexpr char kDummyFilename2[] = "another_file.dll"; -constexpr char kDummyFilename3[] = "more_stuff.dll"; -constexpr char kDummyFilename4[] = "run_me.exe"; - -constexpr char kShowDetails[] = "Learn more"; -constexpr char kHideDetails[] = "Close"; -constexpr char kWindowTitle[] = "Chrome detected unusual behavior"; -constexpr char kAcceptButtonLabel[] = "Start cleanup"; +constexpr char kWindowTitle[] = "Clean up your computer?"; +constexpr char kMainText[] = + "Chrome found software that harms your browsing experience. Remove related " + "files from your computer and restore browser settings, including your " + "search engine and home page."; +constexpr char kAcceptButtonLabel[] = "Cleanup"; +constexpr char kAdvancedButtonLabel[] = "Advanced"; } // namespace -SRTPromptController::LabelInfo::LabelInfo(LabelType type, - const base::string16& text) - : type(type), text(text) {} - -SRTPromptController::LabelInfo::~LabelInfo() = default; - SRTPromptController::SRTPromptController() {} SRTPromptController::~SRTPromptController() = default; @@ -66,65 +30,18 @@ return base::UTF8ToUTF16(kWindowTitle); } -std::vector<SRTPromptController::LabelInfo> SRTPromptController::GetMainText() - const { - return { - LabelInfo(LabelInfo::PARAGRAPH, base::UTF8ToUTF16(kMainTextIntroduction)), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(kUnwantedSoftwareCategory1)), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(kUnwantedSoftwareCategory2)), - LabelInfo(LabelInfo::PARAGRAPH, - base::UTF8ToUTF16(kMainTextActionExplanation)), - }; -} - -std::vector<SRTPromptController::LabelInfo> -SRTPromptController::GetDetailsText() const { - return { - LabelInfo(LabelInfo::PARAGRAPH, - base::UTF8ToUTF16(kDetailsSectionSettingsResetExplanation)), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(kDetailsSectionSetting1)), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(kDetailsSectionSetting2)), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(kDetailsSectionSetting3)), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(kDetailsSectionSetting4)), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(kDetailsSectionSetting5)), - LabelInfo(LabelInfo::PARAGRAPH, - base::UTF8ToUTF16(kDetailsSectionActionExplanation)), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(base::JoinString( - {kDummyDirectory, kDummyFilename1}, nullptr))), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(base::JoinString( - {kDummyDirectory, kDummyFilename2}, nullptr))), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(base::JoinString( - {kDummyDirectory, kDummyFilename3}, nullptr))), - LabelInfo(LabelInfo::BULLET_ITEM, - base::UTF8ToUTF16(base::JoinString( - {kDummyDirectory, kDummyFilename4}, nullptr))), - LabelInfo(LabelInfo::PARAGRAPH, - base::UTF8ToUTF16(kDetailsSectionPoweredBy)), - }; -} - -base::string16 SRTPromptController::GetShowDetailsLabel() const { - return base::UTF8ToUTF16(kShowDetails); -} - -base::string16 SRTPromptController::GetHideDetailsLabel() const { - return base::UTF8ToUTF16(kHideDetails); +base::string16 SRTPromptController::GetMainText() const { + return base::UTF8ToUTF16(kMainText); } base::string16 SRTPromptController::GetAcceptButtonLabel() const { return base::UTF8ToUTF16(kAcceptButtonLabel); } +base::string16 SRTPromptController::GetAdvancedButtonLabel() const { + return base::UTF8ToUTF16(kAdvancedButtonLabel); +} + void SRTPromptController::DialogShown() {} void SRTPromptController::Accept() { @@ -135,6 +52,14 @@ OnInteractionDone(); } +void SRTPromptController::Close() { + OnInteractionDone(); +} + +void SRTPromptController::AdvancedButtonClicked() { + OnInteractionDone(); +} + void SRTPromptController::OnInteractionDone() { delete this; }
diff --git a/chrome/browser/safe_browsing/srt_prompt_controller.h b/chrome/browser/safe_browsing/srt_prompt_controller.h index 3546491..81dca5b 100644 --- a/chrome/browser/safe_browsing/srt_prompt_controller.h +++ b/chrome/browser/safe_browsing/srt_prompt_controller.h
@@ -16,57 +16,40 @@ // UI. Also provides functions, such as |Accept()| and |Cancel()|, that should // be called by the UI in response to user actions. // -// Objects of this class are typically created by the SwReporterProcess class, -// which will pass in information the controller needs to be able to create -// strings to be displayed in the prompt dialog. -// // This class manages its own lifetime and will delete itself once the Cleaner // dialog has been dismissed and either of |Accept()| or |Cancel()| have been // called. class SRTPromptController { public: - struct LabelInfo { - enum LabelType { - // Indicates that |text| should be displayed as a multi-line label. - PARAGRAPH, - // Indicates that |text| should be displayed as a multi-line label that is - // indented and starts with a bullet point. - BULLET_ITEM, - }; - - LabelInfo(LabelType type, const base::string16& text); - ~LabelInfo(); - - LabelType type; - base::string16 text; - }; - SRTPromptController(); base::string16 GetWindowTitle() const; - // The text to be shown in the Cleaner dialog's main section and will - // always be visible while the dialog is displayed. - std::vector<LabelInfo> GetMainText() const; - // The text to be shown in the expandable details section of the - // Cleaner dialog. - std::vector<LabelInfo> GetDetailsText() const; - // The text on the button that expands the details section. - base::string16 GetShowDetailsLabel() const; - // The text on the button that folds the details section. - base::string16 GetHideDetailsLabel() const; + base::string16 GetMainText() const; base::string16 GetAcceptButtonLabel() const; + base::string16 GetAdvancedButtonLabel() const; // Called by the Cleaner dialog when the dialog has been shown. Used for // reporting metrics. void DialogShown(); // Called by the Cleaner dialog when user accepts the prompt. Once |Accept()| - // has been called, the controller will eventually delete itself and so no - // member functions should be called after that. + // has been called, the controller will eventually delete itself and no member + // functions should be called after that. void Accept(); - // Called by the Cleaner dialog when the dialog is dismissed or canceled. Once - // |Cancel()| has been called, the controller will eventually delete itself - // and so no member functions should be called after that. + // Called by the Cleaner dialog when the dialog is closed via the cancel + // button. Once |Cancel()| has been called, the controller will eventually + // delete itself and no member functions should be called after that. void Cancel(); + // Called by the Cleaner dialog when the dialog is closed by some other means + // than the cancel button (for example, by pressing Esc or clicking the 'x' on + // the top of the dialog). After a call to |Dismiss()|, the controller will + // eventually delete itself and no member functions should be called after + // that. + void Close(); + // Called when the advanced button is clicked, after which the dialog will + // close. After a call to |AdvancedButtonClicked()|, the controller will + // eventually delete itself and no member functions should be called after + // that. + void AdvancedButtonClicked(); protected: ~SRTPromptController();
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.cc b/chrome/browser/supervised_user/supervised_user_interstitial.cc index 0e25c7c..311e725 100644 --- a/chrome/browser/supervised_user/supervised_user_interstitial.cc +++ b/chrome/browser/supervised_user/supervised_user_interstitial.cc
@@ -271,7 +271,8 @@ ReportChildAccountFeedback(web_contents_, message, url_); #else chrome::ShowFeedbackPage(chrome::FindBrowserWithWebContents(web_contents_), - message, std::string()); + chrome::kFeedbackSourceSupervisedUserInterstitial, + message, std::string() /* category_tag */); #endif return; }
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc index 90f4deed..e9a75ec 100644 --- a/chrome/browser/ui/ash/chrome_new_window_client.cc +++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -218,5 +218,5 @@ } void ChromeNewWindowClient::OpenFeedbackPage() { - chrome::OpenFeedbackDialog(GetActiveBrowser()); + chrome::OpenFeedbackDialog(GetActiveBrowser(), chrome::kFeedbackSourceAsh); }
diff --git a/chrome/browser/ui/ash/ime_controller_chromeos.cc b/chrome/browser/ui/ash/ime_controller_chromeos.cc index f9637bb..d252e368 100644 --- a/chrome/browser/ui/ash/ime_controller_chromeos.cc +++ b/chrome/browser/ui/ash/ime_controller_chromeos.cc
@@ -10,6 +10,12 @@ bool ImeController::CanCycleIme() { chromeos::input_method::InputMethodManager* manager = chromeos::input_method::InputMethodManager::Get(); + DCHECK(manager); + if (!manager->GetActiveIMEState()) { + LOG(WARNING) << "Cannot cycle through input methods as they are not " + "initialized yet."; + return false; + } return manager->GetActiveIMEState()->CanCycleInputMethod(); } @@ -28,6 +34,12 @@ bool ImeController::CanSwitchIme(const ui::Accelerator& accelerator) { chromeos::input_method::InputMethodManager* manager = chromeos::input_method::InputMethodManager::Get(); + DCHECK(manager); + if (!manager->GetActiveIMEState()) { + LOG(WARNING) << "Cannot switch input methods as they are not " + "initialized yet."; + return false; + } return manager->GetActiveIMEState()->CanSwitchInputMethod(accelerator); }
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index a3da129..9c9e27f 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -76,8 +76,6 @@ user_prefs::UserPrefs::Get(web_contents->GetBrowserContext()), Profile::FromBrowserContext(web_contents->GetBrowserContext()) ->IsOffTheRecord()) { - DCHECK(web_contents); - #if !defined(OS_ANDROID) // Since ZoomController is also a WebContentsObserver, we need to be careful // about disconnecting from it since the relative order of destruction of @@ -192,7 +190,7 @@ ->AddInfoBar(CreateSaveCardInfoBarMobile( base::MakeUnique<AutofillSaveCardInfoBarDelegateMobile>( false, card, std::unique_ptr<base::DictionaryValue>(nullptr), - callback))); + callback, GetPrefs()))); #else // Do lazy initialization of SaveCardBubbleControllerImpl. autofill::SaveCardBubbleControllerImpl::CreateForWebContents( @@ -212,7 +210,7 @@ InfoBarService::FromWebContents(web_contents()) ->AddInfoBar(CreateSaveCardInfoBarMobile( base::MakeUnique<AutofillSaveCardInfoBarDelegateMobile>( - true, card, std::move(legal_message), callback))); + true, card, std::move(legal_message), callback, GetPrefs()))); #else // Do lazy initialization of SaveCardBubbleControllerImpl. autofill::SaveCardBubbleControllerImpl::CreateForWebContents(web_contents());
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc index 78ad6a8..4aaaf03 100644 --- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc +++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
@@ -14,8 +14,11 @@ #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_pref_names.h" #include "components/grit/components_scaled_resources.h" +#include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" +#include "components/user_prefs/user_prefs.h" #include "content/public/browser/navigation_handle.h" #include "ui/base/l10n/l10n_util.h" @@ -35,9 +38,9 @@ SaveCardBubbleControllerImpl::SaveCardBubbleControllerImpl( content::WebContents* web_contents) : content::WebContentsObserver(web_contents), - save_card_bubble_view_(nullptr) { - DCHECK(web_contents); -} + save_card_bubble_view_(nullptr), + pref_service_( + user_prefs::UserPrefs::Get(web_contents->GetBrowserContext())) {} SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() { if (save_card_bubble_view_) @@ -54,7 +57,9 @@ AutofillMetrics::LogSaveCardPromptMetric( AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_uploading_, - is_reshow_); + is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); card_ = card; save_card_callback_ = save_card_callback; @@ -71,12 +76,16 @@ should_cvc_be_requested_ = should_cvc_be_requested; AutofillMetrics::LogSaveCardPromptMetric( AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_uploading_, - is_reshow_); + is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); if (!LegalMessageLine::Parse(*legal_message, &legal_message_lines_)) { AutofillMetrics::LogSaveCardPromptMetric( AutofillMetrics::SAVE_CARD_PROMPT_END_INVALID_LEGAL_MESSAGE, - is_uploading_, is_reshow_); + is_uploading_, is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); return; } @@ -96,7 +105,9 @@ is_reshow_ = true; AutofillMetrics::LogSaveCardPromptMetric( AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, is_uploading_, - is_reshow_); + is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); ShowBubble(); } @@ -151,28 +162,41 @@ save_card_callback_.Run(); save_card_callback_.Reset(); AutofillMetrics::LogSaveCardPromptMetric( - AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, is_uploading_, - is_reshow_); + AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, is_uploading_, is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); + pref_service_->SetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED); } void SaveCardBubbleControllerImpl::OnCancelButton() { save_card_callback_.Reset(); AutofillMetrics::LogSaveCardPromptMetric( - AutofillMetrics::SAVE_CARD_PROMPT_END_DENIED, is_uploading_, is_reshow_); + AutofillMetrics::SAVE_CARD_PROMPT_END_DENIED, is_uploading_, is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); + pref_service_->SetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED); } void SaveCardBubbleControllerImpl::OnLearnMoreClicked() { OpenUrl(GURL(kHelpURL)); AutofillMetrics::LogSaveCardPromptMetric( AutofillMetrics::SAVE_CARD_PROMPT_DISMISS_CLICK_LEARN_MORE, is_uploading_, - is_reshow_); + is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); } void SaveCardBubbleControllerImpl::OnLegalMessageLinkClicked(const GURL& url) { OpenUrl(url); AutofillMetrics::LogSaveCardPromptMetric( AutofillMetrics::SAVE_CARD_PROMPT_DISMISS_CLICK_LEGAL_MESSAGE, - is_uploading_, is_reshow_); + is_uploading_, is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); } void SaveCardBubbleControllerImpl::OnBubbleClosed() { @@ -222,13 +246,17 @@ AutofillMetrics::LogSaveCardPromptMetric( AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_SHOWING, is_uploading_, - is_reshow_); + is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); } else { UpdateIcon(); AutofillMetrics::LogSaveCardPromptMetric( AutofillMetrics::SAVE_CARD_PROMPT_END_NAVIGATION_HIDDEN, is_uploading_, - is_reshow_); + is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); } } @@ -252,7 +280,9 @@ timer_.reset(new base::ElapsedTimer()); AutofillMetrics::LogSaveCardPromptMetric( - AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, is_uploading_, is_reshow_); + AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, is_uploading_, is_reshow_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); } void SaveCardBubbleControllerImpl::UpdateIcon() {
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h index 1f5382f..2b924ab8 100644 --- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h +++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
@@ -14,6 +14,8 @@ #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" +class PrefService; + namespace autofill { // Implementation of per-tab class to control the save credit card bubble and @@ -93,6 +95,9 @@ // Weak reference. Will be nullptr if no bubble is currently shown. SaveCardBubbleView* save_card_bubble_view_; + // Weak reference to read & write |kAutofillAcceptSaveCreditCardPromptState|. + PrefService* pref_service_; + // Callback to run if user presses Save button in the bubble. // If save_card_callback_.is_null() is true then no bubble is available to // show and the icon is not visible.
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc index a1121ec0e..fc31bc0 100644 --- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc +++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
@@ -18,6 +18,8 @@ #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/user_prefs/user_prefs.h" #include "content/public/browser/navigation_handle.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -61,8 +63,13 @@ void SetUp() override { BrowserWithTestWindowTest::SetUp(); AddTab(browser(), GURL("about:blank")); - TestSaveCardBubbleControllerImpl::CreateForTesting( - browser()->tab_strip_model()->GetActiveWebContents()); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + TestSaveCardBubbleControllerImpl::CreateForTesting(web_contents); + user_prefs::UserPrefs::Get(web_contents->GetBrowserContext()) + ->SetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE); } BrowserWindow* CreateBrowserWindow() override { @@ -267,6 +274,63 @@ } TEST_F(SaveCardBubbleControllerImplTest, + Metrics_Local_FirstShow_CancelButton_FirstShow) { + base::HistogramTester histogram_tester; + ShowLocalBubble(); + controller()->OnCancelButton(); + controller()->OnBubbleClosed(); + + ShowLocalBubble(); + controller()->OnCancelButton(); + controller()->OnBubbleClosed(); + + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.SaveCreditCardPrompt.Local.FirstShow"), + ElementsAre(Bucket(AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, 1), + Bucket(AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, 1), + Bucket(AutofillMetrics::SAVE_CARD_PROMPT_END_DENIED, 1))); + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.SaveCreditCardPrompt.Local.FirstShow.PreviouslyDenied"), + ElementsAre(Bucket(AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, 1), + Bucket(AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, 1), + Bucket(AutofillMetrics::SAVE_CARD_PROMPT_END_DENIED, 1))); +} + +TEST_F(SaveCardBubbleControllerImplTest, + Metrics_Local_FirstShow_CancelButton_FirstShow_SaveButton_FirstShow) { + base::HistogramTester histogram_tester; + ShowLocalBubble(); + controller()->OnCancelButton(); + controller()->OnBubbleClosed(); + + ShowLocalBubble(); + controller()->OnSaveButton(); + controller()->OnBubbleClosed(); + + ShowLocalBubble(); + + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.SaveCreditCardPrompt.Local.FirstShow"), + ElementsAre(Bucket(AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, 1), + Bucket(AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, 1), + Bucket(AutofillMetrics::SAVE_CARD_PROMPT_END_DENIED, 1))); + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.SaveCreditCardPrompt.Local.FirstShow.PreviouslyAccepted"), + ElementsAre(Bucket(AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, 1), + Bucket(AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, 1))); + EXPECT_THAT( + histogram_tester.GetAllSamples( + "Autofill.SaveCreditCardPrompt.Local.FirstShow.PreviouslyDenied"), + ElementsAre(Bucket(AutofillMetrics::SAVE_CARD_PROMPT_SHOW_REQUESTED, 1), + Bucket(AutofillMetrics::SAVE_CARD_PROMPT_SHOWN, 1), + Bucket(AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, 1))); +} + +TEST_F(SaveCardBubbleControllerImplTest, Metrics_Local_FirstShow_NavigateWhileShowing) { ShowLocalBubble();
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc index a8f59027..e917e171 100644 --- a/chrome/browser/ui/browser_command_controller.cc +++ b/chrome/browser/ui/browser_command_controller.cc
@@ -559,7 +559,7 @@ #endif #if defined(GOOGLE_CHROME_BUILD) case IDC_FEEDBACK: - OpenFeedbackDialog(browser_); + OpenFeedbackDialog(browser_, kFeedbackSourceBrowserCommand); break; #endif case IDC_SHOW_BOOKMARK_BAR:
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc index b8c0b13..713c98e 100644 --- a/chrome/browser/ui/browser_commands.cc +++ b/chrome/browser/ui/browser_commands.cc
@@ -13,7 +13,6 @@ #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browsing_data/browsing_data_helper.h" - #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/devtools/devtools_window.h" @@ -1103,9 +1102,11 @@ #endif } -void OpenFeedbackDialog(Browser* browser) { +void OpenFeedbackDialog(Browser* browser, FeedbackSource source) { base::RecordAction(UserMetricsAction("Feedback")); - chrome::ShowFeedbackPage(browser, std::string(), std::string()); + chrome::ShowFeedbackPage(browser, source, + std::string() /* description_template */, + std::string() /* category_tag */); } void ToggleBookmarkBar(Browser* browser) {
diff --git a/chrome/browser/ui/browser_commands.h b/chrome/browser/ui/browser_commands.h index 1c5d567..235a46e 100644 --- a/chrome/browser/ui/browser_commands.h +++ b/chrome/browser/ui/browser_commands.h
@@ -9,6 +9,7 @@ #include "build/build_config.h" #include "chrome/browser/devtools/devtools_toggle_action.h" +#include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" #include "content/public/common/page_zoom.h" #include "printing/features/features.h" @@ -130,7 +131,7 @@ void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action); bool CanOpenTaskManager(); void OpenTaskManager(Browser* browser); -void OpenFeedbackDialog(Browser* browser); +void OpenFeedbackDialog(Browser* browser, FeedbackSource source); void ToggleBookmarkBar(Browser* browser); void ShowAppMenu(Browser* browser); void ShowAvatarMenu(Browser* browser);
diff --git a/chrome/browser/ui/chrome_pages.h b/chrome/browser/ui/chrome_pages.h index 98513eba..61f08af 100644 --- a/chrome/browser/ui/chrome_pages.h +++ b/chrome/browser/ui/chrome_pages.h
@@ -34,6 +34,24 @@ HELP_SOURCE_WEBUI, }; +// Sources of feedback requests. +// +// WARNING: The below enum MUST never be renamed, modified or reordered, as +// they're written to logs. You can only insert a new element immediately +// before the last. +enum FeedbackSource { + kFeedbackSourceArcApp = 0, + kFeedbackSourceAsh, + kFeedbackSourceBrowserCommand, + kFeedbackSourceMdSettingsAboutPage, + kFeedbackSourceOldSettingsAboutPage, + kFeedbackSourceProfileErrorDialog, + kFeedbackSourceSadTabPage, + kFeedbackSourceSupervisedUserInterstitial, + + // Must be last. + kFeedbackSourceCount, +}; void ShowBookmarkManager(Browser* browser); void ShowBookmarkManagerForNode(Browser* browser, int64_t node_id); @@ -46,6 +64,7 @@ // ShowFeedbackPage() uses |browser| to determine the URL of the current tab. // |browser| should be NULL if there are no currently open browser windows. void ShowFeedbackPage(Browser* browser, + FeedbackSource source, const std::string& description_template, const std::string& category_tag);
diff --git a/chrome/browser/ui/profile_error_dialog.cc b/chrome/browser/ui/profile_error_dialog.cc index a705b6f9..be87874 100644 --- a/chrome/browser/ui/profile_error_dialog.cc +++ b/chrome/browser/ui/profile_error_dialog.cc
@@ -48,7 +48,8 @@ l10n_util::GetStringUTF8(IDS_PROFILE_ERROR_FEEDBACK_DESCRIPTION); feedback_description += "\n" + diagnostics; - chrome::ShowFeedbackPage(nullptr, feedback_description, + chrome::ShowFeedbackPage(nullptr, chrome::kFeedbackSourceProfileErrorDialog, + feedback_description, kProfileErrorFeedbackCategory); } #endif
diff --git a/chrome/browser/ui/sad_tab.cc b/chrome/browser/ui/sad_tab.cc index 5c88b0cc..c9b3cc42 100644 --- a/chrome/browser/ui/sad_tab.cc +++ b/chrome/browser/ui/sad_tab.cc
@@ -53,7 +53,7 @@ } } -const char kCategoryTagCrash[] = "Crash"; +constexpr char kCategoryTagCrash[] = "Crash"; bool ShouldShowFeedbackButton() { #if defined(GOOGLE_CHROME_BUILD) @@ -158,9 +158,10 @@ case Action::BUTTON: RecordEvent(show_feedback_button_, SadTabEvent::BUTTON_CLICKED); if (show_feedback_button_) { - chrome::ShowFeedbackPage( - chrome::FindBrowserWithWebContents(web_contents_), - l10n_util::GetStringUTF8(kind_ == chrome::SAD_TAB_KIND_CRASHED + ShowFeedbackPage( + FindBrowserWithWebContents(web_contents_), + kFeedbackSourceSadTabPage, + l10n_util::GetStringUTF8(kind_ == SAD_TAB_KIND_CRASHED ? IDS_CRASHED_TAB_FEEDBACK_MESSAGE : IDS_KILLED_TAB_FEEDBACK_MESSAGE), std::string(kCategoryTagCrash));
diff --git a/chrome/browser/ui/views/srt_prompt_dialog.cc b/chrome/browser/ui/views/srt_prompt_dialog.cc index 21ccc1d..24d885b 100644 --- a/chrome/browser/ui/views/srt_prompt_dialog.cc +++ b/chrome/browser/ui/views/srt_prompt_dialog.cc
@@ -4,33 +4,18 @@ #include "chrome/browser/ui/views/srt_prompt_dialog.h" -#include <vector> - -#include "base/memory/ptr_util.h" #include "base/strings/string16.h" -#include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/safe_browsing/srt_prompt_controller.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h" #include "components/constrained_window/constrained_window_views.h" -#include "components/web_modal/web_contents_modal_dialog_host.h" #include "ui/base/ui_base_types.h" #include "ui/events/event.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/gfx/geometry/size.h" #include "ui/gfx/native_widget_types.h" -#include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/text_constants.h" -#include "ui/native_theme/native_theme.h" -#include "ui/views/border.h" #include "ui/views/controls/label.h" -#include "ui/views/controls/scroll_view.h" -#include "ui/views/controls/separator.h" #include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/layout/grid_layout.h" #include "ui/views/layout/layout_constants.h" #include "ui/views/widget/widget.h" @@ -45,198 +30,30 @@ } // namespace chrome namespace { - -using LabelInfo = safe_browsing::SRTPromptController::LabelInfo; - constexpr int kDialogWidth = 448; -constexpr int kDetailsSectionMaxHeight = 150; -constexpr int kBulletColumnWidth = 10; -// Constants used for the layout of the label views. -constexpr int kMainColumSetId = 0; -constexpr int kBulletColumnSetId = 1; - -// Returns a view containing |item| with insets defined by |top|, |left|, -// |bottom|, and |right|. -views::View* CreateViewWithInsets(views::View* item, - int top, - int left, - int bottom, - int right) { - views::View* view = new views::View(); - view->SetLayoutManager(new views::FillLayout()); - view->SetBorder(views::CreateEmptyBorder(top, left, bottom, right)); - view->AddChildView(item); - return view; -} - -// Helper function used by |CreateLabelView()| below that adds |labels| to -// |label_view|. -void AddLabelsToLabelView(views::View* label_view, - views::GridLayout* layout, - const std::vector<LabelInfo>& labels) { - static constexpr base::char16 kBulletPoint[] = {0x2022, 0}; - - bool first_label = true; - bool last_label_was_bullet = false; - for (const LabelInfo& label_info : labels) { - const bool is_bullet = label_info.type == LabelInfo::BULLET_ITEM; - views::Label* label = new views::Label(label_info.text); - label->SetMultiLine(true); - label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - - // Do not add a padding row if - // - this is the first label being added, or - // - a bullet item is being added and the last label was also a bullet item. - bool skip_padding = first_label || (is_bullet && last_label_was_bullet); - if (!skip_padding) - layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); - - layout->StartRow(0, is_bullet ? kBulletColumnSetId : kMainColumSetId); - if (is_bullet) { - views::Label* bullet = new views::Label(base::string16(kBulletPoint)); - layout->AddView(bullet); - } - layout->AddView(label); - - last_label_was_bullet = is_bullet; - first_label = false; - } -} - -// Creates a view that displays two types of labels: multiline labels -// representing whole paragraphs or indented labels that are start with a bullet -// point. -// -// A vertical padding of size |top_vertical_space| is added before the labels. -views::View* CreateLabelView(int top_vertical_space, - const std::vector<LabelInfo>& labels) { - views::View* label_view = new views::View(); - views::GridLayout* layout = new views::GridLayout(label_view); - layout->SetInsets(0, views::kButtonHEdgeMarginNew, 0, - views::kButtonHEdgeMarginNew); - - label_view->SetLayoutManager(layout); - - views::ColumnSet* main_column_set = layout->AddColumnSet(kMainColumSetId); - main_column_set->AddColumn(views::GridLayout::FILL, - views::GridLayout::LEADING, - /*resize_percent=*/1, views::GridLayout::USE_PREF, - /*fixed_width=*/0, - /*min_width=*/0); - - views::ColumnSet* bullet_column_set_ = - layout->AddColumnSet(kBulletColumnSetId); - bullet_column_set_->AddPaddingColumn( - /*resize_percent=*/0, views::kUnrelatedControlLargeHorizontalSpacing); - bullet_column_set_->AddColumn( - views::GridLayout::FILL, views::GridLayout::LEADING, - /*resize_percent=*/0, views::GridLayout::USE_PREF, - /*fixed_width=*/0, - /*min_width=*/0); - bullet_column_set_->AddPaddingColumn(/*resize_percent=*/0, - kBulletColumnWidth); - bullet_column_set_->AddColumn( - views::GridLayout::FILL, views::GridLayout::LEADING, - /*resize_percent=*/1, views::GridLayout::USE_PREF, - /*fixed_width=*/0, - /*min_width=*/0); - - if (top_vertical_space > 0) - layout->AddPaddingRow(/*vertical_resize=*/0, top_vertical_space); - - AddLabelsToLabelView(label_view, layout, labels); - - layout->AddPaddingRow(/*vertical_resize=*/0, - views::kUnrelatedControlLargeHorizontalSpacing); - return label_view; -} - } // namespace //////////////////////////////////////////////////////////////////////////////// -// SRTPromptDialog::ExpandableMessageView -// -// A view, whose visibilty can be toggled, and will be used for the details -// section the main dialog. -class SRTPromptDialog::ExpandableMessageView : public views::View { - public: - explicit ExpandableMessageView(const std::vector<LabelInfo>& labels); - ~ExpandableMessageView() override; - - void AnimateToState(double state); - - // views::View overrides. - gfx::Size GetPreferredSize() const override; - int GetHeightForWidth(int width) const override; - - private: - // A number between 0 and 1 that determines how much of the view's preferred - // height should be visible. - double animation_state_; - - DISALLOW_COPY_AND_ASSIGN(ExpandableMessageView); -}; - -SRTPromptDialog::ExpandableMessageView::ExpandableMessageView( - const std::vector<LabelInfo>& labels) - : animation_state_(0.0) { - // Add the main message view inside a scroll view. - views::View* label_view = - CreateLabelView(views::kUnrelatedControlLargeHorizontalSpacing, labels); - views::ScrollView* scroll_view = new views::ScrollView(); - scroll_view->ClipHeightTo(kDetailsSectionMaxHeight, kDetailsSectionMaxHeight); - scroll_view->SetContents(label_view); - scroll_view->SetSize(gfx::Size(kDialogWidth, kDetailsSectionMaxHeight)); - AddChildView(scroll_view); -} - -SRTPromptDialog::ExpandableMessageView::~ExpandableMessageView() {} - -void SRTPromptDialog::ExpandableMessageView::AnimateToState(double state) { - DCHECK_LE(0.0, state); - DCHECK_GE(1.0, state); - - animation_state_ = state; - PreferredSizeChanged(); -} - -gfx::Size SRTPromptDialog::ExpandableMessageView::GetPreferredSize() const { - return gfx::Size(kDialogWidth, kDetailsSectionMaxHeight * animation_state_); -} - -int SRTPromptDialog::ExpandableMessageView::GetHeightForWidth(int width) const { - return GetPreferredSize().height(); -} - -//////////////////////////////////////////////////////////////////////////////// // SRTPromptDialog SRTPromptDialog::SRTPromptDialog(safe_browsing::SRTPromptController* controller) : browser_(nullptr), controller_(controller), - slide_animation_(base::MakeUnique<gfx::SlideAnimation>(this)), - details_view_(new ExpandableMessageView(controller_->GetDetailsText())), - details_button_( - new views::LabelButton(this, controller_->GetShowDetailsLabel())) { + advanced_button_( + new views::LabelButton(this, controller_->GetAdvancedButtonLabel())) { DCHECK(controller_); SetLayoutManager(new views::BoxLayout( /*orientation=*/views::BoxLayout::kVertical, - /*inside_border_horizontal_spacing=*/0, + /*inside_border_horizontal_spacing=*/views::kButtonHEdgeMarginNew, /*inside_border_vertical_spacing=*/views::kPanelVertMargin, /*between_child_spacing=*/0)); + views::Label* label = new views::Label(controller_->GetMainText()); + label->SetMultiLine(true); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + AddChildView(label); - AddChildView(CreateLabelView(0, controller_->GetMainText())); - AddChildView(new views::Separator()); - - AddChildView(details_view_); - - details_button_->SetEnabledTextColors(GetDetailsButtonColor()); - UpdateDetailsButton(); - AddChildView(CreateViewWithInsets( - details_button_, views::kPanelVertMargin, views::kButtonHEdgeMarginNew, - views::kPanelVertMargin, views::kButtonHEdgeMarginNew)); - AddChildView(new views::Separator()); + advanced_button_->SetStyle(views::Button::STYLE_BUTTON); } SRTPromptDialog::~SRTPromptDialog() { @@ -282,9 +99,13 @@ DCHECK(button == ui::DIALOG_BUTTON_OK || button == ui::DIALOG_BUTTON_CANCEL); DCHECK(controller_); - if (button == ui::DIALOG_BUTTON_OK) - return controller_->GetAcceptButtonLabel(); - return DialogDelegate::GetDialogButtonLabel(button); + return button == ui::DIALOG_BUTTON_OK + ? controller_->GetAcceptButtonLabel() + : DialogDelegate::GetDialogButtonLabel(button); +} + +views::View* SRTPromptDialog::CreateExtraView() { + return advanced_button_; } bool SRTPromptDialog::Accept() { @@ -303,6 +124,14 @@ return true; } +bool SRTPromptDialog::Close() { + if (controller_) { + controller_->Close(); + controller_ = nullptr; + } + return true; +} + // View overrides. gfx::Size SRTPromptDialog::GetPreferredSize() const { @@ -313,42 +142,14 @@ void SRTPromptDialog::ButtonPressed(views::Button* sender, const ui::Event& event) { - DCHECK_EQ(sender, details_button_); + DCHECK_EQ(sender, advanced_button_); DCHECK(browser_); - if (slide_animation_->IsShowing()) - slide_animation_->Hide(); - else - slide_animation_->Show(); -} - -void SRTPromptDialog::AnimationProgressed(const gfx::Animation* animation) { - DCHECK_EQ(slide_animation_.get(), animation); - - details_view_->AnimateToState(animation->GetCurrentValue()); - ChromeWebModalDialogManagerDelegate* manager = browser_; - constrained_window::UpdateWidgetModalDialogPosition( - GetWidget(), manager->GetWebContentsModalDialogHost()); -} - -void SRTPromptDialog::AnimationEnded(const gfx::Animation* animation) { - DCHECK_EQ(slide_animation_.get(), animation); - UpdateDetailsButton(); -} - -SkColor SRTPromptDialog::GetDetailsButtonColor() { - return GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_LinkEnabled); -} - -void SRTPromptDialog::UpdateDetailsButton() { - DCHECK(controller_); - details_button_->SetText(slide_animation_->IsShowing() - ? controller_->GetHideDetailsLabel() - : controller_->GetShowDetailsLabel()); - details_button_->SetImage( - views::Button::STATE_NORMAL, - slide_animation_->IsShowing() - ? gfx::CreateVectorIcon(kCaretUpIcon, GetDetailsButtonColor()) - : gfx::CreateVectorIcon(kCaretDownIcon, GetDetailsButtonColor())); + // TODO(alito): Navigate to the webui version of the Chrome Cleaner UI when + // that is implemented. + if (controller_) { + controller_->AdvancedButtonClicked(); + controller_ = nullptr; + } + GetWidget()->Close(); }
diff --git a/chrome/browser/ui/views/srt_prompt_dialog.h b/chrome/browser/ui/views/srt_prompt_dialog.h index 59e1110e..c2d7a76e 100644 --- a/chrome/browser/ui/views/srt_prompt_dialog.h +++ b/chrome/browser/ui/views/srt_prompt_dialog.h
@@ -8,31 +8,18 @@ #include <memory> #include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/animation/animation_delegate.h" -#include "ui/gfx/image/image_skia.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/window/dialog_delegate.h" class Browser; -namespace gfx { -class SlideAnimation; -} - namespace safe_browsing { class SRTPromptController; } -// A modal dialog asking the user if they want to run the Chrome Cleanup -// tool. The dialog will have the following sections: -// -// 1. Main section with general information about unwanted software that has -// been found on the user's system. -// 2. Expandable details section with more details about unwanted software that -// will be removed and Chrome settings that will be reset. -// 3. Checkbox asking for permissions to upload logs (not yet implemented). +// A modal dialog asking the user if they want to remove harmful software from +// their computers by running the Chrome Cleanup tool. // // The strings and icons used in the dialog are provided by a // |SRTPromptController| object, which will also receive information about how @@ -41,8 +28,7 @@ // interaction with the dialog. See the |SRTPromptController| class's // description for more details. class SRTPromptDialog : public views::DialogDelegateView, - public views::ButtonListener, - public gfx::AnimationDelegate { + public views::ButtonListener { public: // The |controller| object manages its own lifetime and is not owned by // |SRTPromptDialog|. See the description of the |SRTPromptController| class @@ -61,8 +47,10 @@ // views::DialogDelegate overrides. base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; + views::View* CreateExtraView() override; bool Accept() override; bool Cancel() override; + bool Close() override; // views::View overrides. gfx::Size GetPreferredSize() const override; @@ -70,24 +58,13 @@ // views::ButtonListener overrides. void ButtonPressed(views::Button* sender, const ui::Event& event) override; - // gfx::AnimationDelegate overrides. - void AnimationProgressed(const gfx::Animation* animation) override; - void AnimationEnded(const gfx::Animation* animation) override; - private: - class ExpandableMessageView; - - SkColor GetDetailsButtonColor(); - void UpdateDetailsButton(); - Browser* browser_; // The pointer will be set to nullptr once the controller has been notified of // user interaction since the controller can delete itself after that point. safe_browsing::SRTPromptController* controller_; - std::unique_ptr<gfx::SlideAnimation> slide_animation_; - ExpandableMessageView* details_view_; - views::LabelButton* details_button_; + views::LabelButton* advanced_button_; DISALLOW_COPY_AND_ASSIGN(SRTPromptDialog); };
diff --git a/chrome/browser/ui/webui/help/help_handler.cc b/chrome/browser/ui/webui/help/help_handler.cc index 3cb5e47..aeacd09 100644 --- a/chrome/browser/ui/webui/help/help_handler.cc +++ b/chrome/browser/ui/webui/help/help_handler.cc
@@ -538,7 +538,8 @@ DCHECK(args->empty()); Browser* browser = chrome::FindBrowserWithWebContents( web_ui()->GetWebContents()); - chrome::OpenFeedbackDialog(browser); + chrome::OpenFeedbackDialog(browser, + chrome::kFeedbackSourceOldSettingsAboutPage); } void HelpHandler::OpenHelpPage(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc index a4ff8df..e91c922 100644 --- a/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -440,7 +440,8 @@ DCHECK(args->empty()); Browser* browser = chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()); - chrome::OpenFeedbackDialog(browser); + chrome::OpenFeedbackDialog(browser, + chrome::kFeedbackSourceMdSettingsAboutPage); } void AboutHandler::HandleOpenHelpPage(const base::ListValue* args) {
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index 82d9367..09c7441 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -68,6 +68,7 @@ "chrome_content_client.cc", "chrome_content_client.h", "chrome_content_client_constants.cc", + "chrome_isolated_world_ids.h", "chrome_result_codes.h", "chrome_utility_messages.h", "common_message_generator.cc", @@ -118,6 +119,7 @@ "pause_tabs_field_trial.h", "pref_names_util.cc", "pref_names_util.h", + "prerender_messages.h", "prerender_types.h", "profiling.cc", "profiling.h", @@ -245,6 +247,7 @@ sources += [ "cast_messages.cc", "cast_messages.h", + "extensions/api/automation_api_constants.h", "extensions/api/commands/commands_handler.cc", "extensions/api/commands/commands_handler.h", "extensions/api/extension_action/action_info.cc", @@ -435,6 +438,7 @@ "importer/profile_import_process_param_traits.cc", "importer/profile_import_process_param_traits.h", "importer/profile_import_process_param_traits_macros.h", + "importer/pstore_declarations.h", "importer/safari_importer_utils.h", "importer/safari_importer_utils.mm", ]
diff --git a/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js b/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js index 69dde01..f39c1ee 100644 --- a/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js +++ b/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js
@@ -81,6 +81,21 @@ }; chrome.networkingPrivate.onPortalDetectionCompleted.addListener( self.onPortalDetectionCompleted); + }, + verifyTetherNetwork: function( + properties, expectedGuid, expectedName, expectedBatteryPercentage, + expectedCarrier, expectedSignalStrength) { + //assertEq(NetworkType.Tether, properties.Type); + assertEq(expectedGuid, properties.GUID); + assertEq(expectedName, + properties.Name.hasOwnProperty('Active') ? properties.Name.Active + : properties.Name); + assertEq(expectedBatteryPercentage, properties.Tether.BatteryPercentage); + assertEq(expectedCarrier, properties.Tether.Carrier); + // TODO(khorimoto): Add the expected value as a parameter once it can be set + // via the Tether component. + assertFalse(properties.Tether.HasConnectedToHost); + assertEq(expectedSignalStrength, properties.Tether.SignalStrength); } }; @@ -923,6 +938,41 @@ }, result); })); }, + function getTetherNetworks() { + chrome.networkingPrivate.getNetworks( + {networkType: 'Tether'}, + callbackPass(function(tetherNetworks) { + assertEq(2, tetherNetworks.length); + privateHelpers.verifyTetherNetwork(tetherNetworks[0], 'tetherGuid1', + 'tetherName1', 50, 'tetherCarrier1', 75); + privateHelpers.verifyTetherNetwork(tetherNetworks[1], 'tetherGuid2', + 'tetherName2', 75, 'tetherCarrier2', 100); + })); + }, + function getTetherNetworkProperties() { + chrome.networkingPrivate.getProperties( + 'tetherGuid1', + callbackPass(function(tetherNetwork) { + privateHelpers.verifyTetherNetwork(tetherNetwork, 'tetherGuid1', + 'tetherName1', 50, 'tetherCarrier1', 75); + })); + }, + function getTetherNetworkManagedProperties() { + chrome.networkingPrivate.getManagedProperties( + 'tetherGuid1', + callbackPass(function(tetherNetwork) { + privateHelpers.verifyTetherNetwork(tetherNetwork, 'tetherGuid1', + 'tetherName1', 50, 'tetherCarrier1', 75); + })); + }, + function getTetherNetworkState() { + chrome.networkingPrivate.getState( + 'tetherGuid1', + callbackPass(function(tetherNetwork) { + privateHelpers.verifyTetherNetwork(tetherNetwork, 'tetherGuid1', + 'tetherName1', 50, 'tetherCarrier1', 75); + })); + }, ]; chrome.test.getConfig(function(config) {
diff --git a/chrome/test/data/payments/payment_request_id.js b/chrome/test/data/payments/payment_request_id.js new file mode 100644 index 0000000..abfda37a --- /dev/null +++ b/chrome/test/data/payments/payment_request_id.js
@@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * Launches the PaymentRequest UI including a details.id and prints the + * resulting requestId. + */ +function buy() { // eslint-disable-line no-unused-vars + try { + new PaymentRequest( + [{supportedMethods: ['visa']}], + {id: 'my_payment_id', + total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}}) + .show() + .then(function(resp) { + resp.complete('success') + .then(function() { + print(resp.requestId); + }) + .catch(function(error) { + print(error.message); + }); + }) + .catch(function(error) { + print(error.message); + }); + } catch (error) { + print(error.message); + } +}
diff --git a/chrome/test/data/payments/payment_request_id_test.html b/chrome/test/data/payments/payment_request_id_test.html new file mode 100644 index 0000000..922c9d0 --- /dev/null +++ b/chrome/test/data/payments/payment_request_id_test.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html> +<head> +<title>Payment Request Id Test</title> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> +<link rel="stylesheet" type="text/css" href="style.css"> +</head> +<body> +<button onclick="buy()" id="buy">Payment Request Id Test</button> +<pre id="result"></pre> +<script src="util.js"></script> +<script src="payment_request_id.js"></script> +</body> +</html>
diff --git a/chromecast/media/cdm/cast_cdm.cc b/chromecast/media/cdm/cast_cdm.cc index 1f49273..59cb523 100644 --- a/chromecast/media/cdm/cast_cdm.cc +++ b/chromecast/media/cdm/cast_cdm.cc
@@ -132,6 +132,11 @@ player_tracker_impl_->NotifyNewKey(); } +void CastCdm::OnSessionExpirationUpdate(const std::string& session_id, + base::Time new_expiry_time) { + session_expiration_update_cb_.Run(session_id, new_expiry_time); +} + void CastCdm::KeyIdAndKeyPairsToInfo(const ::media::KeyIdAndKeyPairs& keys, ::media::CdmKeysInfo* keys_info) { DCHECK(keys_info);
diff --git a/chromecast/media/cdm/cast_cdm.h b/chromecast/media/cdm/cast_cdm.h index 6ceefd81..004cd63 100644 --- a/chromecast/media/cdm/cast_cdm.h +++ b/chromecast/media/cdm/cast_cdm.h
@@ -16,6 +16,7 @@ #include "base/memory/ref_counted.h" #include "base/sequenced_task_runner_helpers.h" #include "base/threading/thread_checker.h" +#include "base/time/time.h" #include "chromecast/media/base/media_resource_tracker.h" #include "chromecast/media/cdm/cast_cdm_context.h" #include "chromecast/public/media/cast_key_status.h" @@ -82,6 +83,8 @@ void OnSessionKeysChange(const std::string& session_id, bool newly_usable_keys, ::media::CdmKeysInfo keys_info); + void OnSessionExpirationUpdate(const std::string& session_id, + base::Time new_expiry_time); void KeyIdAndKeyPairsToInfo(const ::media::KeyIdAndKeyPairs& keys, ::media::CdmKeysInfo* key_info);
diff --git a/chromeos/network/network_configuration_handler_unittest.cc b/chromeos/network/network_configuration_handler_unittest.cc index bfe3471..d07215f 100644 --- a/chromeos/network/network_configuration_handler_unittest.cc +++ b/chromeos/network/network_configuration_handler_unittest.cc
@@ -366,6 +366,9 @@ NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED); std::string kTetherGuid = "TetherGuid"; + // TODO(khorimoto): Pass a has_connected_to_host parameter to this function + // and verify that it is present in the JSON below. Currently, it is hard- + // coded to false. network_state_handler_->AddTetherNetworkState( kTetherGuid, "TetherNetworkName", "TetherNetworkCarrier", 100 /* battery_percentage */, 100 /* signal_strength */); @@ -380,6 +383,7 @@ "\"State\": \"\",\n " "\"Tether.BatteryPercentage\": 100,\n " "\"Tether.Carrier\": \"TetherNetworkCarrier\",\n " + "\"Tether.HasConnectedToHost\": false,\n " "\"Tether.SignalStrength\": 100,\n " "\"Type\": \"wifi-tether\"\n" "}\n";
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc index 838faa0..5577518 100644 --- a/chromeos/network/network_state.cc +++ b/chromeos/network/network_state.cc
@@ -267,6 +267,8 @@ dictionary->SetIntegerWithoutPathExpansion(kTetherBatteryPercentage, battery_percentage()); dictionary->SetStringWithoutPathExpansion(kTetherCarrier, carrier()); + dictionary->SetBooleanWithoutPathExpansion(kTetherHasConnectedToHost, + tether_has_connected_to_host()); dictionary->SetIntegerWithoutPathExpansion(kTetherSignalStrength, signal_strength()); }
diff --git a/chromeos/network/network_state.h b/chromeos/network/network_state.h index 995207d3..d43c562 100644 --- a/chromeos/network/network_state.h +++ b/chromeos/network/network_state.h
@@ -114,6 +114,12 @@ } const std::string& carrier() const { return carrier_; } void set_carrier(const std::string& carrier) { carrier_ = carrier; } + bool tether_has_connected_to_host() const { + return tether_has_connected_to_host_; + } + void set_tether_has_connected_to_host(bool tether_has_connected_to_host) { + tether_has_connected_to_host_ = tether_has_connected_to_host; + } const std::string& tether_guid() const { return tether_guid_; } void set_tether_guid(const std::string& guid) { tether_guid_ = guid; } @@ -229,6 +235,12 @@ // Tether properties. std::string carrier_; int battery_percentage_; + // Whether the current device has already connected to the tether host device + // providing the hotspot corresponding to this NetworkState. + // Note: this means that the current device has already connected to the + // tether host, but it does not necessarily mean that the current device has + // connected to the Tether network corresponding to this NetworkState. + bool tether_has_connected_to_host_; // TODO(pneubeck): Remove this once (Managed)NetworkConfigurationHandler // provides proxy configuration. crbug.com/241775
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc index 6aeacbe..09c70fc 100644 --- a/chromeos/network/network_state_handler.cc +++ b/chromeos/network/network_state_handler.cc
@@ -476,8 +476,11 @@ bool configured_only) const { ManagedState* managed = GetModifiableManagedState(&network_list_, service_path); - if (!managed) - return nullptr; + if (!managed) { + managed = GetModifiableManagedState(&tether_network_list_, service_path); + if (!managed) + return nullptr; + } const NetworkState* network = managed->AsNetworkState(); DCHECK(network); if (!network->update_received() || @@ -528,6 +531,9 @@ tether_network_state->set_connectable(true); tether_network_state->set_carrier(carrier); tether_network_state->set_battery_percentage(battery_percentage); + // TODO(khorimoto): Add this field as a parameter to this function and set it + // accordingly from the Tether component. + tether_network_state->set_tether_has_connected_to_host(false); tether_network_state->set_signal_strength(signal_strength); tether_network_list_.push_back(std::move(tether_network_state));
diff --git a/chromeos/network/network_state_unittest.cc b/chromeos/network/network_state_unittest.cc index e151c96..5cd7489 100644 --- a/chromeos/network/network_state_unittest.cc +++ b/chromeos/network/network_state_unittest.cc
@@ -262,6 +262,7 @@ network_state_.set_type(kTypeTether); network_state_.set_carrier("Project Fi"); network_state_.set_battery_percentage(85); + network_state_.set_tether_has_connected_to_host(true); network_state_.set_signal_strength(75); base::DictionaryValue dictionary; @@ -277,6 +278,11 @@ kTetherBatteryPercentage, &battery_percentage)); EXPECT_EQ(85, battery_percentage); + bool tether_has_connected_to_host; + EXPECT_TRUE(dictionary.GetBooleanWithoutPathExpansion( + kTetherHasConnectedToHost, &tether_has_connected_to_host)); + EXPECT_TRUE(tether_has_connected_to_host); + std::string carrier; EXPECT_TRUE( dictionary.GetStringWithoutPathExpansion(kTetherCarrier, &carrier));
diff --git a/chromeos/network/onc/onc_signature.cc b/chromeos/network/onc/onc_signature.cc index 78abfb2..58afa58 100644 --- a/chromeos/network/onc/onc_signature.cc +++ b/chromeos/network/onc/onc_signature.cc
@@ -167,9 +167,12 @@ {::onc::ethernet::kEAP, &kEAPSignature}, {NULL}}; -const OncFieldSignature tether_fields[] = { +const OncFieldSignature tether_fields[] = {{NULL}}; + +const OncFieldSignature tether_with_state_fields[] = { {::onc::tether::kBatteryPercentage, &kIntegerSignature}, {::onc::tether::kCarrier, &kStringSignature}, + {::onc::tether::kHasConnectedToHost, &kBoolSignature}, {::onc::tether::kSignalStrength, &kIntegerSignature}, {NULL}}; @@ -336,7 +339,7 @@ {::onc::network_config::kRestrictedConnectivity, &kBoolSignature}, {::onc::network_config::kSavedIPConfig, &kSavedIPConfigSignature}, {::onc::network_config::kSource, &kStringSignature}, - {::onc::network_config::kTether, &kTetherSignature}, + {::onc::network_config::kTether, &kTetherWithStateSignature}, {::onc::network_config::kWiFi, &kWiFiWithStateSignature}, {::onc::network_config::kWimax, &kWiMAXWithStateSignature}, {NULL}}; @@ -401,8 +404,6 @@ vpn_fields, NULL}; const OncValueSignature kEthernetSignature = {base::Value::Type::DICTIONARY, ethernet_fields, NULL}; -const OncValueSignature kTetherSignature = {base::Value::Type::DICTIONARY, - tether_fields, NULL}; const OncValueSignature kIPConfigSignature = {base::Value::Type::DICTIONARY, ipconfig_fields, NULL}; const OncValueSignature kSavedIPConfigSignature = { @@ -439,6 +440,11 @@ const OncValueSignature kWiFiWithStateSignature = { base::Value::Type::DICTIONARY, wifi_with_state_fields, NULL, &kWiFiSignature}; +const OncValueSignature kTetherSignature = {base::Value::Type::DICTIONARY, + tether_fields, NULL}; +const OncValueSignature kTetherWithStateSignature = { + base::Value::Type::DICTIONARY, tether_with_state_fields, NULL, + &kTetherSignature}; const OncValueSignature kWiMAXWithStateSignature = { base::Value::Type::DICTIONARY, wimax_with_state_fields, NULL, &kWiMAXSignature};
diff --git a/chromeos/network/onc/onc_signature.h b/chromeos/network/onc/onc_signature.h index ebc8778..9b7a732 100644 --- a/chromeos/network/onc/onc_signature.h +++ b/chromeos/network/onc/onc_signature.h
@@ -47,6 +47,7 @@ CHROMEOS_EXPORT extern const OncValueSignature kVPNSignature; CHROMEOS_EXPORT extern const OncValueSignature kEthernetSignature; CHROMEOS_EXPORT extern const OncValueSignature kTetherSignature; +CHROMEOS_EXPORT extern const OncValueSignature kTetherWithStateSignature; CHROMEOS_EXPORT extern const OncValueSignature kIPConfigSignature; CHROMEOS_EXPORT extern const OncValueSignature kSavedIPConfigSignature; CHROMEOS_EXPORT extern const OncValueSignature kStaticIPConfigSignature;
diff --git a/chromeos/network/onc/onc_translation_tables.cc b/chromeos/network/onc/onc_translation_tables.cc index 51fa269c..217a4de 100644 --- a/chromeos/network/onc/onc_translation_tables.cc +++ b/chromeos/network/onc/onc_translation_tables.cc
@@ -114,6 +114,7 @@ const FieldTranslationEntry tether_fields[] = { {::onc::tether::kBatteryPercentage, kTetherBatteryPercentage}, {::onc::tether::kCarrier, kTetherCarrier}, + {::onc::tether::kHasConnectedToHost, kTetherHasConnectedToHost}, {::onc::tether::kSignalStrength, kTetherSignalStrength}, {NULL}}; @@ -248,6 +249,7 @@ {&kVerifyX509Signature, verify_x509_fields}, {&kVPNSignature, vpn_fields}, {&kTetherSignature, tether_fields}, + {&kTetherWithStateSignature, tether_fields}, {&kWiFiSignature, wifi_fields}, {&kWiFiWithStateSignature, wifi_fields}, {&kWiMAXSignature, wimax_fields},
diff --git a/chromeos/network/onc/onc_validator.cc b/chromeos/network/onc/onc_validator.cc index 5842134e..cd83e3f4 100644 --- a/chromeos/network/onc/onc_validator.cc +++ b/chromeos/network/onc/onc_validator.cc
@@ -129,7 +129,7 @@ valid = ValidateEAP(repaired.get()); } else if (&signature == &kCertificateSignature) { valid = ValidateCertificate(repaired.get()); - } else if (&signature == &kTetherSignature) { + } else if (&signature == &kTetherWithStateSignature) { valid = ValidateTether(repaired.get()); } } @@ -1008,19 +1008,19 @@ bool Validator::ValidateTether(base::DictionaryValue* result) { using namespace ::onc::tether; - int batteryPercentage; + int battery_percentage; if (!result->GetIntegerWithoutPathExpansion(kBatteryPercentage, - &batteryPercentage) || - batteryPercentage < 0 || batteryPercentage > 100) { + &battery_percentage) || + battery_percentage < 0 || battery_percentage > 100) { // Battery percentage must be present and within [0, 100]. error_or_warning_found_ = true; return false; } - int signalStrength; + int signal_strength; if (!result->GetIntegerWithoutPathExpansion(kSignalStrength, - &signalStrength) || - signalStrength < 0 || signalStrength > 100) { + &signal_strength) || + signal_strength < 0 || signal_strength > 100) { // Signal strength must be present and within [0, 100]. error_or_warning_found_ = true; return false; @@ -1034,8 +1034,12 @@ return false; } - // No required fields. - return true; + bool all_required_exist = RequireField(*result, kHasConnectedToHost); + if (!all_required_exist) { + error_or_warning_found_ = true; + } + + return !error_on_missing_field_ || all_required_exist; } std::string Validator::MessageHeader() {
diff --git a/chromeos/network/onc/onc_validator_unittest.cc b/chromeos/network/onc/onc_validator_unittest.cc index 4102a0c..917dffa 100644 --- a/chromeos/network/onc/onc_validator_unittest.cc +++ b/chromeos/network/onc/onc_validator_unittest.cc
@@ -564,6 +564,10 @@ &kNetworkWithStateSignature, true), ExpectBothNotValid("", "")), + std::make_pair(OncParams("tether-missing-has-connected-to-host", + &kNetworkWithStateSignature, + true), + ExpectBothNotValid("", "")), std::make_pair(OncParams("tether-missing-signal-strength", &kNetworkWithStateSignature, true),
diff --git a/chromeos/network/tether_constants.cc b/chromeos/network/tether_constants.cc index 72fd96b..1a80364e7 100644 --- a/chromeos/network/tether_constants.cc +++ b/chromeos/network/tether_constants.cc
@@ -9,6 +9,7 @@ const char kTypeTether[] = "wifi-tether"; const char kTetherBatteryPercentage[] = "Tether.BatteryPercentage"; const char kTetherCarrier[] = "Tether.Carrier"; +const char kTetherHasConnectedToHost[] = "Tether.HasConnectedToHost"; const char kTetherSignalStrength[] = "Tether.SignalStrength"; const char kTetherDevicePath[] = "tether-device-path"; const char kTetherDeviceName[] = "tether-name";
diff --git a/chromeos/network/tether_constants.h b/chromeos/network/tether_constants.h index 4d73d1d..fb2fa60 100644 --- a/chromeos/network/tether_constants.h +++ b/chromeos/network/tether_constants.h
@@ -20,6 +20,7 @@ // Properties associated with tether networks. CHROMEOS_EXPORT extern const char kTetherBatteryPercentage[]; CHROMEOS_EXPORT extern const char kTetherCarrier[]; +CHROMEOS_EXPORT extern const char kTetherHasConnectedToHost[]; CHROMEOS_EXPORT extern const char kTetherSignalStrength[]; // The device path used for the tether DeviceState.
diff --git a/chromeos/test/data/network/invalid_settings_with_repairs.json b/chromeos/test/data/network/invalid_settings_with_repairs.json index c6e0e5c0..f7d9b6c 100644 --- a/chromeos/test/data/network/invalid_settings_with_repairs.json +++ b/chromeos/test/data/network/invalid_settings_with_repairs.json
@@ -383,6 +383,7 @@ "Type": "Tether", "Tether": { "Carrier": "Project Fi", + "HasConnectedToHost": true, "SignalStrength": 75 } }, @@ -393,6 +394,7 @@ "Tether": { "BatteryPercentage": -1, "Carrier": "Project Fi", + "HasConnectedToHost": true, "SignalStrength": 75 } }, @@ -403,6 +405,7 @@ "Tether": { "BatteryPercentage": 101, "Carrier": "Project Fi", + "HasConnectedToHost": true, "SignalStrength": 75 } }, @@ -412,16 +415,28 @@ "Type": "Tether", "Tether": { "BatteryPercentage": 85, + "HasConnectedToHost": true, "SignalStrength": 75 } }, + "tether-missing-has-connected-to-host": { + "GUID": "guid", + "Name": "name", + "Type": "Tether", + "Tether": { + "BatteryPercentage": 85, + "Carrier": "Project Fi", + "SignalStrength": 101 + } + }, "tether-missing-signal-strength": { "GUID": "guid", "Name": "name", "Type": "Tether", "Tether": { "BatteryPercentage": 85, - "Carrier": "Project Fi" + "Carrier": "Project Fi", + "HasConnectedToHost": true, } }, "tether-negative-signal-strength": { @@ -431,6 +446,7 @@ "Tether": { "BatteryPercentage": 85, "Carrier": "Project Fi", + "HasConnectedToHost": true, "SignalStrength": -1 } }, @@ -441,6 +457,7 @@ "Tether": { "BatteryPercentage": 85, "Carrier": "Project Fi", + "HasConnectedToHost": true, "SignalStrength": 101 } },
diff --git a/chromeos/test/data/network/shill_tether.json b/chromeos/test/data/network/shill_tether.json index 2f7e18e..f22e879 100644 --- a/chromeos/test/data/network/shill_tether.json +++ b/chromeos/test/data/network/shill_tether.json
@@ -3,5 +3,6 @@ "Name": "Tether Network", "Tether.BatteryPercentage": 85, "Tether.Carrier": "Project Fi", + "Tether.HasConnectedToHost": true, "Tether.SignalStrength": 75 }
diff --git a/chromeos/test/data/network/tether.onc b/chromeos/test/data/network/tether.onc index 02970b1..3d63154 100644 --- a/chromeos/test/data/network/tether.onc +++ b/chromeos/test/data/network/tether.onc
@@ -4,6 +4,7 @@ "Tether": { "BatteryPercentage": 85, "Carrier": "Project Fi", + "HasConnectedToHost": true, "SignalStrength": 75 } }
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index 6921626..62b31f2 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc
@@ -284,6 +284,9 @@ registry->RegisterBooleanPref(prefs::kAutofillWalletImportEnabled, true); registry->RegisterBooleanPref( prefs::kAutofillWalletImportStorageCheckboxState, true); + registry->RegisterIntegerPref( + prefs::kAutofillAcceptSaveCreditCardPromptState, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE); } void AutofillManager::SetExternalDelegate(AutofillExternalDelegate* delegate) {
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc index 7744239..5e04434 100644 --- a/components/autofill/core/browser/autofill_metrics.cc +++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -80,6 +80,23 @@ NUM_FIELD_TYPE_GROUPS_FOR_METRICS }; +std::string PreviousSaveCreditCardPromptUserDecisionToString( + int previous_save_credit_card_prompt_user_decision) { + DCHECK_LT(previous_save_credit_card_prompt_user_decision, + prefs::NUM_PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISIONS); + std::string previous_response; + if (previous_save_credit_card_prompt_user_decision == + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED) + previous_response = ".PreviouslyAccepted"; + else if (previous_save_credit_card_prompt_user_decision == + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED) + previous_response = ".PreviouslyDenied"; + else + DCHECK_EQ(previous_save_credit_card_prompt_user_decision, + prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE); + return previous_response; +} + } // namespace // First, translates |field_type| to the corresponding logical |group| from @@ -298,16 +315,18 @@ } // static -void AutofillMetrics::LogCreditCardInfoBarMetric(InfoBarMetric metric, - bool is_uploading) { +void AutofillMetrics::LogCreditCardInfoBarMetric( + InfoBarMetric metric, + bool is_uploading, + int previous_save_credit_card_prompt_user_decision) { DCHECK_LT(metric, NUM_INFO_BAR_METRICS); - if (is_uploading) { - UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar.Server", metric, - NUM_INFO_BAR_METRICS); - } else { - UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar.Local", metric, - NUM_INFO_BAR_METRICS); - } + + std::string destination = is_uploading ? ".Server" : ".Local"; + LogUMAHistogramEnumeration( + "Autofill.CreditCardInfoBar" + destination + + PreviousSaveCreditCardPromptUserDecisionToString( + previous_save_credit_card_prompt_user_decision), + metric, NUM_INFO_BAR_METRICS); } // static @@ -318,15 +337,19 @@ } // static -void AutofillMetrics::LogSaveCardPromptMetric(SaveCardPromptMetric metric, - bool is_uploading, - bool is_reshow) { +void AutofillMetrics::LogSaveCardPromptMetric( + SaveCardPromptMetric metric, + bool is_uploading, + bool is_reshow, + int previous_save_credit_card_prompt_user_decision) { DCHECK_LT(metric, NUM_SAVE_CARD_PROMPT_METRICS); std::string destination = is_uploading ? ".Upload" : ".Local"; std::string show = is_reshow ? ".Reshows" : ".FirstShow"; LogUMAHistogramEnumeration( - "Autofill.SaveCreditCardPrompt" + destination + show, metric, - NUM_SAVE_CARD_PROMPT_METRICS); + "Autofill.SaveCreditCardPrompt" + destination + show + + PreviousSaveCreditCardPromptUserDecisionToString( + previous_save_credit_card_prompt_user_decision), + metric, NUM_SAVE_CARD_PROMPT_METRICS); } // static
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h index 58ab8d2..ac50c90 100644 --- a/components/autofill/core/browser/autofill_metrics.h +++ b/components/autofill/core/browser/autofill_metrics.h
@@ -16,6 +16,7 @@ #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/common/autofill_pref_names.h" #include "components/autofill/core/common/form_field_data.h" namespace ukm { @@ -645,12 +646,16 @@ }; static void LogCardUploadDecisionMetric(CardUploadDecisionMetric metric); - static void LogCreditCardInfoBarMetric(InfoBarMetric metric, - bool is_uploading); + static void LogCreditCardInfoBarMetric( + InfoBarMetric metric, + bool is_uploading, + int previous_save_credit_card_prompt_user_decision); static void LogCreditCardFillingInfoBarMetric(InfoBarMetric metric); - static void LogSaveCardPromptMetric(SaveCardPromptMetric metric, - bool is_uploading, - bool is_reshow); + static void LogSaveCardPromptMetric( + SaveCardPromptMetric metric, + bool is_uploading, + bool is_reshow, + int previous_save_credit_card_prompt_user_decision); static void LogScanCreditCardPromptMetric(ScanCreditCardPromptMetric metric); // Should be called when credit card scan is finished. |duration| should be
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc index 28f7aea..85060ad 100644 --- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc +++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -11,9 +11,11 @@ #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/legal_message_line.h" #include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_pref_names.h" #include "components/grit/components_scaled_resources.h" #include "components/infobars/core/infobar.h" #include "components/infobars/core/infobar_manager.h" +#include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/window_open_disposition.h" @@ -25,10 +27,12 @@ bool upload, const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, - const base::Closure& save_card_callback) + const base::Closure& save_card_callback, + PrefService* pref_service) : ConfirmInfoBarDelegate(), upload_(upload), save_card_callback_(save_card_callback), + pref_service_(pref_service), had_user_interaction_(false), #if defined(OS_IOS) // TODO(jdonnelly): Use credit card issuer images on iOS. @@ -42,8 +46,10 @@ if (legal_message) LegalMessageLine::Parse(*legal_message, &legal_messages_); - AutofillMetrics::LogCreditCardInfoBarMetric(AutofillMetrics::INFOBAR_SHOWN, - upload_); + AutofillMetrics::LogCreditCardInfoBarMetric( + AutofillMetrics::INFOBAR_SHOWN, upload_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); } AutofillSaveCardInfoBarDelegateMobile:: @@ -120,7 +126,15 @@ AutofillMetrics::InfoBarMetric user_action) { DCHECK(!had_user_interaction_); - AutofillMetrics::LogCreditCardInfoBarMetric(user_action, upload_); + AutofillMetrics::LogCreditCardInfoBarMetric( + user_action, upload_, + pref_service_->GetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState)); + pref_service_->SetInteger( + prefs::kAutofillAcceptSaveCreditCardPromptState, + user_action == AutofillMetrics::INFOBAR_ACCEPTED + ? prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED + : prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED); had_user_interaction_ = true; }
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h index d507696..d1a0d229 100644 --- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h +++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
@@ -14,6 +14,8 @@ #include "components/autofill/core/browser/legal_message_line.h" #include "components/infobars/core/confirm_infobar_delegate.h" +class PrefService; + namespace base { class DictionaryValue; } @@ -30,7 +32,8 @@ bool upload, const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, - const base::Closure& save_card_callback); + const base::Closure& save_card_callback, + PrefService* pref_service); ~AutofillSaveCardInfoBarDelegateMobile() override; @@ -64,6 +67,9 @@ // The callback to save credit card if the user accepts the infobar. base::Closure save_card_callback_; + // Weak reference to read & write |kAutofillAcceptSaveCreditCardPromptState|, + PrefService* pref_service_; + // Did the user ever explicitly accept or dismiss this infobar? bool had_user_interaction_;
diff --git a/components/autofill/core/common/autofill_pref_names.cc b/components/autofill/core/common/autofill_pref_names.cc index 1dc5b59..4f3b11dc 100644 --- a/components/autofill/core/common/autofill_pref_names.cc +++ b/components/autofill/core/common/autofill_pref_names.cc
@@ -26,10 +26,17 @@ // was run. This routine will be run once per version. const char kAutofillLastVersionDeduped[] = "autofill.last_version_deduped"; -// Boolean that allows the "Don't ask again for this card" checkbox to be -// sticky. +// Boolean that is set to the last choice user made when prompted for saving an +// unmasked server card locally. const char kAutofillWalletImportStorageCheckboxState[] = "autofill.wallet_import_storage_checkbox_state"; +// Integer that is set to the last choice user made when prompted for saving a +// credit card. The prompt is for user's consent in saving the card in the +// server for signed in users and saving the card locally for non signed-in +// users. +const char kAutofillAcceptSaveCreditCardPromptState[] = + "autofill.accept_save_credit_card_prompt_state"; + } // namespace prefs } // namespace autofill
diff --git a/components/autofill/core/common/autofill_pref_names.h b/components/autofill/core/common/autofill_pref_names.h index cab272d..e18a77a 100644 --- a/components/autofill/core/common/autofill_pref_names.h +++ b/components/autofill/core/common/autofill_pref_names.h
@@ -11,6 +11,7 @@ // Alphabetical list of preference names specific to the Autofill // component. Keep alphabetized, and document each in the .cc file. +extern const char kAutofillAcceptSaveCreditCardPromptState[]; extern const char kAutofillCreditCardSigninPromoImpressionCount[]; extern const char kAutofillEnabled[]; extern const char kAutofillProfileUseDatesFixed[]; @@ -18,6 +19,15 @@ extern const char kAutofillWalletImportEnabled[]; extern const char kAutofillWalletImportStorageCheckboxState[]; +// Possible values for previous user decision when we displayed a save credit +// card prompt. +enum PreviousSaveCreditCardPromptUserDecision { + PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE, + PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_ACCEPTED, + PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_DENIED, + NUM_PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISIONS +}; + } // namespace prefs } // namespace autofill
diff --git a/components/chrome_cleaner/public/interfaces/BUILD.gn b/components/chrome_cleaner/public/interfaces/BUILD.gn index 039f122..16089838 100644 --- a/components/chrome_cleaner/public/interfaces/BUILD.gn +++ b/components/chrome_cleaner/public/interfaces/BUILD.gn
@@ -8,4 +8,7 @@ sources = [ "chrome_prompt.mojom", ] + deps = [ + "//mojo/common:common_custom_types", + ] }
diff --git a/components/chrome_cleaner/public/interfaces/chrome_prompt.mojom b/components/chrome_cleaner/public/interfaces/chrome_prompt.mojom index 7458a8e..b10a3a1 100644 --- a/components/chrome_cleaner/public/interfaces/chrome_prompt.mojom +++ b/components/chrome_cleaner/public/interfaces/chrome_prompt.mojom
@@ -4,6 +4,8 @@ module chrome_cleaner.mojom; +import "mojo/common/file_path.mojom"; + // The behaviours that have been observed for a given UwS. struct ObservedBehaviours { bool ad_injector; @@ -27,7 +29,7 @@ // List of fully-qualified paths of the files that will be deleted by the // Chrome Cleanup Tool for this unwanted software. - array<string> files_to_delete; + array<mojo.common.mojom.FilePath> files_to_delete; }; // Indicates if elevation will be required for cleanup.
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index b51708c0c..6af3c08 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn
@@ -587,7 +587,6 @@ "//base:base_java", "//base:base_java_test_support", "//net/android:net_java_test_support", - "//third_party/netty-tcnative:netty-tcnative_java", "//third_party/netty4:netty_all_java", ] @@ -1024,7 +1023,6 @@ "$root_out_dir/lib.java/components/cronet/android/cronet_test_apk_java.jar", "$root_out_dir/lib.java/net/android/net_java.jar", "$root_out_dir/lib.java/net/android/net_java_test_support.jar", - "$root_out_dir/lib.java/third_party/netty-tcnative/netty-tcnative_java.jar", "$root_out_dir/lib.java/url/url_java.jar", NETTY4_JAR_FILE, ] @@ -1053,7 +1051,6 @@ "//base:base_java_test_support", "//net/android:net_java", "//net/android:net_java_test_support", - "//third_party/netty-tcnative:netty-tcnative_java", "//third_party/netty4:netty_all_java", "//url:url_java", ]
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java index b9811038..ae4e008 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
@@ -46,7 +46,7 @@ mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, builder); assertTrue(Http2TestServer.startHttp2TestServer( - getContext(), QuicTestServer.getServerCert(), QuicTestServer.getServerCertKey())); + getContext(), SERVER_CERT_PEM, SERVER_KEY_PKCS8_PEM)); } @Override
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java index b23e4da5..7a06ae7 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java
@@ -20,7 +20,7 @@ // Load library first to create MockCertVerifier. System.loadLibrary("cronet_tests"); assertTrue(Http2TestServer.startHttp2TestServer( - getContext(), QuicTestServer.getServerCert(), QuicTestServer.getServerCertKey())); + getContext(), SERVER_CERT_PEM, SERVER_KEY_PKCS8_PEM)); } @Override
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java index bf932bd..4c34173 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java
@@ -24,6 +24,16 @@ * Base test class for all CronetTest based tests. */ public class CronetTestBase extends AndroidTestCase { + /** + * Name of the file that contains the test server certificate in PEM format. + */ + static final String SERVER_CERT_PEM = "quic_test.example.com.crt"; + + /** + * Name of the file that contains the test server private key in PKCS8 PEM format. + */ + static final String SERVER_KEY_PKCS8_PEM = "quic_test.example.com.key.pkcs8.pem"; + private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "cronet_test"; private static final String LOOPBACK_ADDRESS = "127.0.0.1";
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java index 505ee82c..93d96744 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java
@@ -32,7 +32,7 @@ CronetTestUtil.setMockCertVerifierForTesting( mBuilder, QuicTestServer.createMockCertVerifier()); assertTrue(Http2TestServer.startHttp2TestServer( - getContext(), QuicTestServer.getServerCert(), QuicTestServer.getServerCertKey())); + getContext(), SERVER_CERT_PEM, SERVER_KEY_PKCS8_PEM)); } @Override
diff --git a/components/cronet/android/test/smoketests/src/org/chromium/net/smoke/ChromiumNativeTestSupport.java b/components/cronet/android/test/smoketests/src/org/chromium/net/smoke/ChromiumNativeTestSupport.java index d130350..05958b6 100644 --- a/components/cronet/android/test/smoketests/src/org/chromium/net/smoke/ChromiumNativeTestSupport.java +++ b/components/cronet/android/test/smoketests/src/org/chromium/net/smoke/ChromiumNativeTestSupport.java
@@ -18,6 +18,16 @@ class ChromiumNativeTestSupport extends ChromiumPlatformOnlyTestSupport { private static final String TAG = ChromiumNativeTestSupport.class.getSimpleName(); + /** + * Name of the file that contains the test server certificate in PEM format. + */ + private static final String SERVER_CERT_PEM = "quic_test.example.com.crt"; + + /** + * Name of the file that contains the test server private key in PKCS8 PEM format. + */ + private static final String SERVER_KEY_PKCS8_PEM = "quic_test.example.com.key.pkcs8.pem"; + @Override public TestServer createTestServer(Context context, Protocol protocol) { switch (protocol) { @@ -87,9 +97,8 @@ @Override public boolean start() { try { - return org.chromium.net.Http2TestServer.startHttp2TestServer(mContext, - org.chromium.net.QuicTestServer.getServerCert(), - org.chromium.net.QuicTestServer.getServerCertKey()); + return org.chromium.net.Http2TestServer.startHttp2TestServer( + mContext, SERVER_CERT_PEM, SERVER_KEY_PKCS8_PEM); } catch (Exception e) { Log.e(TAG, "Exception during Http2TestServer start", e); return false;
diff --git a/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc b/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc index 9d8a362..2bd7ad5 100644 --- a/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc +++ b/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.cc
@@ -6,9 +6,11 @@ #include <vector> +#include "base/android/callback_android.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" +#include "base/bind.h" #include "base/feature_list.h" #include "components/feature_engagement_tracker/internal/feature_list.h" #include "components/feature_engagement_tracker/public/feature_engagement_tracker.h" @@ -121,11 +123,22 @@ feature_engagement_tracker_impl_->Dismissed(); } +bool FeatureEngagementTrackerImplAndroid::IsInitialized( + JNIEnv* env, + const base::android::JavaRef<jobject>& jobj) { + return feature_engagement_tracker_impl_->IsInitialized(); +} + void FeatureEngagementTrackerImplAndroid::AddOnInitializedCallback( JNIEnv* env, const base::android::JavaRef<jobject>& jobj, const base::android::JavaParamRef<jobject>& j_callback_obj) { - // TODO(nyquist): Implement support for the wrapped base::Callback. + // Disambiguate RunCallbackAndroid to get the reference to the bool version. + void (*runBoolCallback)(const base::android::JavaRef<jobject>&, bool) = + &base::android::RunCallbackAndroid; + feature_engagement_tracker_impl_->AddOnInitializedCallback( + base::Bind(runBoolCallback, + base::android::ScopedJavaGlobalRef<jobject>(j_callback_obj))); } } // namespace feature_engagement_tracker
diff --git a/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h b/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h index 1234ae8..79f3c41 100644 --- a/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h +++ b/components/feature_engagement_tracker/internal/android/feature_engagement_tracker_impl_android.h
@@ -54,6 +54,8 @@ const base::android::JavaParamRef<jstring>& jfeature); virtual void Dismissed(JNIEnv* env, const base::android::JavaRef<jobject>& jobj); + virtual bool IsInitialized(JNIEnv* env, + const base::android::JavaRef<jobject>& jobj); virtual void AddOnInitializedCallback( JNIEnv* env, const base::android::JavaRef<jobject>& jobj,
diff --git a/components/feature_engagement_tracker/internal/android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java b/components/feature_engagement_tracker/internal/android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java index 734b5ba2..8626790 100644 --- a/components/feature_engagement_tracker/internal/android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java +++ b/components/feature_engagement_tracker/internal/android/java/src/org/chromium/components/feature_engagement_tracker/internal/FeatureEngagementTrackerImpl.java
@@ -48,6 +48,12 @@ } @Override + public boolean isInitialized() { + assert mNativePtr != 0; + return nativeIsInitialized(mNativePtr); + } + + @Override public void addOnInitializedCallback(Callback<Boolean> callback) { assert mNativePtr != 0; nativeAddOnInitializedCallback(mNativePtr, callback); @@ -69,6 +75,7 @@ private native boolean nativeShouldTriggerHelpUI( long nativeFeatureEngagementTrackerImplAndroid, String feature); private native void nativeDismissed(long nativeFeatureEngagementTrackerImplAndroid); + private native boolean nativeIsInitialized(long nativeFeatureEngagementTrackerImplAndroid); private native void nativeAddOnInitializedCallback( long nativeFeatureEngagementTrackerImplAndroid, Callback<Boolean> callback); }
diff --git a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc index 4f1d3bf..ecda0ed 100644 --- a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc +++ b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/feature_list.h" #include "base/memory/ptr_util.h" +#include "base/threading/thread_task_runner_handle.h" #include "components/feature_engagement_tracker/internal/editable_configuration.h" #include "components/feature_engagement_tracker/internal/feature_list.h" #include "components/feature_engagement_tracker/internal/in_memory_store.h" @@ -73,6 +74,7 @@ std::unique_ptr<ConditionValidator> condition_validator, std::unique_ptr<StorageValidator> storage_validator) : condition_validator_(std::move(condition_validator)), + initialization_finished_(false), weak_ptr_factory_(this) { model_ = base::MakeUnique<ModelImpl>( std::move(store), std::move(configuration), std::move(storage_validator)); @@ -101,13 +103,31 @@ model_->SetIsCurrentlyShowing(false); } -void FeatureEngagementTrackerImpl::AddOnInitializedCallback( - OnInitializedCallback callback) { - // TODO(nyquist): Add support for this. +bool FeatureEngagementTrackerImpl::IsInitialized() { + return model_->IsReady(); } -void FeatureEngagementTrackerImpl::OnModelInitializationFinished(bool result) { - // TODO(nyquist): Ensure that all OnInitializedCallbacks are invoked. +void FeatureEngagementTrackerImpl::AddOnInitializedCallback( + OnInitializedCallback callback) { + if (initialization_finished_) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(callback, model_->IsReady())); + return; + } + + on_initialized_callbacks_.push_back(callback); +} + +void FeatureEngagementTrackerImpl::OnModelInitializationFinished(bool success) { + DCHECK_EQ(success, model_->IsReady()); + initialization_finished_ = true; + + for (auto& callback : on_initialized_callbacks_) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(callback, success)); + } + + on_initialized_callbacks_.clear(); } } // namespace feature_engagement_tracker
diff --git a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h index 630b396..9ce2dc9 100644 --- a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h +++ b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.h
@@ -36,11 +36,12 @@ void NotifyEvent(const std::string& event) override; bool ShouldTriggerHelpUI(const base::Feature& feature) override; void Dismissed() override; + bool IsInitialized() override; void AddOnInitializedCallback(OnInitializedCallback callback) override; private: // Invoked by the Model when it has been initialized. - void OnModelInitializationFinished(bool result); + void OnModelInitializationFinished(bool success); // The current model. std::unique_ptr<Model> model_; @@ -49,6 +50,13 @@ // help UI. std::unique_ptr<ConditionValidator> condition_validator_; + // Whether the initialization of the underlying model has finished. + bool initialization_finished_; + + // The list of callbacks to invoke when initialization has finished. This + // is cleared after the initialization has happened. + std::vector<OnInitializedCallback> on_initialized_callbacks_; + base::WeakPtrFactory<FeatureEngagementTrackerImpl> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(FeatureEngagementTrackerImpl);
diff --git a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc index 37245da..05eb055 100644 --- a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc +++ b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc
@@ -37,16 +37,55 @@ configuration->SetConfiguration(&feature, config); } +// An OnInitializedCallback that stores whether it has been invoked and what +// the result was. +class StoringInitializedCallback { + public: + StoringInitializedCallback() : invoked_(false), success_(false) {} + + void OnInitialized(bool success) { + DCHECK(!invoked_); + invoked_ = true; + success_ = success; + } + + bool invoked() { return invoked_; } + + bool success() { return success_; } + + private: + bool invoked_; + bool success_; + + DISALLOW_COPY_AND_ASSIGN(StoringInitializedCallback); +}; + +// An InMemoryStore that is able to fake successful and unsuccessful +// loading of state. +class TestInMemoryStore : public InMemoryStore { + public: + explicit TestInMemoryStore(bool load_should_succeed) + : InMemoryStore(), load_should_succeed_(load_should_succeed) {} + + void Load(const OnLoadedCallback& callback) override { + HandleLoadResult(callback, load_should_succeed_); + } + + private: + // Denotes whether the call to Load(...) should succeed or not. This impacts + // both the ready-state and the result for the OnLoadedCallback. + bool load_should_succeed_; + + DISALLOW_COPY_AND_ASSIGN(TestInMemoryStore); +}; + class FeatureEngagementTrackerImplTest : public ::testing::Test { public: - FeatureEngagementTrackerImplTest() { - std::unique_ptr<Store> store = base::MakeUnique<InMemoryStore>(); + FeatureEngagementTrackerImplTest() = default; + + void SetUp() override { std::unique_ptr<EditableConfiguration> configuration = base::MakeUnique<EditableConfiguration>(); - std::unique_ptr<ConditionValidator> condition_validator = - base::MakeUnique<OnceConditionValidator>(); - std::unique_ptr<StorageValidator> storage_validator = - base::MakeUnique<NeverStorageValidator>(); RegisterFeatureConfig(configuration.get(), kTestFeatureFoo, true); RegisterFeatureConfig(configuration.get(), kTestFeatureBar, true); @@ -56,21 +95,177 @@ {kTestFeatureFoo, kTestFeatureBar, kTestFeatureQux}, {}); tracker_.reset(new FeatureEngagementTrackerImpl( - std::move(store), std::move(configuration), - std::move(condition_validator), std::move(storage_validator))); - // Ensure all initialization is finished. - base::RunLoop().RunUntilIdle(); + CreateStore(), std::move(configuration), + base::MakeUnique<OnceConditionValidator>(), + base::MakeUnique<NeverStorageValidator>())); } protected: + virtual std::unique_ptr<Store> CreateStore() { + // Returns a Store that will successfully initialize. + return base::MakeUnique<TestInMemoryStore>(true); + } + base::MessageLoop message_loop_; std::unique_ptr<FeatureEngagementTrackerImpl> tracker_; base::test::ScopedFeatureList scoped_feature_list_; + + private: + DISALLOW_COPY_AND_ASSIGN(FeatureEngagementTrackerImplTest); +}; + +// A top-level test class where the store fails to initialize. +class FailingInitFeatureEngagementTrackerImplTest + : public FeatureEngagementTrackerImplTest { + public: + FailingInitFeatureEngagementTrackerImplTest() = default; + + protected: + std::unique_ptr<Store> CreateStore() override { + // Returns a Store that will fail to initialize. + return base::MakeUnique<TestInMemoryStore>(false); + } + + private: + DISALLOW_COPY_AND_ASSIGN(FailingInitFeatureEngagementTrackerImplTest); }; } // namespace +TEST_F(FeatureEngagementTrackerImplTest, TestInitialization) { + EXPECT_FALSE(tracker_->IsInitialized()); + + StoringInitializedCallback callback; + tracker_->AddOnInitializedCallback(base::Bind( + &StoringInitializedCallback::OnInitialized, base::Unretained(&callback))); + EXPECT_FALSE(callback.invoked()); + + // Ensure all initialization is finished. + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(tracker_->IsInitialized()); + EXPECT_TRUE(callback.invoked()); + EXPECT_TRUE(callback.success()); +} + +TEST_F(FeatureEngagementTrackerImplTest, TestInitializationMultipleCallbacks) { + EXPECT_FALSE(tracker_->IsInitialized()); + + StoringInitializedCallback callback1; + StoringInitializedCallback callback2; + + tracker_->AddOnInitializedCallback( + base::Bind(&StoringInitializedCallback::OnInitialized, + base::Unretained(&callback1))); + tracker_->AddOnInitializedCallback( + base::Bind(&StoringInitializedCallback::OnInitialized, + base::Unretained(&callback2))); + EXPECT_FALSE(callback1.invoked()); + EXPECT_FALSE(callback2.invoked()); + + // Ensure all initialization is finished. + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(tracker_->IsInitialized()); + EXPECT_TRUE(callback1.invoked()); + EXPECT_TRUE(callback2.invoked()); + EXPECT_TRUE(callback1.success()); + EXPECT_TRUE(callback2.success()); +} + +TEST_F(FeatureEngagementTrackerImplTest, TestAddingCallbackAfterInitFinished) { + EXPECT_FALSE(tracker_->IsInitialized()); + + // Ensure all initialization is finished. + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(tracker_->IsInitialized()); + + StoringInitializedCallback callback; + tracker_->AddOnInitializedCallback(base::Bind( + &StoringInitializedCallback::OnInitialized, base::Unretained(&callback))); + EXPECT_FALSE(callback.invoked()); + + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(callback.invoked()); +} + +TEST_F(FeatureEngagementTrackerImplTest, + TestAddingCallbackBeforeAndAfterInitFinished) { + EXPECT_FALSE(tracker_->IsInitialized()); + + // Ensure all initialization is finished. + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(tracker_->IsInitialized()); + + StoringInitializedCallback callback_before; + tracker_->AddOnInitializedCallback( + base::Bind(&StoringInitializedCallback::OnInitialized, + base::Unretained(&callback_before))); + EXPECT_FALSE(callback_before.invoked()); + + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(callback_before.invoked()); + + StoringInitializedCallback callback_after; + tracker_->AddOnInitializedCallback( + base::Bind(&StoringInitializedCallback::OnInitialized, + base::Unretained(&callback_after))); + EXPECT_FALSE(callback_after.invoked()); + + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(callback_after.invoked()); +} + +TEST_F(FailingInitFeatureEngagementTrackerImplTest, TestFailingInitialization) { + EXPECT_FALSE(tracker_->IsInitialized()); + + StoringInitializedCallback callback; + tracker_->AddOnInitializedCallback(base::Bind( + &StoringInitializedCallback::OnInitialized, base::Unretained(&callback))); + EXPECT_FALSE(callback.invoked()); + + // Ensure all initialization is finished. + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(tracker_->IsInitialized()); + EXPECT_TRUE(callback.invoked()); + EXPECT_FALSE(callback.success()); +} + +TEST_F(FailingInitFeatureEngagementTrackerImplTest, + TestFailingInitializationMultipleCallbacks) { + EXPECT_FALSE(tracker_->IsInitialized()); + + StoringInitializedCallback callback1; + StoringInitializedCallback callback2; + tracker_->AddOnInitializedCallback( + base::Bind(&StoringInitializedCallback::OnInitialized, + base::Unretained(&callback1))); + tracker_->AddOnInitializedCallback( + base::Bind(&StoringInitializedCallback::OnInitialized, + base::Unretained(&callback2))); + EXPECT_FALSE(callback1.invoked()); + EXPECT_FALSE(callback2.invoked()); + + // Ensure all initialization is finished. + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(tracker_->IsInitialized()); + EXPECT_TRUE(callback1.invoked()); + EXPECT_TRUE(callback2.invoked()); + EXPECT_FALSE(callback1.success()); + EXPECT_FALSE(callback2.success()); +} + TEST_F(FeatureEngagementTrackerImplTest, TestTriggering) { + // Ensure all initialization is finished. + base::RunLoop().RunUntilIdle(); + // The first time a feature triggers it should be shown. EXPECT_TRUE(tracker_->ShouldTriggerHelpUI(kTestFeatureFoo)); EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(kTestFeatureFoo));
diff --git a/components/feature_engagement_tracker/internal/model.h b/components/feature_engagement_tracker/internal/model.h index 116ff42..f74a910 100644 --- a/components/feature_engagement_tracker/internal/model.h +++ b/components/feature_engagement_tracker/internal/model.h
@@ -22,9 +22,9 @@ // A Model provides all necessary runtime state. class Model { public: - // Callback for when model initialization has finished. The bool argument - // denotes whether the model was successfully initialized. - using OnModelInitializationFinished = base::Callback<void(bool)>; + // Callback for when model initialization has finished. The |success| + // argument denotes whether the model was successfully initialized. + using OnModelInitializationFinished = base::Callback<void(bool success)>; virtual ~Model() = default; @@ -32,7 +32,7 @@ // required operations have been finished, a callback is posted. virtual void Initialize(const OnModelInitializationFinished& callback) = 0; - // Returns whether the model is ready, i.e. whether it has been fully + // Returns whether the model is ready, i.e. whether it has been successfully // initialized. virtual bool IsReady() const = 0;
diff --git a/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureEngagementTracker.java b/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureEngagementTracker.java index 36c8714..633993f 100644 --- a/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureEngagementTracker.java +++ b/components/feature_engagement_tracker/public/android/java/src/org/chromium/components/feature_engagement_tracker/FeatureEngagementTracker.java
@@ -36,10 +36,22 @@ void dismissed(); /** - * For features that trigger on startup, they register a callback to ensure that they are told - * when the tracker has been initialized. The callback will be invoked when the tracker has - * been initialized. The boolean parameter indicated whether the initialization was a success - * and that the tracker is ready to receive calls. + * Returns whether the tracker has been successfully initialized. During startup, this will be + * false until the internal model has been loaded at which point it is set to true if the + * initialization was successful. The state will never change from initialized to uninitialized. + * Callers can invoke AddOnInitializedCallback(...) to be notified when the result of the + * initialization is ready. + */ + boolean isInitialized(); + + /** + * For features that trigger on startup, they can register a callback to ensure that they are + * informed when the tracker has finished the initialization. If the tracker has already been + * initialized, the callback will still be invoked with the result. The callback is guaranteed + * to be invoked exactly one time. + * + * The |result| parameter indicates whether the initialization was a success and the tracker is + * ready to receive calls. */ void addOnInitializedCallback(Callback<Boolean> callback); }
diff --git a/components/feature_engagement_tracker/public/feature_engagement_tracker.h b/components/feature_engagement_tracker/public/feature_engagement_tracker.h index b151dda4..d969a81 100644 --- a/components/feature_engagement_tracker/public/feature_engagement_tracker.h +++ b/components/feature_engagement_tracker/public/feature_engagement_tracker.h
@@ -37,8 +37,8 @@ #endif // defined(OS_ANDROID) // Invoked when the tracker has been initialized. The |success| parameter - // indicates that the initialization was a success and it it ready to receive - // calls. + // indicates that the initialization was a success and the tracker is ready to + // receive calls. using OnInitializedCallback = base::Callback<void(bool success)>; // The |storage_dir| is the path to where all local storage will be. @@ -61,8 +61,19 @@ // Must be called after display of feature enlightenment finishes. virtual void Dismissed() = 0; - // For features that trigger on startup, they register a callback to ensure - // that they are told when the tracker has been initialized. + // Returns whether the tracker has been successfully initialized. During + // startup, this will be false until the internal model has been loaded at + // which point it is set to true if the initialization was successful. The + // state will never change from initialized to uninitialized. + // Callers can invoke AddOnInitializedCallback(...) to be notified when the + // result of the initialization is ready. + virtual bool IsInitialized() = 0; + + // For features that trigger on startup, they can register a callback to + // ensure that they are informed when the tracker has finished the + // initialization. If the tracker has already been initialized, the callback + // will still be invoked with the result. The callback is guaranteed to be + // invoked exactly one time. virtual void AddOnInitializedCallback(OnInitializedCallback callback) = 0; protected:
diff --git a/components/onc/docs/onc_spec.md b/components/onc/docs/onc_spec.md index c42e357c..de07cb0 100644 --- a/components/onc/docs/onc_spec.md +++ b/components/onc/docs/onc_spec.md
@@ -1456,6 +1456,12 @@ * The name of the cellular carrier when the hotspot is provided by a cellular connection. +* **HasConnectedToHost** + * (read-only) - **boolean** + * If *true*, the current device has already connected to a Tether network + created by the same external device which is providing this Tether + network. + * **SignalStrength** * (optional, read-only) - **integer** * The current signal strength for the hotspot's connection in the range
diff --git a/components/onc/onc_constants.cc b/components/onc/onc_constants.cc index d3e68e58..83f6b056 100644 --- a/components/onc/onc_constants.cc +++ b/components/onc/onc_constants.cc
@@ -197,6 +197,7 @@ namespace tether { const char kBatteryPercentage[] = "BatteryPercentage"; const char kCarrier[] = "Carrier"; +const char kHasConnectedToHost[] = "HasConnectedToHost"; const char kSignalStrength[] = "SignalStrength"; } // namespace tether
diff --git a/components/onc/onc_constants.h b/components/onc/onc_constants.h index ff6301c..93c92ae 100644 --- a/components/onc/onc_constants.h +++ b/components/onc/onc_constants.h
@@ -222,6 +222,7 @@ namespace tether { ONC_EXPORT extern const char kBatteryPercentage[]; ONC_EXPORT extern const char kCarrier[]; +ONC_EXPORT extern const char kHasConnectedToHost[]; ONC_EXPORT extern const char kSignalStrength[]; } // namespace tether
diff --git a/components/payments/mojom/payment_request.mojom b/components/payments/mojom/payment_request.mojom index 99dfa91ba..6192f84 100644 --- a/components/payments/mojom/payment_request.mojom +++ b/components/payments/mojom/payment_request.mojom
@@ -193,6 +193,11 @@ array<PaymentShippingOption> shipping_options; array<PaymentDetailsModifier> modifiers; string error = ""; + // Identifier identifying the payment request, to be exposed + // to payment apps. It is optional since this structure is used + // by PaymentDetailsUpdate (next to PaymentDetailsInit) but + // PaymentDetailsUpdate has no id. + string? id; }; enum PaymentShippingType {
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc index 9e0c9d3..8d8cdfa 100644 --- a/components/printing/renderer/print_web_view_helper.cc +++ b/components/printing/renderer/print_web_view_helper.cc
@@ -914,6 +914,7 @@ is_loading_(false), is_scripted_preview_delayed_(false), ipc_nesting_level_(0), + render_frame_gone_(false), weak_ptr_factory_(this) { if (!delegate_->IsPrintPreviewEnabled()) DisablePreview(); @@ -995,8 +996,6 @@ // choose to ignore message or safely crash process. ++ipc_nesting_level_; - auto self = weak_ptr_factory_.GetWeakPtr(); - bool handled = true; IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper, message) #if BUILDFLAG(ENABLE_BASIC_PRINTING) @@ -1015,13 +1014,17 @@ IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() - // Check if |this| is still valid. e.g. when OnPrintPages() returns. - if (self) - --ipc_nesting_level_; + --ipc_nesting_level_; + if (ipc_nesting_level_ == 0 && render_frame_gone_) + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); return handled; } void PrintWebViewHelper::OnDestruct() { + if (ipc_nesting_level_ > 0) { + render_frame_gone_ = true; + return; + } delete this; } @@ -1212,7 +1215,7 @@ prep_frame_view_->CopySelectionIfNeeded( render_frame()->GetWebkitPreferences(), base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument, - base::Unretained(this))); + weak_ptr_factory_.GetWeakPtr())); } void PrintWebViewHelper::OnFramePreparedForPreviewDocument() { @@ -1839,7 +1842,7 @@ prep_frame_view_->CopySelectionIfNeeded( render_frame()->GetWebkitPreferences(), base::Bind(&PrintWebViewHelper::OnFramePreparedForPrintPages, - base::Unretained(this))); + weak_ptr_factory_.GetWeakPtr())); return true; } #endif // BUILDFLAG(ENABLE_BASIC_PRINTING) @@ -1983,7 +1986,7 @@ // DidStopLoading() is called. Defer showing the preview until then. on_stop_loading_closure_ = base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview, - base::Unretained(this)); + weak_ptr_factory_.GetWeakPtr()); } else { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&PrintWebViewHelper::ShowScriptedPrintPreview, @@ -2006,7 +2009,7 @@ if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) { on_stop_loading_closure_ = base::Bind(&PrintWebViewHelper::RequestPrintPreview, - base::Unretained(this), type); + weak_ptr_factory_.GetWeakPtr(), type); return; } @@ -2022,7 +2025,7 @@ if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) { on_stop_loading_closure_ = base::Bind(&PrintWebViewHelper::RequestPrintPreview, - base::Unretained(this), type); + weak_ptr_factory_.GetWeakPtr(), type); return; } @@ -2091,10 +2094,10 @@ : total_page_count_(0), current_page_index_(0), generate_draft_pages_(true), + is_modifiable_(true), print_ready_metafile_page_count_(0), error_(PREVIEW_ERROR_NONE), - state_(UNINITIALIZED) { -} + state_(UNINITIALIZED) {} PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() { } @@ -2106,6 +2109,7 @@ state_ = INITIALIZED; source_frame_.Reset(web_frame); source_node_.Reset(); + CalculateIsModifiable(); } void PrintWebViewHelper::PrintPreviewContext::InitWithNode( @@ -2116,6 +2120,7 @@ state_ = INITIALIZED; source_frame_.Reset(web_node.GetDocument().GetFrame()); source_node_ = web_node; + CalculateIsModifiable(); } void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() { @@ -2241,9 +2246,9 @@ return state_ == RENDERING || state_ == DONE; } -bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() { - // The only kind of node we can print right now is a PDF node. - return !PrintingNodeOrPdfFrame(source_frame(), source_node_); +bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() const { + DCHECK(state_ != UNINITIALIZED); + return is_modifiable_; } bool PrintWebViewHelper::PrintPreviewContext::HasSelection() { @@ -2320,6 +2325,11 @@ error_ = PREVIEW_ERROR_NONE; } +void PrintWebViewHelper::PrintPreviewContext::CalculateIsModifiable() { + // The only kind of node we can print right now is a PDF node. + is_modifiable_ = !PrintingNodeOrPdfFrame(source_frame(), source_node_); +} + void PrintWebViewHelper::SetPrintPagesParams( const PrintMsg_PrintPages_Params& settings) { print_pages_params_ = base::MakeUnique<PrintMsg_PrintPages_Params>(settings);
diff --git a/components/printing/renderer/print_web_view_helper.h b/components/printing/renderer/print_web_view_helper.h index 652fbf03..15d2c28 100644 --- a/components/printing/renderer/print_web_view_helper.h +++ b/components/printing/renderer/print_web_view_helper.h
@@ -449,7 +449,7 @@ // Helper functions int GetNextPageNumber(); bool IsRendering() const; - bool IsModifiable(); + bool IsModifiable() const; bool HasSelection(); bool IsLastPageOfPrintReadyMetafile() const; bool IsFinalPageRendered() const; @@ -487,6 +487,8 @@ // Reset some of the internal rendering context. void ClearContext(); + void CalculateIsModifiable(); + // Specifies what to render for print preview. FrameReference source_frame_; blink::WebNode source_node_; @@ -506,6 +508,9 @@ // True, when draft pages needs to be generated. bool generate_draft_pages_; + // True, if the document source is modifiable. e.g. HTML and not PDF. + bool is_modifiable_; + // Specifies the total number of pages in the print ready metafile. int print_ready_metafile_page_count_; @@ -515,6 +520,8 @@ enum PrintPreviewErrorBuckets error_; State state_; + + DISALLOW_COPY_AND_ASSIGN(PrintPreviewContext); }; class ScriptingThrottler { @@ -541,6 +548,7 @@ bool is_loading_; bool is_scripted_preview_delayed_; int ipc_nesting_level_; + bool render_frame_gone_; // Used to fix a race condition where the source is a PDF and print preview // hangs because RequestPrintPreview is called before DidStopLoading() is
diff --git a/components/proximity_auth/fake_remote_device_life_cycle.cc b/components/proximity_auth/fake_remote_device_life_cycle.cc index e8d70396..c5bf7111 100644 --- a/components/proximity_auth/fake_remote_device_life_cycle.cc +++ b/components/proximity_auth/fake_remote_device_life_cycle.cc
@@ -22,6 +22,10 @@ return remote_device_; } +cryptauth::Connection* FakeRemoteDeviceLifeCycle::GetConnection() const { + return connection_; +} + RemoteDeviceLifeCycle::State FakeRemoteDeviceLifeCycle::GetState() const { return state_; }
diff --git a/components/proximity_auth/fake_remote_device_life_cycle.h b/components/proximity_auth/fake_remote_device_life_cycle.h index 548099b1..4307b3c 100644 --- a/components/proximity_auth/fake_remote_device_life_cycle.h +++ b/components/proximity_auth/fake_remote_device_life_cycle.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/observer_list.h" +#include "components/cryptauth/fake_connection.h" #include "components/cryptauth/remote_device.h" #include "components/proximity_auth/remote_device_life_cycle.h" @@ -20,6 +21,7 @@ // RemoteDeviceLifeCycle: void Start() override; cryptauth::RemoteDevice GetRemoteDevice() const override; + cryptauth::Connection* GetConnection() const override; State GetState() const override; Messenger* GetMessenger() override; void AddObserver(Observer* observer) override; @@ -30,6 +32,10 @@ void set_messenger(Messenger* messenger) { messenger_ = messenger; } + void set_connection(cryptauth::Connection* connection) { + connection_ = connection; + } + bool started() { return started_; } base::ObserverList<Observer>& observers() { return observers_; } @@ -43,6 +49,8 @@ State state_; + cryptauth::Connection* connection_; + Messenger* messenger_; DISALLOW_COPY_AND_ASSIGN(FakeRemoteDeviceLifeCycle);
diff --git a/components/proximity_auth/messenger.h b/components/proximity_auth/messenger.h index d88f7d88..7267982 100644 --- a/components/proximity_auth/messenger.h +++ b/components/proximity_auth/messenger.h
@@ -42,6 +42,11 @@ // Returns the SecureContext instance used by the messenger. Ownership of the // SecureContext is not passed. virtual cryptauth::SecureContext* GetSecureContext() const = 0; + + // Returns the underlying raw connection. Note that you should use + // |GetSecureContext()| instead if you want to send and receive messages + // securely. + virtual cryptauth::Connection* GetConnection() const = 0; }; } // namespace proximity_auth
diff --git a/components/proximity_auth/messenger_impl.cc b/components/proximity_auth/messenger_impl.cc index 1ffa646bd..da2c602 100644 --- a/components/proximity_auth/messenger_impl.cc +++ b/components/proximity_auth/messenger_impl.cc
@@ -154,6 +154,10 @@ return secure_context_.get(); } +cryptauth::Connection* MessengerImpl::GetConnection() const { + return connection_.get(); +} + MessengerImpl::PendingMessage::PendingMessage() {} MessengerImpl::PendingMessage::PendingMessage(
diff --git a/components/proximity_auth/messenger_impl.h b/components/proximity_auth/messenger_impl.h index 47310a0..e7c7fd5d 100644 --- a/components/proximity_auth/messenger_impl.h +++ b/components/proximity_auth/messenger_impl.h
@@ -44,6 +44,7 @@ void RequestDecryption(const std::string& challenge) override; void RequestUnlock() override; cryptauth::SecureContext* GetSecureContext() const override; + cryptauth::Connection* GetConnection() const override; // Exposed for testing. cryptauth::Connection* connection() { return connection_.get(); }
diff --git a/components/proximity_auth/proximity_monitor.h b/components/proximity_auth/proximity_monitor.h index b2978bf..b441cce 100644 --- a/components/proximity_auth/proximity_monitor.h +++ b/components/proximity_auth/proximity_monitor.h
@@ -13,8 +13,6 @@ // sufficiently close to the local device to permit unlocking. class ProximityMonitor { public: - enum class Strategy { NONE, CHECK_RSSI, CHECK_TRANSMIT_POWER }; - virtual ~ProximityMonitor() {} // Activates the proximity monitor. No-op if the proximity monitor is already @@ -25,18 +23,10 @@ // already inactive. virtual void Stop() = 0; - // Returns the strategy used to determine whether the remote device is in - // proximity. - virtual Strategy GetStrategy() const = 0; - // Returns |true| iff the remote device is close enough to the local device, // given the user's current settings. virtual bool IsUnlockAllowed() const = 0; - // Returns |true| iff the remote device is close enough to the local device, - // according to its RSSI measurement. - virtual bool IsInRssiRange() const = 0; - // Records the current proximity measurements to UMA. This should be called // when the user successfully authenticates using proximity auth. virtual void RecordProximityMetricsOnAuthSuccess() = 0;
diff --git a/components/proximity_auth/proximity_monitor_impl.cc b/components/proximity_auth/proximity_monitor_impl.cc index 02422ca..22bedf4 100644 --- a/components/proximity_auth/proximity_monitor_impl.cc +++ b/components/proximity_auth/proximity_monitor_impl.cc
@@ -27,16 +27,15 @@ // The RSSI threshold below which we consider the remote device to not be in // proximity. -const int kRssiThreshold = -5; +const int kRssiThreshold = -45; // The weight of the most recent RSSI sample. const double kRssiSampleWeight = 0.3; ProximityMonitorImpl::ProximityMonitorImpl( - const cryptauth::RemoteDevice& remote_device, + cryptauth::Connection* connection, std::unique_ptr<base::TickClock> clock) - : remote_device_(remote_device), - strategy_(Strategy::NONE), + : connection_(connection), remote_device_is_in_proximity_(false), is_active_(false), clock_(std::move(clock)), @@ -50,11 +49,6 @@ PA_LOG(ERROR) << "[Proximity] Proximity monitoring unavailable: " << "Bluetooth is unsupported on this platform."; } - - // TODO(isherman): Test prefs to set the strategy. Need to read from "Local - // State" prefs on the sign-in screen, and per-user prefs on the lock screen. - // TODO(isherman): Unlike in the JS app, destroy and recreate the proximity - // monitor when the connection state changes. } ProximityMonitorImpl::~ProximityMonitorImpl() { @@ -71,17 +65,8 @@ UpdatePollingState(); } -ProximityMonitor::Strategy ProximityMonitorImpl::GetStrategy() const { - return strategy_; -} - bool ProximityMonitorImpl::IsUnlockAllowed() const { - return strategy_ == Strategy::NONE || remote_device_is_in_proximity_; -} - -bool ProximityMonitorImpl::IsInRssiRange() const { - return (strategy_ != Strategy::NONE && rssi_rolling_average_ && - *rssi_rolling_average_ > kRssiThreshold); + return remote_device_is_in_proximity_; } void ProximityMonitorImpl::RecordProximityMetricsOnAuthSuccess() { @@ -89,26 +74,12 @@ ? *rssi_rolling_average_ : metrics::kUnknownProximityValue; - int last_transmit_power_delta = - last_transmit_power_reading_ - ? (last_transmit_power_reading_->transmit_power - - last_transmit_power_reading_->max_transmit_power) - : metrics::kUnknownProximityValue; - - // If no zero RSSI value has been read, then record an overflow. - base::TimeDelta time_since_last_zero_rssi; - if (last_zero_rssi_timestamp_) - time_since_last_zero_rssi = clock_->NowTicks() - *last_zero_rssi_timestamp_; - else - time_since_last_zero_rssi = base::TimeDelta::FromDays(100); - std::string remote_device_model = metrics::kUnknownDeviceModel; - if (remote_device_.name != remote_device_.bluetooth_address) - remote_device_model = remote_device_.name; + cryptauth::RemoteDevice remote_device = connection_->remote_device(); + if (!remote_device.name.empty()) + remote_device_model = remote_device.name; metrics::RecordAuthProximityRollingRssi(round(rssi_rolling_average)); - metrics::RecordAuthProximityTransmitPowerDelta(last_transmit_power_delta); - metrics::RecordAuthProximityTimeSinceLastZeroRssi(time_since_last_zero_rssi); metrics::RecordAuthProximityRemoteDeviceModelHash(remote_device_model); } @@ -120,24 +91,6 @@ observers_.RemoveObserver(observer); } -void ProximityMonitorImpl::SetStrategy(Strategy strategy) { - if (strategy_ == strategy) - return; - strategy_ = strategy; - CheckForProximityStateChange(); - UpdatePollingState(); -} - -ProximityMonitorImpl::TransmitPowerReading::TransmitPowerReading( - int transmit_power, - int max_transmit_power) - : transmit_power(transmit_power), max_transmit_power(max_transmit_power) { -} - -bool ProximityMonitorImpl::TransmitPowerReading::IsInProximity() const { - return transmit_power < max_transmit_power; -} - void ProximityMonitorImpl::OnAdapterInitialized( scoped_refptr<device::BluetoothAdapter> adapter) { bluetooth_adapter_ = adapter; @@ -170,25 +123,23 @@ } bool ProximityMonitorImpl::ShouldPoll() const { - // Note: We poll even if the strategy is NONE so we can record measurements. return is_active_ && bluetooth_adapter_; } void ProximityMonitorImpl::Poll() { DCHECK(ShouldPoll()); - BluetoothDevice* device = - bluetooth_adapter_->GetDevice(remote_device_.bluetooth_address); + std::string address = connection_->GetDeviceAddress(); + BluetoothDevice* device = bluetooth_adapter_->GetDevice(address); if (!device) { - PA_LOG(ERROR) << "Unknown Bluetooth device with address " - << remote_device_.bluetooth_address; + PA_LOG(ERROR) << "Unknown Bluetooth device with address " << address; ClearProximityState(); return; } if (!device->IsConnected()) { - PA_LOG(ERROR) << "Bluetooth device with address " - << remote_device_.bluetooth_address << " is not connected."; + PA_LOG(ERROR) << "Bluetooth device with address " << address + << " is not connected."; ClearProximityState(); return; } @@ -204,17 +155,12 @@ return; } - if (connection_info.rssi != BluetoothDevice::kUnknownPower && - connection_info.transmit_power != BluetoothDevice::kUnknownPower && - connection_info.max_transmit_power != BluetoothDevice::kUnknownPower) { + if (connection_info.rssi != BluetoothDevice::kUnknownPower) { AddSample(connection_info); } else { PA_LOG(WARNING) << "[Proximity] Unkown values received from API: " - << connection_info.rssi << " " - << connection_info.transmit_power << " " - << connection_info.max_transmit_power; + << connection_info.rssi; rssi_rolling_average_.reset(); - last_transmit_power_reading_.reset(); CheckForProximityStateChange(); } } @@ -227,8 +173,6 @@ remote_device_is_in_proximity_ = false; rssi_rolling_average_.reset(); - last_transmit_power_reading_.reset(); - last_zero_rssi_timestamp_.reset(); } void ProximityMonitorImpl::AddSample( @@ -240,33 +184,16 @@ *rssi_rolling_average_ = weight * connection_info.rssi + (1 - weight) * (*rssi_rolling_average_); } - last_transmit_power_reading_.reset(new TransmitPowerReading( - connection_info.transmit_power, connection_info.max_transmit_power)); - - // It's rare but possible for the RSSI to be positive briefly. - if (connection_info.rssi >= 0) - last_zero_rssi_timestamp_.reset(new base::TimeTicks(clock_->NowTicks())); CheckForProximityStateChange(); } void ProximityMonitorImpl::CheckForProximityStateChange() { - if (strategy_ == Strategy::NONE) - return; + bool is_now_in_proximity = + rssi_rolling_average_ && *rssi_rolling_average_ > kRssiThreshold; - bool is_now_in_proximity = false; - switch (strategy_) { - case Strategy::NONE: - return; - - case Strategy::CHECK_RSSI: - is_now_in_proximity = IsInRssiRange(); - break; - - case Strategy::CHECK_TRANSMIT_POWER: - is_now_in_proximity = (last_transmit_power_reading_ && - last_transmit_power_reading_->IsInProximity()); - break; + if (rssi_rolling_average_) { + LOG(WARNING) << "RSSI: " << *rssi_rolling_average_; } if (remote_device_is_in_proximity_ != is_now_in_proximity) {
diff --git a/components/proximity_auth/proximity_monitor_impl.h b/components/proximity_auth/proximity_monitor_impl.h index 11cffd3..1aebd2e 100644 --- a/components/proximity_auth/proximity_monitor_impl.h +++ b/components/proximity_auth/proximity_monitor_impl.h
@@ -11,13 +11,13 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "components/cryptauth/connection.h" #include "components/cryptauth/remote_device.h" #include "components/proximity_auth/proximity_monitor.h" #include "device/bluetooth/bluetooth_device.h" namespace base { class TickClock; -class TimeTicks; } namespace device { @@ -31,41 +31,20 @@ // The concrete implemenation of the proximity monitor interface. class ProximityMonitorImpl : public ProximityMonitor { public: - // The |observer| is not owned, and must outlive |this| instance. - ProximityMonitorImpl(const cryptauth::RemoteDevice& remote_device, + // The |connection| is not owned, and must outlive |this| instance. + ProximityMonitorImpl(cryptauth::Connection* connection, std::unique_ptr<base::TickClock> clock); ~ProximityMonitorImpl() override; // ProximityMonitor: void Start() override; void Stop() override; - Strategy GetStrategy() const override; bool IsUnlockAllowed() const override; - bool IsInRssiRange() const override; void RecordProximityMetricsOnAuthSuccess() override; void AddObserver(ProximityMonitorObserver* observer) override; void RemoveObserver(ProximityMonitorObserver* observer) override; - protected: - // Sets the proximity detection strategy. Exposed for testing. - // TODO(isherman): Stop exposing this for testing once prefs are properly - // hooked up. - virtual void SetStrategy(Strategy strategy); - private: - struct TransmitPowerReading { - TransmitPowerReading(int transmit_power, int max_transmit_power); - - // Returns true if |this| transmit power reading indicates proximity. - bool IsInProximity() const; - - // The current transmit power. - int transmit_power; - - // The maximum possible transmit power. - int max_transmit_power; - }; - // Callback for asynchronous initialization of the Bluetooth adpater. void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter); @@ -95,7 +74,7 @@ void ClearProximityState(); // Updates the proximity state with a new |connection_info| sample of the - // current RSSI and Tx power, and the device's maximum Tx power. + // current RSSI. void AddSample( const device::BluetoothDevice::ConnectionInfo& connection_info); @@ -103,8 +82,9 @@ // samples. Notifies |observers_| on a change. void CheckForProximityStateChange(); - // The remote device being monitored. - const cryptauth::RemoteDevice remote_device_; + // The current connection being monitored. Not owned and must outlive this + // instance. + cryptauth::Connection* connection_; // The observers attached to the ProximityMonitor. base::ObserverList<ProximityMonitorObserver> observers_; @@ -112,9 +92,6 @@ // The Bluetooth adapter that will be polled for connection info. scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_; - // The strategy used to determine whether the remote device is in proximity. - Strategy strategy_; - // Whether the remote device is currently in close proximity to the local // device. bool remote_device_is_in_proximity_; @@ -129,18 +106,6 @@ // measurement. std::unique_ptr<double> rssi_rolling_average_; - // The last TX power reading. Null if the monitor is inactive, has not - // recently observed a TX power reading, or the most recent connection info - // included an invalid measurement. - std::unique_ptr<TransmitPowerReading> last_transmit_power_reading_; - - // The timestamp of the last zero RSSI reading. An RSSI value of 0 is special - // because both devices adjust their transmit powers such that the RSSI is in - // this golden range, if possible. Null if the monitor is inactive, has not - // recently observed an RSSI reading, or the most recent connection info - // included an invalid measurement. - std::unique_ptr<base::TimeTicks> last_zero_rssi_timestamp_; - // Used to access non-decreasing time measurements. std::unique_ptr<base::TickClock> clock_;
diff --git a/components/proximity_auth/proximity_monitor_impl_unittest.cc b/components/proximity_auth/proximity_monitor_impl_unittest.cc index af5f8eb..9130dfd 100644 --- a/components/proximity_auth/proximity_monitor_impl_unittest.cc +++ b/components/proximity_auth/proximity_monitor_impl_unittest.cc
@@ -15,6 +15,7 @@ #include "base/test/test_simple_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" +#include "components/cryptauth/fake_connection.h" #include "components/cryptauth/remote_device.h" #include "components/proximity_auth/logging/logging.h" #include "components/proximity_auth/proximity_monitor_observer.h" @@ -33,24 +34,11 @@ namespace { const char kRemoteDeviceUserId[] = "example@gmail.com"; -const char kBluetoothAddress[] = "AA:BB:CC:DD:EE:FF"; const char kRemoteDevicePublicKey[] = "Remote Public Key"; const char kRemoteDeviceName[] = "LGE Nexus 5"; +const char kBluetoothAddress[] = "AA:BB:CC:DD:EE:FF"; const char kPersistentSymmetricKey[] = "PSK"; - -class TestProximityMonitorImpl : public ProximityMonitorImpl { - public: - explicit TestProximityMonitorImpl( - const cryptauth::RemoteDevice& remote_device, - std::unique_ptr<base::TickClock> clock) - : ProximityMonitorImpl(remote_device, std::move(clock)) {} - ~TestProximityMonitorImpl() override {} - - using ProximityMonitorImpl::SetStrategy; - - private: - DISALLOW_COPY_AND_ASSIGN(TestProximityMonitorImpl); -}; +const int kRssiThreshold = -45; class MockProximityMonitorObserver : public ProximityMonitorObserver { public: @@ -83,17 +71,17 @@ remote_bluetooth_device_(&*bluetooth_adapter_, 0, kRemoteDeviceName, - kBluetoothAddress, + "", false /* paired */, true /* connected */), - monitor_( - cryptauth::RemoteDevice(kRemoteDeviceUserId, - kRemoteDeviceName, - kRemoteDevicePublicKey, - kBluetoothAddress, - kPersistentSymmetricKey, - std::string()), - base::WrapUnique(clock_)), + remote_device_(kRemoteDeviceUserId, + kRemoteDeviceName, + kRemoteDevicePublicKey, + kBluetoothAddress, + kPersistentSymmetricKey, + std::string()), + connection_(remote_device_), + monitor_(&connection_, base::WrapUnique(clock_)), task_runner_(new base::TestSimpleTaskRunner()), thread_task_runner_handle_(task_runner_) { ON_CALL(*bluetooth_adapter_, GetDevice(kBluetoothAddress)) @@ -102,6 +90,7 @@ .WillByDefault(SaveArg<0>(&connection_info_callback_)); monitor_.AddObserver(&observer_); } + ~ProximityAuthProximityMonitorImplTest() override {} void RunPendingTasks() { task_runner_->RunPendingTasks(); } @@ -126,9 +115,11 @@ // Mocks used for verifying interactions with the Bluetooth subsystem. scoped_refptr<device::MockBluetoothAdapter> bluetooth_adapter_; NiceMock<device::MockBluetoothDevice> remote_bluetooth_device_; + cryptauth::RemoteDevice remote_device_; + cryptauth::FakeConnection connection_; // The proximity monitor under test. - TestProximityMonitorImpl monitor_; + ProximityMonitorImpl monitor_; private: scoped_refptr<base::TestSimpleTaskRunner> task_runner_; @@ -137,304 +128,124 @@ ScopedDisableLoggingForTesting disable_logging_; }; -TEST_F(ProximityAuthProximityMonitorImplTest, GetStrategy) { - EXPECT_EQ(ProximityMonitor::Strategy::NONE, monitor_.GetStrategy()); - - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER); - EXPECT_EQ(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER, - monitor_.GetStrategy()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, ProximityState_StrategyIsNone) { - monitor_.SetStrategy(ProximityMonitor::Strategy::NONE); - - EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, ProximityState_NeverStarted) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - +TEST_F(ProximityAuthProximityMonitorImplTest, IsUnlockAllowed_NeverStarted) { EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); } TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_Started_NoConnectionInfoReceivedYet) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); + IsUnlockAllowed_Started_NoConnectionInfoReceivedYet) { + monitor_.Start(); + EXPECT_FALSE(monitor_.IsUnlockAllowed()); +} + +TEST_F(ProximityAuthProximityMonitorImplTest, IsUnlockAllowed_RssiInRange) { + monitor_.Start(); + ProvideConnectionInfo({0, 4, 4}); + EXPECT_TRUE(monitor_.IsUnlockAllowed()); +} + +TEST_F(ProximityAuthProximityMonitorImplTest, IsUnlockAllowed_UnknownRssi) { monitor_.Start(); + ProvideConnectionInfo({0, 0, 4}); + ProvideConnectionInfo({BluetoothDevice::kUnknownPower, 0, 4}); + EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); } TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_InformsObserverOfChanges) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER); - + IsUnlockAllowed_InformsObserverOfChanges) { // Initially, the device is not in proximity. monitor_.Start(); EXPECT_FALSE(monitor_.IsUnlockAllowed()); - // Simulate a reading indicating proximity. + // Simulate receiving an RSSI reading in proximity. EXPECT_CALL(observer_, OnProximityStateChanged()).Times(1); - ProvideConnectionInfo({0, 0, 4}); + ProvideConnectionInfo({kRssiThreshold / 2, 4, 4}); EXPECT_TRUE(monitor_.IsUnlockAllowed()); // Simulate a reading indicating non-proximity. EXPECT_CALL(observer_, OnProximityStateChanged()).Times(1); - ProvideConnectionInfo({0, 4, 4}); + ProvideConnectionInfo({2 * kRssiThreshold, 4, 4}); + ProvideConnectionInfo({2 * kRssiThreshold, 4, 4}); EXPECT_FALSE(monitor_.IsUnlockAllowed()); } -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckRssi_RssiIndicatesProximity_TxPowerDoesNot) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); +TEST_F(ProximityAuthProximityMonitorImplTest, IsUnlockAllowed_StartThenStop) { monitor_.Start(); - ProvideConnectionInfo({0, 4, 4}); - + ProvideConnectionInfo({0, 0, 4}); EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); -} -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckRssi_TxPowerIndicatesProximity_RssiDoesNot) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - monitor_.Start(); - - ProvideConnectionInfo({-10, 0, 4}); - - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckRssi_NeitherRssiNorTxPowerIndicatesProximity) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - monitor_.Start(); - - ProvideConnectionInfo({-10, 4, 4}); - - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckRssi_BothRssiAndTxPowerIndicateProximity) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - monitor_.Start(); - - ProvideConnectionInfo({0, 0, 4}); - - EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckRssi_UnknownRssi) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - monitor_.Start(); - - ProvideConnectionInfo({0, 0, 4}); - ProvideConnectionInfo({BluetoothDevice::kUnknownPower, 0, 4}); - - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckRssi_UnknownTxPower) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - monitor_.Start(); - - ProvideConnectionInfo({0, 0, 4}); - ProvideConnectionInfo({0, BluetoothDevice::kUnknownPower, 4}); - - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckRssi_UnknownMaxTxPower) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - monitor_.Start(); - - ProvideConnectionInfo({0, 0, 4}); - ProvideConnectionInfo({0, 0, BluetoothDevice::kUnknownPower}); - - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckTxPower_RssiIndicatesProximity_TxPowerDoesNot) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER); - monitor_.Start(); - - ProvideConnectionInfo({0, 4, 4}); - - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckTxPower_TxPowerIndicatesProximity_RssiDoesNot) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER); - monitor_.Start(); - - ProvideConnectionInfo({-10, 0, 4}); - - EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckTxPower_NeitherRssiNorTxPowerIndicatesProximity) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER); - monitor_.Start(); - - ProvideConnectionInfo({-10, 4, 4}); - - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckTxPower_BothRssiAndTxPowerIndicateProximity) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER); - monitor_.Start(); - - ProvideConnectionInfo({0, 0, 4}); - - EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckTxPower_UnknownRssi) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER); - monitor_.Start(); - - ProvideConnectionInfo({0, 0, 4}); - ProvideConnectionInfo({BluetoothDevice::kUnknownPower, 0, 4}); - - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckTxPower_UnknownTxPower) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER); - monitor_.Start(); - - ProvideConnectionInfo({0, 0, 4}); - ProvideConnectionInfo({0, BluetoothDevice::kUnknownPower, 4}); - - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_CheckTxPower_UnknownMaxTxPower) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER); - monitor_.Start(); - - ProvideConnectionInfo({0, 0, 4}); - ProvideConnectionInfo({0, 0, BluetoothDevice::kUnknownPower}); - - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); -} - -TEST_F(ProximityAuthProximityMonitorImplTest, ProximityState_StartThenStop) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - - monitor_.Start(); - ProvideConnectionInfo({0, 0, 4}); monitor_.Stop(); - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); } TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_StartThenStopThenStartAgain) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - + IsUnlockAllowed_StartThenStopThenStartAgain) { monitor_.Start(); - ProvideConnectionInfo({-10, 4, 4}); - ProvideConnectionInfo({-10, 4, 4}); - ProvideConnectionInfo({-10, 4, 4}); - ProvideConnectionInfo({-10, 4, 4}); - ProvideConnectionInfo({-10, 4, 4}); + ProvideConnectionInfo({kRssiThreshold / 2, 4, 4}); + ProvideConnectionInfo({kRssiThreshold / 2, 4, 4}); + ProvideConnectionInfo({kRssiThreshold / 2, 4, 4}); + ProvideConnectionInfo({kRssiThreshold / 2, 4, 4}); + ProvideConnectionInfo({kRssiThreshold / 2, 4, 4}); + EXPECT_TRUE(monitor_.IsUnlockAllowed()); monitor_.Stop(); // Restarting the monitor should immediately reset the proximity state, rather // than building on the previous rolling average. monitor_.Start(); - ProvideConnectionInfo({0, 4, 4}); + ProvideConnectionInfo({kRssiThreshold - 1, 4, 4}); - EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); + EXPECT_FALSE(monitor_.IsUnlockAllowed()); } TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_RemoteDeviceRemainsInProximity) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - + IsUnlockAllowed_RemoteDeviceRemainsInProximity) { monitor_.Start(); - ProvideConnectionInfo({0, 4, 4}); - ProvideConnectionInfo({-1, 4, 4}); - ProvideConnectionInfo({0, 4, 4}); - ProvideConnectionInfo({-2, 4, 4}); - ProvideConnectionInfo({-1, 4, 4}); + ProvideConnectionInfo({kRssiThreshold / 2 + 1, 4, 4}); + ProvideConnectionInfo({kRssiThreshold / 2 - 1, 4, 4}); + ProvideConnectionInfo({kRssiThreshold / 2 + 2, 4, 4}); + ProvideConnectionInfo({kRssiThreshold / 2 - 3, 4, 4}); EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); // Brief drops in RSSI should be handled by weighted averaging. - ProvideConnectionInfo({-10, 4, 4}); + ProvideConnectionInfo({kRssiThreshold - 5, 4, 4}); EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); } TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_RemoteDeviceLeavesProximity) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); + IsUnlockAllowed_RemoteDeviceLeavesProximity) { monitor_.Start(); // Start with a device in proximity. ProvideConnectionInfo({0, 4, 4}); EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); // Simulate readings for the remote device leaving proximity. ProvideConnectionInfo({-1, 4, 4}); ProvideConnectionInfo({-4, 4, 4}); ProvideConnectionInfo({0, 4, 4}); ProvideConnectionInfo({-10, 4, 4}); - ProvideConnectionInfo({-8, 4, 4}); ProvideConnectionInfo({-15, 4, 4}); - ProvideConnectionInfo({-10, 4, 4}); - ProvideConnectionInfo({-10, 4, 4}); - ProvideConnectionInfo({-10, 4, 4}); - ProvideConnectionInfo({-10, 4, 4}); + ProvideConnectionInfo({-20, 4, 4}); + ProvideConnectionInfo({kRssiThreshold, 4, 4}); + ProvideConnectionInfo({kRssiThreshold - 10, 4, 4}); + ProvideConnectionInfo({kRssiThreshold - 20, 4, 4}); + ProvideConnectionInfo({kRssiThreshold - 20, 4, 4}); EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); } TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_RemoteDeviceEntersProximity) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); + IsUnlockAllowed_RemoteDeviceEntersProximity) { monitor_.Start(); - // Start with a device in proximity. - ProvideConnectionInfo({-20, 4, 4}); + // Start with a device out of proximity. + ProvideConnectionInfo({2 * kRssiThreshold, 4, 4}); EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); // Simulate readings for the remote device entering proximity. ProvideConnectionInfo({-15, 4, 4}); @@ -448,18 +259,15 @@ ProvideConnectionInfo({0, 4, 4}); EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); } TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_DeviceNotKnownToAdapter) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); + IsUnlockAllowed_DeviceNotKnownToAdapter) { monitor_.Start(); // Start with the device known to the adapter and in proximity. ProvideConnectionInfo({0, 4, 4}); EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); // Simulate it being forgotten. ON_CALL(*bluetooth_adapter_, GetDevice(kBluetoothAddress)) @@ -468,18 +276,15 @@ RunPendingTasks(); EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); } TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_DeviceNotConnected) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); + IsUnlockAllowed_DeviceNotConnected) { monitor_.Start(); // Start with the device connected and in proximity. ProvideConnectionInfo({0, 4, 4}); EXPECT_TRUE(monitor_.IsUnlockAllowed()); - EXPECT_TRUE(monitor_.IsInRssiRange()); // Simulate it disconnecting. ON_CALL(remote_bluetooth_device_, IsConnected()).WillByDefault(Return(false)); @@ -487,19 +292,14 @@ RunPendingTasks(); EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); } TEST_F(ProximityAuthProximityMonitorImplTest, - ProximityState_ConnectionInfoReceivedAfterStopping) { - monitor_.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI); - + IsUnlockAllowed_ConnectionInfoReceivedAfterStopping) { monitor_.Start(); monitor_.Stop(); ProvideConnectionInfo({0, 4, 4}); - EXPECT_FALSE(monitor_.IsUnlockAllowed()); - EXPECT_FALSE(monitor_.IsInRssiRange()); } TEST_F(ProximityAuthProximityMonitorImplTest, @@ -516,10 +316,6 @@ histogram_tester.ExpectUniqueSample("EasyUnlock.AuthProximity.RollingRssi", -6, 1); histogram_tester.ExpectUniqueSample( - "EasyUnlock.AuthProximity.TransmitPowerDelta", -1, 1); - histogram_tester.ExpectUniqueSample( - "EasyUnlock.AuthProximity.TimeSinceLastZeroRssi", 304, 1); - histogram_tester.ExpectUniqueSample( "EasyUnlock.AuthProximity.RemoteDeviceModelHash", 1881443083 /* hash of "LGE Nexus 5" */, 1); } @@ -533,20 +329,18 @@ monitor_.RecordProximityMetricsOnAuthSuccess(); histogram_tester.ExpectUniqueSample("EasyUnlock.AuthProximity.RollingRssi", -100, 1); - histogram_tester.ExpectUniqueSample( - "EasyUnlock.AuthProximity.TransmitPowerDelta", 50, 1); } TEST_F(ProximityAuthProximityMonitorImplTest, RecordProximityMetricsOnAuthSuccess_UnknownValues) { - // Note: A device without a recorded name will have its Bluetooth address as - // its name. + // Note: A device without a recorded name will have "Unknown" as its name. cryptauth::RemoteDevice unnamed_remote_device( - kRemoteDeviceUserId, kBluetoothAddress, kRemoteDevicePublicKey, + kRemoteDeviceUserId, "" /* name */, kRemoteDevicePublicKey, kBluetoothAddress, kPersistentSymmetricKey, std::string()); + cryptauth::FakeConnection connection(unnamed_remote_device); std::unique_ptr<base::TickClock> clock(new base::SimpleTestTickClock()); - ProximityMonitorImpl monitor(unnamed_remote_device, std::move(clock)); + ProximityMonitorImpl monitor(&connection, std::move(clock)); monitor.AddObserver(&observer_); monitor.Start(); ProvideConnectionInfo({127, 127, 127}); @@ -556,11 +350,6 @@ histogram_tester.ExpectUniqueSample("EasyUnlock.AuthProximity.RollingRssi", 127, 1); histogram_tester.ExpectUniqueSample( - "EasyUnlock.AuthProximity.TransmitPowerDelta", 127, 1); - histogram_tester.ExpectUniqueSample( - "EasyUnlock.AuthProximity.TimeSinceLastZeroRssi", - base::TimeDelta::FromSeconds(10).InMilliseconds(), 1); - histogram_tester.ExpectUniqueSample( "EasyUnlock.AuthProximity.RemoteDeviceModelHash", -1808066424 /* hash of "Unknown" */, 1); }
diff --git a/components/proximity_auth/remote_device_life_cycle.h b/components/proximity_auth/remote_device_life_cycle.h index ed7f4c6..2990e95b8 100644 --- a/components/proximity_auth/remote_device_life_cycle.h +++ b/components/proximity_auth/remote_device_life_cycle.h
@@ -6,6 +6,7 @@ #define COMPONENTS_PROXIMITY_AUTH_REMOTE_DEVICE_LIFE_CYCLE_H #include "base/macros.h" +#include "components/cryptauth/connection.h" #include "components/cryptauth/remote_device.h" namespace proximity_auth { @@ -57,6 +58,9 @@ // Returns the RemoteDevice instance that this life cycle manages. virtual cryptauth::RemoteDevice GetRemoteDevice() const = 0; + // Returns the current Connection, or null if the device is not yet connected. + virtual cryptauth::Connection* GetConnection() const = 0; + // Returns the current state of in the life cycle. virtual State GetState() const = 0;
diff --git a/components/proximity_auth/remote_device_life_cycle_impl.cc b/components/proximity_auth/remote_device_life_cycle_impl.cc index 0661088b..54e4b71f 100644 --- a/components/proximity_auth/remote_device_life_cycle_impl.cc +++ b/components/proximity_auth/remote_device_life_cycle_impl.cc
@@ -62,6 +62,14 @@ return remote_device_; } +cryptauth::Connection* RemoteDeviceLifeCycleImpl::GetConnection() const { + if (connection_) + return connection_.get(); + if (messenger_) + return messenger_->GetConnection(); + return nullptr; +} + RemoteDeviceLifeCycle::State RemoteDeviceLifeCycleImpl::GetState() const { return state_; }
diff --git a/components/proximity_auth/remote_device_life_cycle_impl.h b/components/proximity_auth/remote_device_life_cycle_impl.h index 2bc82767..4df1973 100644 --- a/components/proximity_auth/remote_device_life_cycle_impl.h +++ b/components/proximity_auth/remote_device_life_cycle_impl.h
@@ -41,6 +41,7 @@ // RemoteDeviceLifeCycle: void Start() override; cryptauth::RemoteDevice GetRemoteDevice() const override; + cryptauth::Connection* GetConnection() const override; RemoteDeviceLifeCycle::State GetState() const override; Messenger* GetMessenger() override; void AddObserver(Observer* observer) override;
diff --git a/components/proximity_auth/unlock_manager_impl.cc b/components/proximity_auth/unlock_manager_impl.cc index 19babab..2d8b30b 100644 --- a/components/proximity_auth/unlock_manager_impl.cc +++ b/components/proximity_auth/unlock_manager_impl.cc
@@ -141,7 +141,6 @@ life_cycle_ = life_cycle; if (life_cycle_) { - proximity_monitor_ = CreateProximityMonitor(life_cycle->GetRemoteDevice()); SetWakingUpState(true); } else { proximity_monitor_.reset(); @@ -156,8 +155,12 @@ << static_cast<int>(state); remote_screenlock_state_.reset(); - if (state == RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) + if (state == RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) { + DCHECK(life_cycle_->GetConnection()); + DCHECK(GetMessenger()); + proximity_monitor_ = CreateProximityMonitor(life_cycle_->GetConnection()); GetMessenger()->AddObserver(this); + } if (state == RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED) SetWakingUpState(false); @@ -320,9 +323,9 @@ } std::unique_ptr<ProximityMonitor> UnlockManagerImpl::CreateProximityMonitor( - const cryptauth::RemoteDevice& remote_device) { + cryptauth::Connection* connection) { return base::MakeUnique<ProximityMonitorImpl>( - remote_device, base::WrapUnique(new base::DefaultTickClock())); + connection, base::WrapUnique(new base::DefaultTickClock())); } void UnlockManagerImpl::SendSignInChallenge() { @@ -356,7 +359,10 @@ RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED) return ScreenlockState::PHONE_NOT_AUTHENTICATED; - if (is_waking_up_) + if (is_waking_up_ || + life_cycle_->GetState() == RemoteDeviceLifeCycle::State::AUTHENTICATING || + life_cycle_->GetState() == + RemoteDeviceLifeCycle::State::FINDING_CONNECTION) return ScreenlockState::BLUETOOTH_CONNECTING; if (!bluetooth_adapter_ || !bluetooth_adapter_->IsPowered()) @@ -370,8 +376,7 @@ // If the RSSI is too low, then the remote device is nowhere near the local // device. This message should take priority over messages about screen lock // states. - if (!proximity_monitor_->IsUnlockAllowed() && - !proximity_monitor_->IsInRssiRange()) + if (!proximity_monitor_->IsUnlockAllowed()) return ScreenlockState::RSSI_TOO_LOW; if (remote_screenlock_state_) { @@ -380,11 +385,6 @@ return ScreenlockState::PHONE_NOT_LOCKABLE; case RemoteScreenlockState::LOCKED: - if (proximity_monitor_->GetStrategy() == - ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER && - !proximity_monitor_->IsUnlockAllowed()) { - return ScreenlockState::PHONE_LOCKED_AND_TX_POWER_TOO_HIGH; - } return ScreenlockState::PHONE_LOCKED; case RemoteScreenlockState::UNKNOWN: @@ -396,18 +396,6 @@ } } - if (!proximity_monitor_->IsUnlockAllowed()) { - ProximityMonitor::Strategy strategy = proximity_monitor_->GetStrategy(); - if (strategy != ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER) { - // CHECK_RSSI should have been handled above, and no other states should - // prevent unlocking. - PA_LOG(ERROR) << "[Unlock] Invalid ProximityMonitor strategy: " - << static_cast<int>(strategy); - return ScreenlockState::NO_PHONE; - } - return ScreenlockState::TX_POWER_TOO_HIGH; - } - return ScreenlockState::NO_PHONE; }
diff --git a/components/proximity_auth/unlock_manager_impl.h b/components/proximity_auth/unlock_manager_impl.h index 3e1c03c..104f01b 100644 --- a/components/proximity_auth/unlock_manager_impl.h +++ b/components/proximity_auth/unlock_manager_impl.h
@@ -52,10 +52,10 @@ ScreenlockBridge::LockHandler::AuthType auth_type) override; protected: - // Creates a ProximityMonitor instance for the given |remote_device|. + // Creates a ProximityMonitor instance for the given |connection|. // Exposed for testing. virtual std::unique_ptr<ProximityMonitor> CreateProximityMonitor( - const cryptauth::RemoteDevice& remote_device); + cryptauth::Connection* connection); private: // The possible lock screen states for the remote device.
diff --git a/components/proximity_auth/unlock_manager_impl_unittest.cc b/components/proximity_auth/unlock_manager_impl_unittest.cc index 6dec288b..004ae9d 100644 --- a/components/proximity_auth/unlock_manager_impl_unittest.cc +++ b/components/proximity_auth/unlock_manager_impl_unittest.cc
@@ -13,9 +13,11 @@ #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "components/cryptauth/cryptauth_test_util.h" +#include "components/cryptauth/fake_connection.h" #include "components/cryptauth/fake_secure_context.h" #include "components/cryptauth/secure_context.h" #include "components/proximity_auth/fake_lock_handler.h" +#include "components/proximity_auth/fake_remote_device_life_cycle.h" #include "components/proximity_auth/logging/logging.h" #include "components/proximity_auth/messenger.h" #include "components/proximity_auth/mock_proximity_auth_client.h" @@ -66,6 +68,7 @@ MOCK_CONST_METHOD0(GetRemoteDevice, cryptauth::RemoteDevice()); MOCK_CONST_METHOD0(GetState, State()); MOCK_METHOD0(GetMessenger, Messenger*()); + MOCK_CONST_METHOD0(GetConnection, cryptauth::Connection*()); MOCK_METHOD1(AddObserver, void(Observer*)); MOCK_METHOD1(RemoveObserver, void(Observer*)); }; @@ -82,6 +85,7 @@ MOCK_METHOD1(RequestDecryption, void(const std::string& challenge)); MOCK_METHOD0(RequestUnlock, void()); MOCK_CONST_METHOD0(GetSecureContext, cryptauth::SecureContext*()); + MOCK_CONST_METHOD0(GetConnection, cryptauth::Connection*()); private: DISALLOW_COPY_AND_ASSIGN(MockMessenger); @@ -89,24 +93,25 @@ class MockProximityMonitor : public ProximityMonitor { public: - MockProximityMonitor() { - ON_CALL(*this, GetStrategy()) - .WillByDefault(Return(ProximityMonitor::Strategy::NONE)); + MockProximityMonitor() : started_(false), stopped_(false) { ON_CALL(*this, IsUnlockAllowed()).WillByDefault(Return(true)); - ON_CALL(*this, IsInRssiRange()).WillByDefault(Return(false)); } ~MockProximityMonitor() override {} - MOCK_METHOD0(Start, void()); - MOCK_METHOD0(Stop, void()); - MOCK_CONST_METHOD0(GetStrategy, Strategy()); + void Start() override { started_ = true; } + void Stop() override { stopped_ = true; } MOCK_CONST_METHOD0(IsUnlockAllowed, bool()); - MOCK_CONST_METHOD0(IsInRssiRange, bool()); MOCK_METHOD0(RecordProximityMetricsOnAuthSuccess, void()); MOCK_METHOD1(AddObserver, void(ProximityMonitorObserver*)); MOCK_METHOD1(RemoveObserver, void(ProximityMonitorObserver*)); + bool started() { return started_; } + bool stopped() { return stopped_; } + private: + bool started_; + bool stopped_; + DISALLOW_COPY_AND_ASSIGN(MockProximityMonitor); }; @@ -132,8 +137,9 @@ private: std::unique_ptr<ProximityMonitor> CreateProximityMonitor( - const cryptauth::RemoteDevice& remote_device) override { - EXPECT_EQ(cryptauth::kTestRemoteDevicePublicKey, remote_device.public_key); + cryptauth::Connection* connection) override { + EXPECT_EQ(cryptauth::kTestRemoteDevicePublicKey, + connection->remote_device().public_key); std::unique_ptr<MockProximityMonitor> proximity_monitor( new NiceMock<MockProximityMonitor>()); proximity_monitor_ = proximity_monitor.get(); @@ -162,17 +168,18 @@ public: ProximityAuthUnlockManagerImplTest() : remote_device_(cryptauth::CreateClassicRemoteDeviceForTest()), + life_cycle_(remote_device_), + connection_(remote_device_), bluetooth_adapter_(CreateAndRegisterMockBluetoothAdapter()), task_runner_(new base::TestSimpleTaskRunner()), thread_task_runner_handle_(task_runner_) { ON_CALL(*bluetooth_adapter_, IsPowered()).WillByDefault(Return(true)); - ON_CALL(life_cycle_, GetMessenger()).WillByDefault(Return(&messenger_)); - ON_CALL(life_cycle_, GetRemoteDevice()) - .WillByDefault(Return(remote_device_)); ON_CALL(messenger_, SupportsSignIn()).WillByDefault(Return(true)); ON_CALL(messenger_, GetSecureContext()) .WillByDefault(Return(&secure_context_)); + life_cycle_.set_connection(&connection_); + life_cycle_.set_messenger(&messenger_); ScreenlockBridge::Get()->SetLockHandler(&lock_handler_); #if defined(OS_CHROMEOS) @@ -207,15 +214,10 @@ } void SimulateUserPresentState() { - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::STOPPED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); - - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); unlock_manager_->OnLifeCycleStateChanged(); - unlock_manager_->OnRemoteStatusUpdate(kRemoteScreenUnlocked); } @@ -227,12 +229,13 @@ protected: cryptauth::RemoteDevice remote_device_; + FakeRemoteDeviceLifeCycle life_cycle_; + cryptauth::FakeConnection connection_; // Mock used for verifying interactions with the Bluetooth subsystem. scoped_refptr<device::MockBluetoothAdapter> bluetooth_adapter_; NiceMock<MockProximityAuthClient> proximity_auth_client_; - NiceMock<MockRemoteDeviceLifeCycle> life_cycle_; NiceMock<MockMessenger> messenger_; std::unique_ptr<TestUnlockManager> unlock_manager_; cryptauth::FakeSecureContext secure_context_; @@ -253,10 +256,10 @@ IsUnlockAllowed_SessionLock_AllGood) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); + unlock_manager_->OnLifeCycleStateChanged(); unlock_manager_->OnRemoteStatusUpdate(kRemoteScreenUnlocked); EXPECT_TRUE(unlock_manager_->IsUnlockAllowed()); @@ -264,14 +267,10 @@ TEST_F(ProximityAuthUnlockManagerImplTest, IsUnlockAllowed_SignIn_AllGood) { CreateUnlockManager(ProximityAuthSystem::SIGN_IN); - - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::STOPPED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); unlock_manager_->OnLifeCycleStateChanged(); ON_CALL(messenger_, SupportsSignIn()).WillByDefault(Return(true)); @@ -283,14 +282,10 @@ TEST_F(ProximityAuthUnlockManagerImplTest, IsUnlockAllowed_SignIn_MessengerDoesNotSupportSignIn) { CreateUnlockManager(ProximityAuthSystem::SIGN_IN); - - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::STOPPED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); unlock_manager_->OnLifeCycleStateChanged(); ON_CALL(messenger_, SupportsSignIn()).WillByDefault(Return(false)); @@ -300,30 +295,16 @@ } TEST_F(ProximityAuthUnlockManagerImplTest, - IsUnlockAllowed_SignIn_MessengerIsNull) { - CreateUnlockManager(ProximityAuthSystem::SIGN_IN); - - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); - ON_CALL(life_cycle_, GetMessenger()).WillByDefault(Return(nullptr)); - unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); - unlock_manager_->OnRemoteStatusUpdate(kRemoteScreenUnlocked); - - EXPECT_FALSE(unlock_manager_->IsUnlockAllowed()); -} - -TEST_F(ProximityAuthUnlockManagerImplTest, IsUnlockAllowed_DisallowedByProximityMonitor) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); - unlock_manager_->OnRemoteStatusUpdate(kRemoteScreenUnlocked); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); + unlock_manager_->OnLifeCycleStateChanged(); ON_CALL(*proximity_monitor(), IsUnlockAllowed()).WillByDefault(Return(false)); + unlock_manager_->OnRemoteStatusUpdate(kRemoteScreenUnlocked); EXPECT_FALSE(unlock_manager_->IsUnlockAllowed()); } @@ -331,9 +312,9 @@ IsUnlockAllowed_SecureChannelNotEstablished) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::AUTHENTICATING)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::AUTHENTICATING); + unlock_manager_->OnLifeCycleStateChanged(); unlock_manager_->OnRemoteStatusUpdate(kRemoteScreenUnlocked); EXPECT_FALSE(unlock_manager_->IsUnlockAllowed()); @@ -353,10 +334,10 @@ IsUnlockAllowed_RemoteScreenlockStateLocked) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); + unlock_manager_->OnLifeCycleStateChanged(); unlock_manager_->OnRemoteStatusUpdate(kRemoteScreenLocked); EXPECT_FALSE(unlock_manager_->IsUnlockAllowed()); @@ -366,10 +347,10 @@ IsUnlockAllowed_RemoteScreenlockStateUnknown) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); + unlock_manager_->OnLifeCycleStateChanged(); unlock_manager_->OnRemoteStatusUpdate(kRemoteScreenlockStateUnknown); EXPECT_FALSE(unlock_manager_->IsUnlockAllowed()); @@ -379,10 +360,10 @@ IsUnlockAllowed_RemoteScreenlockStateDisabled) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); + unlock_manager_->OnLifeCycleStateChanged(); unlock_manager_->OnRemoteStatusUpdate(kRemoteScreenlockDisabled); EXPECT_FALSE(unlock_manager_->IsUnlockAllowed()); @@ -392,10 +373,10 @@ IsUnlockAllowed_RemoteScreenlockStateNotYetReceived) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); + unlock_manager_->OnLifeCycleStateChanged(); EXPECT_FALSE(unlock_manager_->IsUnlockAllowed()); } @@ -419,29 +400,14 @@ } TEST_F(ProximityAuthUnlockManagerImplTest, - SetRemoteDeviceLifeCycle_NullThenExistingRemoteDeviceLifeCycle) { - CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - SimulateUserPresentState(); - - EXPECT_CALL(proximity_auth_client_, - UpdateScreenlockState(ScreenlockState::INACTIVE)); - unlock_manager_->SetRemoteDeviceLifeCycle(nullptr); - - EXPECT_CALL(proximity_auth_client_, - UpdateScreenlockState(ScreenlockState::AUTHENTICATED)); - unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); -} - -TEST_F(ProximityAuthUnlockManagerImplTest, SetRemoteDeviceLifeCycle_AuthenticationFailed) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); SimulateUserPresentState(); unlock_manager_->SetRemoteDeviceLifeCycle(nullptr); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED)); + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED); + EXPECT_CALL(proximity_auth_client_, UpdateScreenlockState(ScreenlockState::PHONE_NOT_AUTHENTICATED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); @@ -453,8 +419,8 @@ unlock_manager_->SetRemoteDeviceLifeCycle(nullptr); - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::FINDING_CONNECTION)); + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::FINDING_CONNECTION); + EXPECT_CALL(proximity_auth_client_, UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); @@ -473,27 +439,23 @@ CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); SimulateUserPresentState(); - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::FINDING_CONNECTION)); - - EXPECT_CALL(*proximity_monitor(), Stop()).Times(AtLeast(1)); unlock_manager_->OnLifeCycleStateChanged(); + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::FINDING_CONNECTION); + unlock_manager_->OnLifeCycleStateChanged(); + EXPECT_TRUE(proximity_monitor()->stopped()); } TEST_F( ProximityAuthUnlockManagerImplTest, SetRemoteDeviceLifeCycle_ConnectedRemoteDeviceLifeCycle_StartsProximityMonitor) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::STOPPED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); - EXPECT_CALL(*proximity_monitor(), Start()).Times(AtLeast(1)); unlock_manager_->OnLifeCycleStateChanged(); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); + unlock_manager_->OnLifeCycleStateChanged(); + EXPECT_TRUE(proximity_monitor()->started()); } TEST_F(ProximityAuthUnlockManagerImplTest, @@ -508,7 +470,7 @@ OnLifeCycleStateChanged_StartsProximityMonitor) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); SimulateUserPresentState(); - EXPECT_CALL(*proximity_monitor(), Start()).Times(AtLeast(1)); + EXPECT_TRUE(proximity_monitor()->started()); unlock_manager_->OnLifeCycleStateChanged(); } @@ -517,12 +479,10 @@ CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); SimulateUserPresentState(); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED)); - - EXPECT_CALL(*proximity_monitor(), Stop()).Times(AtLeast(1)); unlock_manager_->OnLifeCycleStateChanged(); + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED); + unlock_manager_->OnLifeCycleStateChanged(); + EXPECT_TRUE(proximity_monitor()->stopped()); } TEST_F(ProximityAuthUnlockManagerImplTest, @@ -530,11 +490,9 @@ CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); SimulateUserPresentState(); - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::STOPPED)); - EXPECT_CALL(proximity_auth_client_, UpdateScreenlockState(ScreenlockState::INACTIVE)); + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::STOPPED); unlock_manager_->OnLifeCycleStateChanged(); } @@ -543,44 +501,31 @@ CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); SimulateUserPresentState(); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED)); - EXPECT_CALL(proximity_auth_client_, UpdateScreenlockState(ScreenlockState::PHONE_NOT_AUTHENTICATED)); + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED); unlock_manager_->OnLifeCycleStateChanged(); } TEST_F(ProximityAuthUnlockManagerImplTest, OnLifeCycleStateChanged_FindingConnection_UpdatesScreenlockState) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::STOPPED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::FINDING_CONNECTION)); - EXPECT_CALL(proximity_auth_client_, UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING)); + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::FINDING_CONNECTION); unlock_manager_->OnLifeCycleStateChanged(); } TEST_F(ProximityAuthUnlockManagerImplTest, OnLifeCycleStateChanged_Authenticating_UpdatesScreenlockState) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::STOPPED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::AUTHENTICATING)); - EXPECT_CALL(proximity_auth_client_, UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING)); + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::AUTHENTICATING); unlock_manager_->OnLifeCycleStateChanged(); } @@ -588,17 +533,12 @@ ProximityAuthUnlockManagerImplTest, OnLifeCycleStateChanged_SecureChannelEstablished_UpdatesScreenlockState) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::STOPPED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); - EXPECT_CALL(proximity_auth_client_, UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING)); + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); unlock_manager_->OnLifeCycleStateChanged(); } @@ -606,10 +546,8 @@ OnDisconnected_UnregistersAsObserver) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); SimulateUserPresentState(); - - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED)); + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED); + unlock_manager_->OnLifeCycleStateChanged(); EXPECT_CALL(messenger_, RemoveObserver(unlock_manager_.get())) .Times(testing::AtLeast(1)); @@ -622,27 +560,23 @@ CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); SimulateUserPresentState(); - EXPECT_CALL(*proximity_monitor(), Stop()); unlock_manager_.get()->OnScreenDidUnlock( ScreenlockBridge::LockHandler::LOCK_SCREEN); + EXPECT_TRUE(proximity_monitor()->stopped()); } TEST_F(ProximityAuthUnlockManagerImplTest, OnScreenDidLock_StartsProximityMonitor) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); - - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::STOPPED)); unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); - ON_CALL(life_cycle_, GetState()) - .WillByDefault( - Return(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED)); - unlock_manager_->OnLifeCycleStateChanged(); - - EXPECT_CALL(*proximity_monitor(), Start()); unlock_manager_.get()->OnScreenDidLock( ScreenlockBridge::LockHandler::LOCK_SCREEN); + + life_cycle_.ChangeState( + RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED); + unlock_manager_->OnLifeCycleStateChanged(); + EXPECT_TRUE(proximity_monitor()->started()); } TEST_F(ProximityAuthUnlockManagerImplTest, OnScreenDidLock_SetsWakingUpState) { @@ -652,14 +586,11 @@ unlock_manager_.get()->OnScreenDidUnlock( ScreenlockBridge::LockHandler::LOCK_SCREEN); - ON_CALL(life_cycle_, GetState()) - .WillByDefault(Return(RemoteDeviceLifeCycle::State::FINDING_CONNECTION)); - unlock_manager_->OnLifeCycleStateChanged(); - EXPECT_CALL(proximity_auth_client_, UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING)); - unlock_manager_.get()->OnScreenDidLock( - ScreenlockBridge::LockHandler::LOCK_SCREEN); + + life_cycle_.ChangeState(RemoteDeviceLifeCycle::State::FINDING_CONNECTION); + unlock_manager_->OnLifeCycleStateChanged(); } TEST_F(ProximityAuthUnlockManagerImplTest,
diff --git a/components/ui_devtools/string_util.h b/components/ui_devtools/string_util.h index 4efb8353..d08b8b6f 100644 --- a/components/ui_devtools/string_util.h +++ b/components/ui_devtools/string_util.h
@@ -45,6 +45,11 @@ static String fromDouble(double number) { return base::DoubleToString(number); } + static double toDouble(const char* s, size_t len, bool* ok) { + double v = 0.0; + *ok = base::StringToDouble(std::string(s, len), &v); + return *ok ? v : 0.0; + } static void builderAppend(StringBuilder& builder, const String& s) { builder.append(s); }
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index f79636db..d4bc3f8 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc
@@ -398,7 +398,7 @@ return rwhva->GetCachedBackgroundColor(); } -// All positions and sizes are in CSS pixels. +// All positions and sizes (except |top_shown_pix|) are in CSS pixels. // Note that viewport_width/height is a best effort based. // ContentViewCore has the actual information about the physical viewport size. void ContentViewCoreImpl::UpdateFrameInfo( @@ -407,16 +407,16 @@ const gfx::Vector2dF& page_scale_factor_limits, const gfx::SizeF& content_size, const gfx::SizeF& viewport_size, - const float top_controls_height, - const float top_controls_shown_ratio, + const float content_offset, + const float top_shown_pix, + bool top_changed, bool is_mobile_optimized_hint) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); if (obj.is_null() || !GetWindowAndroid()) return; - GetViewAndroid()->set_content_offset( - gfx::Vector2dF(0.0f, top_controls_height * top_controls_shown_ratio)); + GetViewAndroid()->set_content_offset(gfx::Vector2dF(0.0f, content_offset)); page_scale_ = page_scale_factor; @@ -424,7 +424,7 @@ env, obj, scroll_offset.x(), scroll_offset.y(), page_scale_factor, page_scale_factor_limits.x(), page_scale_factor_limits.y(), content_size.width(), content_size.height(), viewport_size.width(), - viewport_size.height(), top_controls_height, top_controls_shown_ratio, + viewport_size.height(), top_shown_pix, top_changed, is_mobile_optimized_hint); }
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index f4a2fef..edefe59 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h
@@ -252,14 +252,16 @@ // Hides a visible popup menu. void HideSelectPopupMenu(); - // All sizes and offsets are in CSS pixels as cached by the renderer. + // All sizes and offsets are in CSS pixels (except |top_show_pix|) + // as cached by the renderer. void UpdateFrameInfo(const gfx::Vector2dF& scroll_offset, float page_scale_factor, const gfx::Vector2dF& page_scale_factor_limits, const gfx::SizeF& content_size, const gfx::SizeF& viewport_size, - const float top_controls_height, - const float top_controls_shown_ratio, + const float content_offset, + const float top_shown_pix, + bool top_changed, bool is_mobile_optimized_hint); bool HasFocus();
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc index f86207f9..111d755 100644 --- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc +++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -959,6 +959,25 @@ EXPECT_EQ(0u, notifications_.size()); } +IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, CrossSiteCrash) { + set_agent_host_can_close(); + host_resolver()->AddRule("*", "127.0.0.1"); + content::SetupCrossSiteRedirector(embedded_test_server()); + ASSERT_TRUE(embedded_test_server()->Start()); + + GURL test_url1 = + embedded_test_server()->GetURL("A.com", "/devtools/navigation.html"); + NavigateToURLBlockUntilNavigationsComplete(shell(), test_url1, 1); + Attach(); + CrashTab(shell()->web_contents()); + + GURL test_url2 = + embedded_test_server()->GetURL("B.com", "/devtools/navigation.html"); + NavigateToURLBlockUntilNavigationsComplete(shell(), test_url2, 1); + + // Should not crash at this point. +} + IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, ReconnectPreservesState) { ASSERT_TRUE(embedded_test_server()->Start()); GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html");
diff --git a/content/browser/devtools/protocol_string.h b/content/browser/devtools/protocol_string.h index 90dbd4ab..38dd03e4 100644 --- a/content/browser/devtools/protocol_string.h +++ b/content/browser/devtools/protocol_string.h
@@ -52,6 +52,11 @@ s = "0" + s; return s; } + static double toDouble(const char* s, size_t len, bool* ok) { + double v = 0.0; + *ok = base::StringToDouble(std::string(s, len), &v); + return *ok ? v : 0.0; + } static size_t find(const String& s, const char* needle) { return s.find(needle); }
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc index 204903c3..1a6be75 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.cc +++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -762,7 +762,7 @@ if (session()) protocol::TargetHandler::FromSession(session())->UpdateFrames(); - if (IsBrowserSideNavigationEnabled()) + if (IsBrowserSideNavigationEnabled() && !current_frame_crashed_) return; DCHECK(!pending_ || pending_->host() != old_host);
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 9f6cba6..03367bc 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1429,8 +1429,9 @@ gfx::Vector2dF(frame_metadata.min_page_scale_factor, frame_metadata.max_page_scale_factor), frame_metadata.root_layer_size, frame_metadata.scrollable_viewport_size, - frame_metadata.top_controls_height, - frame_metadata.top_controls_shown_ratio, is_mobile_optimized); + frame_metadata.top_controls_height * + frame_metadata.top_controls_shown_ratio, + top_shown_pix, top_changed, is_mobile_optimized); } void RenderWidgetHostViewAndroid::ShowInternal() {
diff --git a/content/browser/resources/gpu/info_view.js b/content/browser/resources/gpu/info_view.js index e54cc17..d124ac1 100644 --- a/content/browser/resources/gpu/info_view.js +++ b/content/browser/resources/gpu/info_view.js
@@ -38,10 +38,6 @@ if (browserBridge.clientInfo) { var clientInfo = browserBridge.clientInfo; - var commandLineParts = clientInfo.command_line.split(' '); - commandLineParts.shift(); // Pop off the exe path - var commandLineString = commandLineParts.join(' ') - this.setTable_('client-info', [ { description: 'Data exported', @@ -72,8 +68,8 @@ value: clientInfo.graphics_backend }, { - description: 'Command Line Args', - value: commandLineString + description: 'Command Line', + value: clientInfo.command_line }]); } else { this.setText_('client-info', '... loading...');
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc index 0bd18de1..2eaab7a4 100644 --- a/content/browser/tracing/tracing_controller_impl.cc +++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -837,9 +837,23 @@ metadata_dict->SetString("user-agent", GetContentClient()->GetUserAgent()); // OS +#if defined(OS_CHROMEOS) + metadata_dict->SetString("os-name", "CrOS"); + int32_t major_version; + int32_t minor_version; + int32_t bugfix_version; + // OperatingSystemVersion only has a POSIX implementation which returns the + // wrong versions for CrOS. + base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version, + &bugfix_version); + metadata_dict->SetString( + "os-version", base::StringPrintf("%d.%d.%d", major_version, minor_version, + bugfix_version)); +#else metadata_dict->SetString("os-name", base::SysInfo::OperatingSystemName()); metadata_dict->SetString("os-version", base::SysInfo::OperatingSystemVersion()); +#endif metadata_dict->SetString("os-arch", base::SysInfo::OperatingSystemArchitecture());
diff --git a/content/browser/webui/url_data_manager_backend.cc b/content/browser/webui/url_data_manager_backend.cc index 247fc00..3a7431f 100644 --- a/content/browser/webui/url_data_manager_backend.cc +++ b/content/browser/webui/url_data_manager_backend.cc
@@ -145,7 +145,6 @@ void Kill() override; int ReadRawData(net::IOBuffer* buf, int buf_size) override; bool GetMimeType(std::string* mime_type) const override; - int GetResponseCode() const override; void GetResponseInfo(net::HttpResponseInfo* info) override; std::unique_ptr<net::SourceStream> SetUpSourceStream() override; @@ -358,10 +357,6 @@ return !mime_type_.empty(); } -int URLRequestChromeJob::GetResponseCode() const { - return net::HTTP_OK; -} - void URLRequestChromeJob::GetResponseInfo(net::HttpResponseInfo* info) { DCHECK(!info->headers.get()); // Set the headers so that requests serviced by ChromeURLDataManager return a
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index d7b13a1..1eada46 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -426,7 +426,6 @@ "javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java", "javatests/src/org/chromium/content/browser/JavaBridgeTestBase.java", "javatests/src/org/chromium/content/browser/JavaBridgeTestCommon.java", - "javatests/src/org/chromium/content/browser/LocationProviderTest.java", "javatests/src/org/chromium/content/browser/MediaResourceGetterTest.java", "javatests/src/org/chromium/content/browser/MediaSessionTest.java", "javatests/src/org/chromium/content/browser/NavigationTest.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 3de174c..6c35e91 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -1576,9 +1576,8 @@ @CalledByNative private void updateFrameInfo(float scrollOffsetX, float scrollOffsetY, float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor, float contentWidth, - float contentHeight, float viewportWidth, float viewportHeight, - float browserControlsHeightDp, float browserControlsShownRatio, - boolean isMobileOptimizedHint) { + float contentHeight, float viewportWidth, float viewportHeight, float topBarShownPix, + boolean topBarChanged, boolean isMobileOptimizedHint) { TraceEvent.begin("ContentViewCore:updateFrameInfo"); mIsMobileOptimizedHint = isMobileOptimizedHint; // Adjust contentWidth/Height to be always at least as big as @@ -1588,8 +1587,6 @@ mViewportWidthPix / (deviceScale * pageScaleFactor)); contentHeight = Math.max(contentHeight, mViewportHeightPix / (deviceScale * pageScaleFactor)); - final float topBarShownPix = - browserControlsHeightDp * deviceScale * browserControlsShownRatio; final boolean contentSizeChanged = contentWidth != mRenderCoordinates.getContentWidthCss() @@ -1603,8 +1600,6 @@ pageScaleChanged || scrollOffsetX != mRenderCoordinates.getScrollX() || scrollOffsetY != mRenderCoordinates.getScrollY(); - final boolean topBarChanged = Float.compare(topBarShownPix, - mRenderCoordinates.getContentOffsetYPix()) != 0; final boolean needHidePopupZoomer = contentSizeChanged || scrollChanged;
diff --git a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java index 2067654..df43628 100644 --- a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java +++ b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
@@ -455,6 +455,8 @@ mActionMenuDescriptor = createActionMenuDescriptor(); mActionMenuDescriptor.apply(menu); + if (isInsertion() || isSelectionPassword()) return; + initializeTextProcessingMenu(menu); } @@ -857,15 +859,7 @@ mSelectionRect.set(left, top, right, bottom); mHasSelection = true; mUnselectAllOnDismiss = true; - // When this event comes as the result of SelectAll, SelectionClient should not - // change the selection range (http://crbug.com/714106). We assume that two or - // more selected words means SelectAll. - // TODO(amaralp): Find a better way to know that SELECTION_HANDLES_SHOWN was - // caused by SelectAll. - boolean oneWordSelected = - !getSelectedText().isEmpty() && !getSelectedText().matches(".*\\s+.*"); - if (!oneWordSelected || mSelectionClient == null - || !mSelectionClient.sendsSelectionPopupUpdates()) { + if (mSelectionClient == null || !mSelectionClient.sendsSelectionPopupUpdates()) { showActionModeOrClearOnFailure(); } else { // Rely on |mSelectionClient| sending a classification request and the request
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/LocationProviderTest.java b/content/public/android/javatests/src/org/chromium/content/browser/LocationProviderTest.java deleted file mode 100644 index c74b604..0000000 --- a/content/public/android/javatests/src/org/chromium/content/browser/LocationProviderTest.java +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.content.browser; - -import android.app.Activity; -import android.support.test.InstrumentationRegistry; -import android.support.test.annotation.UiThreadTest; -import android.support.test.filters.SmallTest; -import android.support.test.rule.UiThreadTestRule; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.chromium.base.annotations.SuppressFBWarnings; -import org.chromium.base.test.util.Feature; -import org.chromium.content.browser.test.ContentJUnit4ClassRunner; -import org.chromium.device.geolocation.LocationProviderAdapter; - -/** - * Test suite for LocationProvider. - */ -@RunWith(ContentJUnit4ClassRunner.class) -public class LocationProviderTest { - private Activity mActivity; - private LocationProviderAdapter mLocationProvider; - - @Rule - public UiThreadTestRule mRule = new UiThreadTestRule(); - - @Before - @SuppressFBWarnings("URF_UNREAD_FIELD") - public void setUp() { - mActivity = new Activity(); - mLocationProvider = LocationProviderAdapter.create( - InstrumentationRegistry.getInstrumentation().getTargetContext()); - } - - /** - * Verify a normal start/stop call pair without any activity pauses. - */ - @Test - @SmallTest - @UiThreadTest - @Feature({"Location"}) - public void testStartStop() throws Exception { - mLocationProvider.start(false); - Assert.assertTrue("Should be running", mLocationProvider.isRunning()); - mLocationProvider.stop(); - Assert.assertFalse("Should have stopped", mLocationProvider.isRunning()); - } - - /** - * Verify a start/upgrade/stop call sequence without any activity pauses. - */ - @Test - @SmallTest - @UiThreadTest - @Feature({"Location"}) - public void testStartUpgradeStop() throws Exception { - mLocationProvider.start(false); - Assert.assertTrue("Should be running", mLocationProvider.isRunning()); - mLocationProvider.start(true); - Assert.assertTrue("Should be running", mLocationProvider.isRunning()); - mLocationProvider.stop(); - Assert.assertFalse("Should have stopped", mLocationProvider.isRunning()); - } -}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/OWNERS b/content/public/android/javatests/src/org/chromium/content/browser/OWNERS index 05c5396..60ede9cb 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/OWNERS +++ b/content/public/android/javatests/src/org/chromium/content/browser/OWNERS
@@ -1,9 +1,6 @@ # Device Motion / Orientation API related per-file DeviceSensorsTest.java=timvolodine@chromium.org -# Geolocation API related -per-file LocationProviderTest.java=timvolodine@chromium.org - # Screen Orientation API related per-file ScreenOrientation*.java=mlamouri@chromium.org
diff --git a/content/public/test/test_download_request_handler.cc b/content/public/test/test_download_request_handler.cc index d7d05a8..9e854264 100644 --- a/content/public/test/test_download_request_handler.cc +++ b/content/public/test/test_download_request_handler.cc
@@ -109,7 +109,6 @@ void GetResponseInfo(net::HttpResponseInfo* response_info) override; int64_t GetTotalReceivedBytes() const override; bool GetMimeType(std::string* mime_type) const override; - int GetResponseCode() const override; int ReadRawData(net::IOBuffer* buf, int buf_size) override; private: @@ -275,11 +274,6 @@ return !parameters_->content_type.empty(); } -int TestDownloadRequestHandler::PartialResponseJob::GetResponseCode() const { - return response_info_.headers.get() ? response_info_.headers->response_code() - : 0; -} - int TestDownloadRequestHandler::PartialResponseJob::ReadRawData( net::IOBuffer* buf, int buf_size) {
diff --git a/content/renderer/media_recorder/video_track_recorder.cc b/content/renderer/media_recorder/video_track_recorder.cc index 49def8d1..5108aa8 100644 --- a/content/renderer/media_recorder/video_track_recorder.cc +++ b/content/renderer/media_recorder/video_track_recorder.cc
@@ -109,11 +109,6 @@ return; #endif -#if defined(OS_ANDROID) - // See https://crbug.com/653864. - return; -#endif - content::RenderThreadImpl* const render_thread_impl = content::RenderThreadImpl::current(); if (!render_thread_impl) { @@ -132,12 +127,17 @@ gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles(); for (const auto& supported_profile : vea_supported_profiles) { for (auto& codec_id_and_profile : kPreferredCodecIdAndVEAProfiles) { - if (supported_profile.profile >= codec_id_and_profile.min_profile && - supported_profile.profile <= codec_id_and_profile.max_profile) { - DVLOG(2) << "Accelerated codec found: " - << media::GetProfileName(supported_profile.profile); - codec_id_to_profile_.insert(std::make_pair( - codec_id_and_profile.codec_id, supported_profile.profile)); + const media::VideoCodecProfile codec = supported_profile.profile; +#if defined(OS_ANDROID) + // TODO(mcasas): enable other codecs, https://crbug.com/653864. + if (codec < media::VP8PROFILE_MIN || codec > media::VP8PROFILE_MAX) + continue; +#endif + if (codec >= codec_id_and_profile.min_profile && + codec <= codec_id_and_profile.max_profile) { + DVLOG(2) << "Accelerated codec found: " << media::GetProfileName(codec); + codec_id_to_profile_.insert( + std::make_pair(codec_id_and_profile.codec_id, codec)); } } }
diff --git a/content/renderer/media_recorder/video_track_recorder.h b/content/renderer/media_recorder/video_track_recorder.h index 53a871f..e53cef4 100644 --- a/content/renderer/media_recorder/video_track_recorder.h +++ b/content/renderer/media_recorder/video_track_recorder.h
@@ -32,8 +32,13 @@ } // namespace media namespace video_track_recorder { +#if defined(OS_ANDROID) +const int kVEAEncoderMinResolutionWidth = 176; +const int kVEAEncoderMinResolutionHeight = 144; +#else const int kVEAEncoderMinResolutionWidth = 640; const int kVEAEncoderMinResolutionHeight = 480; +#endif } // namespace video_track_recorder namespace content {
diff --git a/content/renderer/mus/renderer_window_tree_client.cc b/content/renderer/mus/renderer_window_tree_client.cc index 5d5915c..328673da 100644 --- a/content/renderer/mus/renderer_window_tree_client.cc +++ b/content/renderer/mus/renderer_window_tree_client.cc
@@ -242,9 +242,8 @@ void RendererWindowTreeClient::OnWindowFocused(ui::Id focused_window_id) {} -void RendererWindowTreeClient::OnWindowPredefinedCursorChanged( - ui::Id window_id, - ui::mojom::CursorType cursor) {} +void RendererWindowTreeClient::OnWindowCursorChanged(ui::Id window_id, + ui::CursorData cursor) {} void RendererWindowTreeClient::OnWindowSurfaceChanged( ui::Id window_id,
diff --git a/content/renderer/mus/renderer_window_tree_client.h b/content/renderer/mus/renderer_window_tree_client.h index 7ac9daf5..cefe8797 100644 --- a/content/renderer/mus/renderer_window_tree_client.h +++ b/content/renderer/mus/renderer_window_tree_client.h
@@ -134,8 +134,7 @@ uint32_t window_id, int64_t display_id) override; void OnWindowFocused(ui::Id focused_window_id) override; - void OnWindowPredefinedCursorChanged(ui::Id window_id, - ui::mojom::CursorType cursor) override; + void OnWindowCursorChanged(ui::Id window_id, ui::CursorData cursor) override; void OnWindowSurfaceChanged(ui::Id window_id, const cc::SurfaceInfo& surface_info) override; void OnDragDropStart(
diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc index 4b62d314..8abe3757 100644 --- a/content/renderer/pepper/pepper_webplugin_impl.cc +++ b/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -183,7 +183,9 @@ } void PepperWebPluginImpl::Paint(WebCanvas* canvas, const WebRect& rect) { - if (!instance_->FlashIsFullscreenOrPending()) + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (instance_ && !instance_->FlashIsFullscreenOrPending()) instance_->Paint(canvas, plugin_rect_, rect); } @@ -200,7 +202,10 @@ void PepperWebPluginImpl::UpdateFocus(bool focused, blink::WebFocusType focus_type) { - instance_->SetWebKitFocus(focused); + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (instance_) + instance_->SetWebKitFocus(focused); } void PepperWebPluginImpl::UpdateVisibility(bool visible) {} @@ -208,7 +213,9 @@ blink::WebInputEventResult PepperWebPluginImpl::HandleInputEvent( const blink::WebInputEvent& event, blink::WebCursorInfo& cursor_info) { - if (instance_->FlashIsFullscreenOrPending()) + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_ || instance_->FlashIsFullscreenOrPending()) return blink::WebInputEventResult::kNotHandled; return instance_->HandleInputEvent(event, &cursor_info) ? blink::WebInputEventResult::kHandledApplication @@ -217,11 +224,19 @@ void PepperWebPluginImpl::DidReceiveResponse( const blink::WebURLResponse& response) { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return; DCHECK(!instance_->document_loader()); instance_->HandleDocumentLoad(response); } void PepperWebPluginImpl::DidReceiveData(const char* data, int data_length) { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return; blink::WebAssociatedURLLoaderClient* document_loader = instance_->document_loader(); if (document_loader) @@ -229,6 +244,10 @@ } void PepperWebPluginImpl::DidFinishLoading() { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return; blink::WebAssociatedURLLoaderClient* document_loader = instance_->document_loader(); if (document_loader) @@ -236,6 +255,10 @@ } void PepperWebPluginImpl::DidFailLoading(const blink::WebURLError& error) { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return; blink::WebAssociatedURLLoaderClient* document_loader = instance_->document_loader(); if (document_loader) @@ -247,62 +270,113 @@ } WebString PepperWebPluginImpl::SelectionAsText() const { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return WebString(); return WebString::FromUTF16(instance_->GetSelectedText(false)); } WebString PepperWebPluginImpl::SelectionAsMarkup() const { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return WebString(); return WebString::FromUTF16(instance_->GetSelectedText(true)); } WebURL PepperWebPluginImpl::LinkAtPosition(const WebPoint& position) const { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return GURL(); return GURL(instance_->GetLinkAtPosition(position)); } bool PepperWebPluginImpl::StartFind(const blink::WebString& search_text, bool case_sensitive, int identifier) { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return false; return instance_->StartFind(search_text.Utf8(), case_sensitive, identifier); } void PepperWebPluginImpl::SelectFindResult(bool forward, int identifier) { - instance_->SelectFindResult(forward, identifier); + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (instance_) + instance_->SelectFindResult(forward, identifier); } void PepperWebPluginImpl::StopFind() { - instance_->StopFind(); + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (instance_) + instance_->StopFind(); } bool PepperWebPluginImpl::SupportsPaginatedPrint() { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return false; return instance_->SupportsPrintInterface(); } bool PepperWebPluginImpl::IsPrintScalingDisabled() { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return false; return instance_->IsPrintScalingDisabled(); } int PepperWebPluginImpl::PrintBegin(const WebPrintParams& print_params) { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return 0; return instance_->PrintBegin(print_params); } void PepperWebPluginImpl::PrintPage(int page_number, blink::WebCanvas* canvas) { - instance_->PrintPage(page_number, canvas); + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (instance_) + instance_->PrintPage(page_number, canvas); } void PepperWebPluginImpl::PrintEnd() { - instance_->PrintEnd(); + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (instance_) + instance_->PrintEnd(); } bool PepperWebPluginImpl::GetPrintPresetOptionsFromDocument( blink::WebPrintPresetOptions* preset_options) { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return false; return instance_->GetPrintPresetOptionsFromDocument(preset_options); } bool PepperWebPluginImpl::CanRotateView() { + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (!instance_) + return false; return instance_->CanRotateView(); } void PepperWebPluginImpl::RotateView(RotationType type) { - instance_->RotateView(type); + // Re-entrancy may cause JS to try to execute script on the plugin before it + // is fully initialized. See: crbug.com/715747. + if (instance_) + instance_->RotateView(type); } bool PepperWebPluginImpl::IsPlaceholder() {
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index 8cf1916d..4313af0 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -696,6 +696,8 @@ ['linux'], bug=483282) self.Fail('conformance2/textures/image_bitmap_from_image/' + 'tex-3d-r16f-red-float.html', ['linux'], bug=679695) + self.Fail('conformance2/textures/canvas_sub_rectangle/' + + 'tex-2d-rgb16f-rgb-float.html', ['linux'], bug=715696) # Linux Multi-vendor failures. self.Skip('deqp/data/gles3/shaders/qualification_order.html',
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt index 489b476..d9345de 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt +++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@ # AUTOGENERATED FILE - DO NOT EDIT # SEE roll_webgl_conformance.py -Current webgl revision 40d75ac0e565191d93ff3c4e8fd19f8b2df7f617 +Current webgl revision f7157c2751220a8f0def9f3f7f6ff37392ac83f0
diff --git a/device/BUILD.gn b/device/BUILD.gn index 3b481aa6..1df91d7 100644 --- a/device/BUILD.gn +++ b/device/BUILD.gn
@@ -7,6 +7,7 @@ import("//testing/test.gni") if (is_android) { + import("//build/config/android/config.gni") import("//build/config/android/rules.gni") # For generate_jni(). } @@ -303,14 +304,20 @@ java_files = [ "gamepad/android/junit/src/org/chromium/device/gamepad/GamepadMappingsTest.java", "generic_sensor/android/junit/src/org/chromium/device/sensors/PlatformSensorAndProviderTest.java", + "geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java", "nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java", ] deps = [ + "$google_play_services_package:google_play_services_base_java", + "$google_play_services_package:google_play_services_basement_java", + "$google_play_services_package:google_play_services_location_java", "//base:base_java", "//base:base_java_test_support", "//device/gamepad:java", "//device/generic_sensor:java", "//device/generic_sensor/public/interfaces:interfaces_java", + "//device/geolocation:geolocation_java", + "//device/geolocation:geolocation_java_test_support", "//device/nfc:mojo_bindings_java", "//device/nfc/android:java", "//mojo/public/java:bindings_java",
diff --git a/device/geolocation/BUILD.gn b/device/geolocation/BUILD.gn index 19ba0bf1..51b1284 100644 --- a/device/geolocation/BUILD.gn +++ b/device/geolocation/BUILD.gn
@@ -5,6 +5,7 @@ import("//build/config/features.gni") if (is_android) { + import("//build/config/android/config.gni") import("//build/config/android/rules.gni") # For generate_jni(). } @@ -127,11 +128,15 @@ "android/java/src/org/chromium/device/geolocation/LocationProviderAdapter.java", "android/java/src/org/chromium/device/geolocation/LocationProviderAndroid.java", "android/java/src/org/chromium/device/geolocation/LocationProviderFactory.java", + "android/java/src/org/chromium/device/geolocation/LocationProviderGmsCore.java", ] deps = [ ":geolocation", ":geolocation_jni_headers", + "$google_play_services_package:google_play_services_base_java", + "$google_play_services_package:google_play_services_basement_java", + "$google_play_services_package:google_play_services_location_java", "//base:base_java", ] }
diff --git a/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAdapter.java b/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAdapter.java index bd2ffb9..c735159 100644 --- a/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAdapter.java +++ b/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAdapter.java
@@ -5,7 +5,9 @@ package org.chromium.device.geolocation; import android.content.Context; +import android.location.Location; +import org.chromium.base.Log; import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; @@ -24,6 +26,8 @@ @MainDex @VisibleForTesting public class LocationProviderAdapter { + private static final String TAG = "cr_LocationProvider"; + // Delegate handling the real work in the main thread. private LocationProviderFactory.LocationProvider mImpl; @@ -75,14 +79,15 @@ return mImpl.isRunning(); } - public static void newLocationAvailable(double latitude, double longitude, double timestamp, - boolean hasAltitude, double altitude, boolean hasAccuracy, double accuracy, - boolean hasHeading, double heading, boolean hasSpeed, double speed) { - nativeNewLocationAvailable(latitude, longitude, timestamp, hasAltitude, altitude, - hasAccuracy, accuracy, hasHeading, heading, hasSpeed, speed); + public static void onNewLocationAvailable(Location location) { + nativeNewLocationAvailable(location.getLatitude(), location.getLongitude(), + location.getTime() / 1000.0, location.hasAltitude(), location.getAltitude(), + location.hasAccuracy(), location.getAccuracy(), location.hasBearing(), + location.getBearing(), location.hasSpeed(), location.getSpeed()); } public static void newErrorAvailable(String message) { + Log.e(TAG, "newErrorAvailable %s", message); nativeNewErrorAvailable(message); }
diff --git a/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAndroid.java b/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAndroid.java index 261ce9d..68c4b46 100644 --- a/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAndroid.java +++ b/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderAndroid.java
@@ -13,6 +13,7 @@ import org.chromium.base.Log; import org.chromium.base.ThreadUtils; +import org.chromium.base.VisibleForTesting; import java.util.List; @@ -37,17 +38,20 @@ @Override public void start(boolean enableHighAccuracy) { + ThreadUtils.assertOnUiThread(); unregisterFromLocationUpdates(); registerForLocationUpdates(enableHighAccuracy); } @Override public void stop() { + ThreadUtils.assertOnUiThread(); unregisterFromLocationUpdates(); } @Override public boolean isRunning() { + ThreadUtils.assertOnUiThread(); return mIsRunning; } @@ -57,7 +61,7 @@ // possible that we receive callbacks after unregistering. At this point, the // native object will no longer exist. if (mIsRunning) { - updateNewLocation(location); + LocationProviderAdapter.onNewLocationAvailable(location); } } @@ -70,7 +74,12 @@ @Override public void onProviderDisabled(String provider) {} - private void ensureLocationManagerCreated() { + @VisibleForTesting + public void setLocationManagerForTesting(LocationManager manager) { + mLocationManager = manager; + } + + private void createLocationManagerIfNeeded() { if (mLocationManager != null) return; mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); if (mLocationManager == null) { @@ -82,7 +91,7 @@ * Registers this object with the location service. */ private void registerForLocationUpdates(boolean enableHighAccuracy) { - ensureLocationManagerCreated(); + createLocationManagerIfNeeded(); if (usePassiveOneShotLocation()) return; assert !mIsRunning; @@ -103,8 +112,8 @@ unregisterFromLocationUpdates(); // Propagate an error to JavaScript, this can happen in case of WebView // when the embedding app does not have sufficient permissions. - LocationProviderAdapter.newErrorAvailable("application does not have sufficient " - + "geolocation permissions."); + LocationProviderAdapter.newErrorAvailable( + "application does not have sufficient geolocation permissions."); } catch (IllegalArgumentException e) { Log.e(TAG, "Caught IllegalArgumentException registering for location updates."); unregisterFromLocationUpdates(); @@ -116,33 +125,26 @@ * Unregisters this object from the location service. */ private void unregisterFromLocationUpdates() { - if (mIsRunning) { - mIsRunning = false; - mLocationManager.removeUpdates(this); - } - } - - private void updateNewLocation(Location location) { - LocationProviderAdapter.newLocationAvailable(location.getLatitude(), - location.getLongitude(), location.getTime() / 1000.0, location.hasAltitude(), - location.getAltitude(), location.hasAccuracy(), location.getAccuracy(), - location.hasBearing(), location.getBearing(), location.hasSpeed(), - location.getSpeed()); + if (!mIsRunning) return; + mIsRunning = false; + mLocationManager.removeUpdates(this); } private boolean usePassiveOneShotLocation() { - if (!isOnlyPassiveLocationProviderEnabled()) return false; + if (!isOnlyPassiveLocationProviderEnabled()) { + return false; + } // Do not request a location update if the only available location provider is // the passive one. Make use of the last known location and call - // onLocationChanged directly. + // onNewLocationAvailable directly. final Location location = mLocationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER); if (location != null) { ThreadUtils.runOnUiThread(new Runnable() { @Override public void run() { - updateNewLocation(location); + LocationProviderAdapter.onNewLocationAvailable(location); } }); } @@ -154,7 +156,7 @@ * in the system. */ private boolean isOnlyPassiveLocationProviderEnabled() { - List<String> providers = mLocationManager.getProviders(true); + final List<String> providers = mLocationManager.getProviders(true); return providers != null && providers.size() == 1 && providers.get(0).equals(LocationManager.PASSIVE_PROVIDER); }
diff --git a/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderFactory.java b/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderFactory.java index 3ffc36a..33809e9 100644 --- a/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderFactory.java +++ b/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderFactory.java
@@ -9,19 +9,20 @@ import org.chromium.base.VisibleForTesting; /** - * Factory to create a LocationProvider to allow us to inject - * a mock for tests. + * Factory to create a LocationProvider to allow us to inject a mock for tests. */ public class LocationProviderFactory { private static LocationProviderFactory.LocationProvider sProviderImpl; + private static boolean sUseGmsCoreLocationProvider; /** * LocationProviderFactory.create() returns an instance of this interface. */ public interface LocationProvider { /** - * Start listening for location updates. - * @param enableHighAccuracy Whether or not to enable high accuracy location providers. + * Start listening for location updates. Calling several times before stop() is interpreted + * as restart. + * @param enableHighAccuracy Whether or not to enable high accuracy location. */ public void start(boolean enableHighAccuracy); @@ -40,12 +41,20 @@ @VisibleForTesting public static void setLocationProviderImpl(LocationProviderFactory.LocationProvider provider) { - assert sProviderImpl == null; sProviderImpl = provider; } + public static void useGmsCoreLocationProvider() { + sUseGmsCoreLocationProvider = true; + } + public static LocationProvider create(Context context) { - if (sProviderImpl == null) { + if (sProviderImpl != null) return sProviderImpl; + + if (sUseGmsCoreLocationProvider + && LocationProviderGmsCore.isGooglePlayServicesAvailable(context)) { + sProviderImpl = new LocationProviderGmsCore(context); + } else { sProviderImpl = new LocationProviderAndroid(context); } return sProviderImpl;
diff --git a/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderGmsCore.java b/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderGmsCore.java new file mode 100644 index 0000000..aed6822 --- /dev/null +++ b/device/geolocation/android/java/src/org/chromium/device/geolocation/LocationProviderGmsCore.java
@@ -0,0 +1,136 @@ +// 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. + +package org.chromium.device.geolocation; + +import android.content.Context; +import android.location.Location; +import android.os.Bundle; + +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GoogleApiAvailability; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; +import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; +import com.google.android.gms.location.FusedLocationProviderApi; +import com.google.android.gms.location.LocationListener; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationServices; + +import org.chromium.base.Log; +import org.chromium.base.ThreadUtils; + +/** + * This is a LocationProvider using Google Play Services. + * + * https://developers.google.com/android/reference/com/google/android/gms/location/package-summary + */ +public class LocationProviderGmsCore implements ConnectionCallbacks, OnConnectionFailedListener, + LocationListener, + LocationProviderFactory.LocationProvider { + private static final String TAG = "cr_LocationProvider"; + + // Values for the LocationRequest's setInterval for normal and high accuracy, respectively. + private static final long UPDATE_INTERVAL_MS = 1000; + private static final long UPDATE_INTERVAL_FAST_MS = 500; + + private final GoogleApiClient mGoogleApiClient; + private FusedLocationProviderApi mLocationProviderApi = LocationServices.FusedLocationApi; + + private boolean mEnablehighAccuracy; + private LocationRequest mLocationRequest; + + public static boolean isGooglePlayServicesAvailable(Context context) { + return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) + == ConnectionResult.SUCCESS; + } + + LocationProviderGmsCore(Context context) { + Log.i(TAG, "Google Play Services"); + mGoogleApiClient = new GoogleApiClient.Builder(context) + .addApi(LocationServices.API) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + assert mGoogleApiClient != null; + } + + LocationProviderGmsCore(GoogleApiClient client, FusedLocationProviderApi locationApi) { + mGoogleApiClient = client; + mLocationProviderApi = locationApi; + } + + // ConnectionCallbacks implementation + @Override + public void onConnected(Bundle connectionHint) { + ThreadUtils.assertOnUiThread(); + + mLocationRequest = LocationRequest.create(); + if (mEnablehighAccuracy) { + mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) + .setInterval(UPDATE_INTERVAL_FAST_MS); + } else { + mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY) + .setInterval(UPDATE_INTERVAL_MS); + } + + final Location location = mLocationProviderApi.getLastLocation(mGoogleApiClient); + if (location != null) { + LocationProviderAdapter.onNewLocationAvailable(location); + } + + try { + // Request updates on UI Thread replicating LocationProviderAndroid's behaviour. + mLocationProviderApi.requestLocationUpdates( + mGoogleApiClient, mLocationRequest, this, ThreadUtils.getUiThreadLooper()); + } catch (IllegalStateException e) { + // Happens "If this method is executed in a thread that has not called Looper.prepare()" + Log.e(TAG, "Unexpected exception " + e); + assert false; + } + } + + @Override + public void onConnectionSuspended(int cause) {} + + // OnConnectionFailedListener implementation + @Override + public void onConnectionFailed(ConnectionResult result) { + LocationProviderAdapter.newErrorAvailable( + "Failed to connect to Google Play Services: " + result.toString()); + } + + // LocationProviderFactory.LocationProvider implementation + @Override + public void start(boolean enableHighAccuracy) { + ThreadUtils.assertOnUiThread(); + if (mGoogleApiClient.isConnected()) mGoogleApiClient.disconnect(); + + mEnablehighAccuracy = enableHighAccuracy; + mGoogleApiClient.connect(); // Should return via onConnected(). + } + + @Override + public void stop() { + ThreadUtils.assertOnUiThread(); + if (!mGoogleApiClient.isConnected()) return; + + mLocationProviderApi.removeLocationUpdates(mGoogleApiClient, this); + + mGoogleApiClient.disconnect(); + } + + @Override + public boolean isRunning() { + assert ThreadUtils.runningOnUiThread(); + if (mGoogleApiClient == null) return false; + return mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected(); + } + + // LocationListener implementation + @Override + public void onLocationChanged(Location location) { + LocationProviderAdapter.onNewLocationAvailable(location); + } +}
diff --git a/device/geolocation/android/javatests/src/org/chromium/device/geolocation/MockLocationProvider.java b/device/geolocation/android/javatests/src/org/chromium/device/geolocation/MockLocationProvider.java index ae99afb..2ed205da5 100644 --- a/device/geolocation/android/javatests/src/org/chromium/device/geolocation/MockLocationProvider.java +++ b/device/geolocation/android/javatests/src/org/chromium/device/geolocation/MockLocationProvider.java
@@ -4,6 +4,7 @@ package org.chromium.device.geolocation; +import android.location.Location; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; @@ -77,7 +78,9 @@ } private void newLocation() { - LocationProviderAdapter.newLocationAvailable( - 0, 0, System.currentTimeMillis() / 1000.0, false, 0, true, 0.5, false, 0, false, 0); + Location location = new Location("MockLocationProvider"); + location.setTime(System.currentTimeMillis()); + location.setAccuracy(0.5f); + LocationProviderAdapter.onNewLocationAvailable(location); } };
diff --git a/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java b/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java new file mode 100644 index 0000000..5b09459 --- /dev/null +++ b/device/geolocation/android/junit/src/org/chromium/device/geolocation/LocationProviderTest.java
@@ -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. + +package org.chromium.device.geolocation; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doAnswer; + +import android.content.Context; +import android.location.LocationManager; + +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.location.FusedLocationProviderApi; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.robolectric.ParameterizedRobolectricTestRunner; +import org.robolectric.ParameterizedRobolectricTestRunner.Parameters; +import org.robolectric.Shadows; +import org.robolectric.annotation.Config; +import org.robolectric.internal.Shadow; +import org.robolectric.shadows.ShadowLocationManager; +import org.robolectric.shadows.ShadowLog; // remove me ? + +import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.Feature; + +import java.util.Arrays; +import java.util.Collection; + +/** + * Test suite for Java Geolocation. + */ +@RunWith(ParameterizedRobolectricTestRunner.class) +@Config(sdk = 21, manifest = Config.NONE) +public class LocationProviderTest { + public static enum LocationProviderType { MOCK, ANDROID, GMS_CORE } + + @Parameters + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][] {{LocationProviderType.MOCK}, + {LocationProviderType.ANDROID}, {LocationProviderType.GMS_CORE}}); + } + + @Mock + private Context mContext; + + // Member variables for LocationProviderType.GMS_CORE case. + @Mock + private GoogleApiClient mGoogleApiClient; + private boolean mGoogleApiClientIsConnected; + + // Member variables for LocationProviderType.ANDROID case. + private LocationManager mLocationManager; + private ShadowLocationManager mShadowLocationManager; + + private LocationProviderAdapter mLocationProviderAdapter; + + private final LocationProviderType mApi; + + public LocationProviderTest(LocationProviderType api) { + mApi = api; + } + + @Before + public void setUp() { + ShadowLog.stream = System.out; + MockitoAnnotations.initMocks(this); + + mContext = Mockito.mock(Context.class); + } + + /** + * Verify a normal start/stop call pair with the given LocationProvider. + */ + @Test + @Feature({"Location"}) + public void testStartStop() { + assertTrue("Should be on UI thread", ThreadUtils.runningOnUiThread()); + + setLocationProvider(); + + createLocationProviderAdapter(); + startLocationProviderAdapter(false); + stopLocationProviderAdapter(); + } + + /** + * Verify a start/upgrade/stop call sequencewith the given LocationProvider. + */ + @Test + @Feature({"Location"}) + public void testStartUpgradeStop() { + assertTrue("Should be on UI thread", ThreadUtils.runningOnUiThread()); + + setLocationProvider(); + + createLocationProviderAdapter(); + startLocationProviderAdapter(false); + startLocationProviderAdapter(true); + stopLocationProviderAdapter(); + } + + private void createLocationProviderAdapter() { + mLocationProviderAdapter = LocationProviderAdapter.create(mContext); + assertNotNull("LocationProvider", mLocationProviderAdapter); + } + + private void setLocationProvider() { + if (mApi == LocationProviderType.MOCK) { + setLocationProviderMock(); + } else if (mApi == LocationProviderType.ANDROID) { + setLocationProviderAndroid(); + } else if (mApi == LocationProviderType.GMS_CORE) { + setLocationProviderGmsCore(); + } else { + assert false; + } + } + + private void setLocationProviderMock() { + LocationProviderFactory.setLocationProviderImpl(new MockLocationProvider()); + } + + private void setLocationProviderAndroid() { + LocationProviderAndroid locationProviderAndroid = new LocationProviderAndroid(mContext); + + // Robolectric has a ShadowLocationManager class that mocks the behaviour of the real + // class very closely. Use it here. + mLocationManager = Shadow.newInstanceOf(LocationManager.class); + mShadowLocationManager = Shadows.shadowOf(mLocationManager); + locationProviderAndroid.setLocationManagerForTesting(mLocationManager); + LocationProviderFactory.setLocationProviderImpl(locationProviderAndroid); + } + + private void setLocationProviderGmsCore() { + // Robolectric has a ShadowGoogleApiClientBuilder class that mocks the behaviour of the real + // class very closely, but it's not available in our build + mGoogleApiClient = Mockito.mock(GoogleApiClient.class); + mGoogleApiClientIsConnected = false; + doAnswer(new Answer<Boolean>() { + public Boolean answer(InvocationOnMock invocation) { + return mGoogleApiClientIsConnected; + } + }) + .when(mGoogleApiClient) + .isConnected(); + + doAnswer(new Answer<Void>() { + public Void answer(InvocationOnMock invocation) { + mGoogleApiClientIsConnected = true; + return null; + } + }) + .when(mGoogleApiClient) + .connect(); + + doAnswer(new Answer<Void>() { + public Void answer(InvocationOnMock invocation) { + mGoogleApiClientIsConnected = false; + return null; + } + }) + .when(mGoogleApiClient) + .disconnect(); + + FusedLocationProviderApi fusedLocationProviderApi = + Mockito.mock(FusedLocationProviderApi.class); + + LocationProviderGmsCore locationProviderGmsCore = + new LocationProviderGmsCore(mGoogleApiClient, fusedLocationProviderApi); + + LocationProviderFactory.setLocationProviderImpl(locationProviderGmsCore); + } + + private void startLocationProviderAdapter(boolean highResolution) { + mLocationProviderAdapter.start(highResolution); + assertTrue("Should be running", mLocationProviderAdapter.isRunning()); + } + + private void stopLocationProviderAdapter() { + mLocationProviderAdapter.stop(); + assertFalse("Should have stopped", mLocationProviderAdapter.isRunning()); + } +}
diff --git a/device/geolocation/wifi_data_provider_win.cc b/device/geolocation/wifi_data_provider_win.cc index 8b296ae..908d06c 100644 --- a/device/geolocation/wifi_data_provider_win.cc +++ b/device/geolocation/wifi_data_provider_win.cc
@@ -2,25 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Windows Vista uses the Native Wifi (WLAN) API for accessing WiFi cards. See -// http://msdn.microsoft.com/en-us/library/ms705945(VS.85).aspx. Windows XP -// Service Pack 3 (and Windows XP Service Pack 2, if upgraded with a hot fix) -// also support a limited version of the WLAN API. See -// http://msdn.microsoft.com/en-us/library/bb204766.aspx. The WLAN API uses -// wlanapi.h, which is not part of the SDK used by Gears, so is replicated -// locally using data from the MSDN. -// -// Windows XP from Service Pack 2 onwards supports the Wireless Zero -// Configuration (WZC) programming interface. See -// http://msdn.microsoft.com/en-us/library/ms706587(VS.85).aspx. -// -// The MSDN recommends that one use the WLAN API where available, and WZC -// otherwise. -// -// However, it seems that WZC fails for some wireless cards. Also, WLAN seems -// not to work on XP SP3. So we use WLAN on Vista, and use NDIS directly -// otherwise. - #include "device/geolocation/wifi_data_provider_win.h" #include <windows.h> @@ -31,29 +12,20 @@ #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/strings/utf_string_conversions.h" +#include "base/timer/elapsed_timer.h" #include "base/win/windows_version.h" #include "device/geolocation/wifi_data_provider_common.h" #include "device/geolocation/wifi_data_provider_common_win.h" #include "device/geolocation/wifi_data_provider_manager.h" -// Taken from ndis.h for WinCE. -#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L) -#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L) - namespace device { + namespace { -// The limits on the size of the buffer used for the OID query. -const int kInitialBufferSize = 2 << 12; // Good for about 50 APs. -const int kMaximumBufferSize = 2 << 20; // 2MB -// Length for generic string buffers passed to Windows APIs. -const int kStringLength = 512; - -// The time periods, in milliseconds, between successive polls of the wifi data. -const int kDefaultPollingInterval = 10000; // 10s -const int kNoChangePollingInterval = 120000; // 2 mins -const int kTwoNoChangePollingInterval = 600000; // 10 mins -const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s +static const int kDefaultPollingIntervalMs = 10 * 1000; // 10s +static const int kNoChangePollingIntervalMs = 2 * 60 * 1000; // 2 mins +static const int kTwoNoChangePollingIntervalMs = 10 * 60 * 1000; // 10 mins +static const int kNoWifiPollingIntervalMs = 20 * 1000; // 20s // WlanOpenHandle typedef DWORD(WINAPI* WlanOpenHandleFunction)(DWORD dwClientVersion, @@ -84,29 +56,47 @@ typedef DWORD(WINAPI* WlanCloseHandleFunction)(HANDLE hClientHandle, PVOID pReserved); -// Local classes and functions +// Extracts data for an access point and converts to AccessPointData. +AccessPointData GetNetworkData(const WLAN_BSS_ENTRY& bss_entry) { + AccessPointData access_point_data; + // Currently we get only MAC address, signal strength and SSID. + access_point_data.mac_address = MacAddressAsString16(bss_entry.dot11Bssid); + access_point_data.radio_signal_strength = bss_entry.lRssi; + // bss_entry.dot11Ssid.ucSSID is not null-terminated. + base::UTF8ToUTF16(reinterpret_cast<const char*>(bss_entry.dot11Ssid.ucSSID), + static_cast<ULONG>(bss_entry.dot11Ssid.uSSIDLength), + &access_point_data.ssid); + + // TODO(steveblock): Is it possible to get the following? + // access_point_data.signal_to_noise + // access_point_data.age + // access_point_data.channel + return access_point_data; +} + +// This class encapsulates loading and interacting with wlan_api.dll, which can +// not be loaded statically because it's not available in Server 2008 R2, where +// it must be installed explicitly by the user if and when they wants to use the +// Wireless interface. +// https://www.bonusbits.com/wiki/KB:Wlanapi.dll_missing_on_Windows_Server_2008_R2 class WindowsWlanApi : public WifiDataProviderCommon::WlanApiInterface { public: - // Factory function. Will return NULL if this API is unavailable. static std::unique_ptr<WindowsWlanApi> Create(); // Takes ownership of the library handle. explicit WindowsWlanApi(HINSTANCE library); ~WindowsWlanApi() override; - // WlanApiInterface + // WlanApiInterface implementation bool GetAccessPointData(WifiData::AccessPointDataSet* data) override; private: - // Loads the required functions from the DLL. - void GetWLANFunctions(HINSTANCE wlan_library); - int GetInterfaceDataWLAN(HANDLE wlan_handle, - const GUID& interface_id, - WifiData::AccessPointDataSet* data); - // Logs number of detected wlan interfaces. static void LogWlanInterfaceCount(int count); + bool GetInterfaceDataWLAN(HANDLE wlan_handle, + const GUID& interface_id, + WifiData::AccessPointDataSet* data); // Handle to the wlanapi.dll library. HINSTANCE library_; @@ -118,130 +108,56 @@ WlanCloseHandleFunction WlanCloseHandle_function_; }; -class WindowsNdisApi : public WifiDataProviderCommon::WlanApiInterface { - public: - static std::unique_ptr<WindowsNdisApi> Create(); - - // Swaps in content of the vector passed - explicit WindowsNdisApi(std::vector<base::string16>* interface_service_names); - ~WindowsNdisApi() override; - - // WlanApiInterface - bool GetAccessPointData(WifiData::AccessPointDataSet* data) override; - - private: - static bool GetInterfacesNDIS( - std::vector<base::string16>* interface_service_names_out); - bool GetInterfaceDataNDIS(HANDLE adapter_handle, - WifiData::AccessPointDataSet* data); - // NDIS variables. - std::vector<base::string16> interface_service_names_; - - // Remembers scan result buffer size across calls. - int oid_buffer_size_; -}; - -// Extracts data for an access point and converts to Gears format. -bool GetNetworkData(const WLAN_BSS_ENTRY& bss_entry, - AccessPointData* access_point_data); -bool UndefineDosDevice(const base::string16& device_name); -bool DefineDosDeviceIfNotExists(const base::string16& device_name); -HANDLE GetFileHandle(const base::string16& device_name); -// Makes the OID query and returns a Windows API error code. -int PerformQuery(HANDLE adapter_handle, - BYTE* buffer, - DWORD buffer_size, - DWORD* bytes_out); -bool ResizeBuffer(int requested_size, - std::unique_ptr<BYTE, base::FreeDeleter>* buffer); -// Gets the system directory and appends a trailing slash if not already -// present. -bool GetSystemDirectory(base::string16* path); -} // anonymous namespace - -WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() { - return new WifiDataProviderWin(); +// static +std::unique_ptr<WindowsWlanApi> WindowsWlanApi::Create() { + // Use an absolute path to load the DLL to avoid DLL preloading attacks. + static const wchar_t* const kDLL = L"%WINDIR%\\system32\\wlanapi.dll"; + wchar_t path[MAX_PATH] = {0}; + ExpandEnvironmentStrings(kDLL, path, arraysize(path)); + HINSTANCE library = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!library) + return nullptr; + return base::MakeUnique<WindowsWlanApi>(library); } -WifiDataProviderWin::WifiDataProviderWin() {} - -WifiDataProviderWin::~WifiDataProviderWin() {} - -std::unique_ptr<WifiDataProviderCommon::WlanApiInterface> -WifiDataProviderWin::CreateWlanApi() { - // Use the WLAN interface if we're on Vista and if it's available. Otherwise, - // use NDIS. - std::unique_ptr<WlanApiInterface> api = WindowsWlanApi::Create(); - if (api) - return api; - return WindowsNdisApi::Create(); -} - -std::unique_ptr<WifiPollingPolicy> WifiDataProviderWin::CreatePollingPolicy() { - return base::MakeUnique<GenericWifiPollingPolicy< - kDefaultPollingInterval, kNoChangePollingInterval, - kTwoNoChangePollingInterval, kNoWifiPollingIntervalMilliseconds>>(); -} - -// Local classes and functions -namespace { - -// WindowsWlanApi WindowsWlanApi::WindowsWlanApi(HINSTANCE library) : library_(library) { - GetWLANFunctions(library_); + DCHECK(library_); + // Extract all methods from |library_|. + WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>( + GetProcAddress(library_, "WlanOpenHandle")); + WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>( + GetProcAddress(library_, "WlanEnumInterfaces")); + WlanGetNetworkBssList_function_ = + reinterpret_cast<WlanGetNetworkBssListFunction>( + GetProcAddress(library_, "WlanGetNetworkBssList")); + WlanFreeMemory_function_ = reinterpret_cast<WlanFreeMemoryFunction>( + GetProcAddress(library_, "WlanFreeMemory")); + WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>( + GetProcAddress(library_, "WlanCloseHandle")); + + DCHECK(WlanOpenHandle_function_ && WlanEnumInterfaces_function_ && + WlanGetNetworkBssList_function_ && WlanFreeMemory_function_ && + WlanCloseHandle_function_); } WindowsWlanApi::~WindowsWlanApi() { FreeLibrary(library_); } -std::unique_ptr<WindowsWlanApi> WindowsWlanApi::Create() { - if (base::win::GetVersion() < base::win::VERSION_VISTA) - return nullptr; - // We use an absolute path to load the DLL to avoid DLL preloading attacks. - base::string16 system_directory; - if (!GetSystemDirectory(&system_directory)) - return nullptr; - DCHECK(!system_directory.empty()); - base::string16 dll_path = system_directory + L"wlanapi.dll"; - HINSTANCE library = - LoadLibraryEx(dll_path.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (!library) - return nullptr; - return base::MakeUnique<WindowsWlanApi>(library); -} - -void WindowsWlanApi::GetWLANFunctions(HINSTANCE wlan_library) { - DCHECK(wlan_library); - WlanOpenHandle_function_ = reinterpret_cast<WlanOpenHandleFunction>( - GetProcAddress(wlan_library, "WlanOpenHandle")); - WlanEnumInterfaces_function_ = reinterpret_cast<WlanEnumInterfacesFunction>( - GetProcAddress(wlan_library, "WlanEnumInterfaces")); - WlanGetNetworkBssList_function_ = - reinterpret_cast<WlanGetNetworkBssListFunction>( - GetProcAddress(wlan_library, "WlanGetNetworkBssList")); - WlanFreeMemory_function_ = reinterpret_cast<WlanFreeMemoryFunction>( - GetProcAddress(wlan_library, "WlanFreeMemory")); - WlanCloseHandle_function_ = reinterpret_cast<WlanCloseHandleFunction>( - GetProcAddress(wlan_library, "WlanCloseHandle")); - DCHECK(WlanOpenHandle_function_ && WlanEnumInterfaces_function_ && - WlanGetNetworkBssList_function_ && WlanFreeMemory_function_ && - WlanCloseHandle_function_); -} - +// static void WindowsWlanApi::LogWlanInterfaceCount(int count) { - UMA_HISTOGRAM_CUSTOM_COUNTS("Net.Wifi.InterfaceCount", count, 1, 5, 6); + UMA_HISTOGRAM_CUSTOM_COUNTS("Net.Wifi.InterfaceCount", count, 1 /* min */, + 5 /* max */, 6 /* bucket_count */); } bool WindowsWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) { DCHECK(data); - // Get the handle to the WLAN API. DWORD negotiated_version; - HANDLE wlan_handle = NULL; - // We could be executing on either Windows XP or Windows Vista, so use the - // lower version of the client WLAN API. It seems that the negotiated version - // is the Vista version irrespective of what we pass! + HANDLE wlan_handle = nullptr; + // Highest WLAN API version supported by the client; pass the lowest. It seems + // that the negotiated version is the Vista version (the highest) irrespective + // of what we pass! static const int kXpWlanClientVersion = 1; if ((*WlanOpenHandle_function_)(kXpWlanClientVersion, NULL, &negotiated_version, @@ -251,8 +167,8 @@ } DCHECK(wlan_handle); - // Get the list of interfaces. WlanEnumInterfaces allocates interface_list. - WLAN_INTERFACE_INFO_LIST* interface_list = NULL; + // Get the list of interfaces. WlanEnumInterfaces allocates |interface_list|. + WLAN_INTERFACE_INFO_LIST* interface_list = nullptr; if ((*WlanEnumInterfaces_function_)(wlan_handle, NULL, &interface_list) != ERROR_SUCCESS) { LogWlanInterfaceCount(0); @@ -263,324 +179,78 @@ LogWlanInterfaceCount(interface_list->dwNumberOfItems); // Go through the list of interfaces and get the data for each. - for (int i = 0; i < static_cast<int>(interface_list->dwNumberOfItems); ++i) { + for (size_t i = 0; i < interface_list->dwNumberOfItems; ++i) { + const WLAN_INTERFACE_INFO interface_info = interface_list->InterfaceInfo[i]; + // Skip any interface that is midway through association; the // WlanGetNetworkBssList function call is known to hang indefinitely - // when it's in this state. http://crbug.com/39300 - if (interface_list->InterfaceInfo[i].isState == - wlan_interface_state_associating) { - LOG(WARNING) << "Skipping wifi scan on adapter " << i << " (" - << interface_list->InterfaceInfo[i].strInterfaceDescription - << ") in 'associating' state. Repeated occurrences " - "indicates a non-responding adapter."; + // when it's in this state. https://crbug.com/39300 + if (interface_info.isState == wlan_interface_state_associating) { + DLOG(WARNING) << "Skipping wifi scan on adapter " << i << " (" + << interface_info.strInterfaceDescription + << ") in 'associating' state. Repeated occurrences " + "indicates a non-responding adapter."; continue; } - GetInterfaceDataWLAN(wlan_handle, - interface_list->InterfaceInfo[i].InterfaceGuid, data); + GetInterfaceDataWLAN(wlan_handle, interface_info.InterfaceGuid, data); } - // Free interface_list. (*WlanFreeMemory_function_)(interface_list); - // Close the handle. - if ((*WlanCloseHandle_function_)(wlan_handle, NULL) != ERROR_SUCCESS) { - return false; - } - - return true; + return (*WlanCloseHandle_function_)(wlan_handle, NULL) == ERROR_SUCCESS; } -// Appends the data for a single interface to the data vector. Returns the -// number of access points found, or -1 on error. -int WindowsWlanApi::GetInterfaceDataWLAN(const HANDLE wlan_handle, - const GUID& interface_id, - WifiData::AccessPointDataSet* data) { - DCHECK(data); - - const base::TimeTicks start_time = base::TimeTicks::Now(); - - // WlanGetNetworkBssList allocates bss_list. - WLAN_BSS_LIST* bss_list = NULL; +// Appends the data for a single interface to |data|. Returns false for error. +bool WindowsWlanApi::GetInterfaceDataWLAN(const HANDLE wlan_handle, + const GUID& interface_id, + WifiData::AccessPointDataSet* data) { + base::ElapsedTimer wlan_get_network_list_timer; + // WlanGetNetworkBssList allocates |bss_list|. + WLAN_BSS_LIST* bss_list = nullptr; if ((*WlanGetNetworkBssList_function_)(wlan_handle, &interface_id, NULL, // Use all SSIDs. dot11_BSS_type_any, false, // bSecurityEnabled - unused NULL, // reserved &bss_list) != ERROR_SUCCESS) { - return -1; + return false; } - // According to http://www.attnetclient.com/kb/questions.php?questionid=75 - // WlanGetNetworkBssList can sometimes return success, but leave the bss - // list as NULL. + // WlanGetNetworkBssList() can return success without filling |bss_list|. if (!bss_list) - return -1; + return false; - const base::TimeDelta duration = base::TimeTicks::Now() - start_time; - - UMA_HISTOGRAM_CUSTOM_TIMES("Net.Wifi.ScanLatency", duration, + UMA_HISTOGRAM_CUSTOM_TIMES("Net.Wifi.ScanLatency", + wlan_get_network_list_timer.Elapsed(), base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 100); - int found = 0; - for (int i = 0; i < static_cast<int>(bss_list->dwNumberOfItems); ++i) { - AccessPointData access_point_data; - if (GetNetworkData(bss_list->wlanBssEntries[i], &access_point_data)) { - ++found; - data->insert(access_point_data); - } - } + for (size_t i = 0; i < bss_list->dwNumberOfItems; ++i) + data->insert(GetNetworkData(bss_list->wlanBssEntries[i])); (*WlanFreeMemory_function_)(bss_list); - return found; -} - -// WindowsNdisApi -WindowsNdisApi::WindowsNdisApi( - std::vector<base::string16>* interface_service_names) - : oid_buffer_size_(kInitialBufferSize) { - DCHECK(!interface_service_names->empty()); - interface_service_names_.swap(*interface_service_names); -} - -WindowsNdisApi::~WindowsNdisApi() {} - -std::unique_ptr<WindowsNdisApi> WindowsNdisApi::Create() { - std::vector<base::string16> interface_service_names; - if (GetInterfacesNDIS(&interface_service_names)) - return base::MakeUnique<WindowsNdisApi>(&interface_service_names); - return nullptr; -} - -bool WindowsNdisApi::GetAccessPointData(WifiData::AccessPointDataSet* data) { - DCHECK(data); - int interfaces_failed = 0; - int interfaces_succeeded = 0; - - for (int i = 0; i < static_cast<int>(interface_service_names_.size()); ++i) { - // First, check that we have a DOS device for this adapter. - if (!DefineDosDeviceIfNotExists(interface_service_names_[i])) - continue; - - // Get the handle to the device. This will fail if the named device is not - // valid. - HANDLE adapter_handle = GetFileHandle(interface_service_names_[i]); - if (adapter_handle == INVALID_HANDLE_VALUE) - continue; - - // Get the data. - if (GetInterfaceDataNDIS(adapter_handle, data)) - ++interfaces_succeeded; - else - ++interfaces_failed; - - // Clean up. - CloseHandle(adapter_handle); - UndefineDosDevice(interface_service_names_[i]); - } - - // Return true if at least one interface succeeded, or at the very least none - // failed. - return interfaces_succeeded > 0 || interfaces_failed == 0; -} - -bool WindowsNdisApi::GetInterfacesNDIS( - std::vector<base::string16>* interface_service_names_out) { - HKEY network_cards_key = NULL; - if (RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - L"Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards", 0, - KEY_READ, &network_cards_key) != ERROR_SUCCESS) { - return false; - } - DCHECK(network_cards_key); - - for (int i = 0;; ++i) { - TCHAR name[kStringLength]; - DWORD name_size = kStringLength; - FILETIME time; - if (RegEnumKeyEx(network_cards_key, i, name, &name_size, NULL, NULL, NULL, - &time) != ERROR_SUCCESS) { - break; - } - HKEY hardware_key = NULL; - if (RegOpenKeyEx(network_cards_key, name, 0, KEY_READ, &hardware_key) != - ERROR_SUCCESS) { - break; - } - DCHECK(hardware_key); - - TCHAR service_name[kStringLength]; - DWORD service_name_size = kStringLength; - DWORD type = 0; - if (RegQueryValueEx(hardware_key, L"ServiceName", NULL, &type, - reinterpret_cast<LPBYTE>(service_name), - &service_name_size) == ERROR_SUCCESS) { - interface_service_names_out->push_back(service_name); - } - RegCloseKey(hardware_key); - } - - RegCloseKey(network_cards_key); return true; } -bool WindowsNdisApi::GetInterfaceDataNDIS(HANDLE adapter_handle, - WifiData::AccessPointDataSet* data) { - DCHECK(data); +} // anonymous namespace - std::unique_ptr<BYTE, base::FreeDeleter> buffer( - static_cast<BYTE*>(malloc(oid_buffer_size_))); - if (!buffer) - return false; - - DWORD bytes_out; - int result; - - while (true) { - bytes_out = 0; - result = PerformQuery(adapter_handle, buffer.get(), oid_buffer_size_, - &bytes_out); - if (result == ERROR_GEN_FAILURE || // Returned by some Intel cards. - result == ERROR_INSUFFICIENT_BUFFER || result == ERROR_MORE_DATA || - result == NDIS_STATUS_INVALID_LENGTH || - result == NDIS_STATUS_BUFFER_TOO_SHORT) { - // The buffer we supplied is too small, so increase it. bytes_out should - // provide the required buffer size, but this is not always the case. - if (bytes_out > static_cast<DWORD>(oid_buffer_size_)) - oid_buffer_size_ = bytes_out; - else - oid_buffer_size_ *= 2; - - if (!ResizeBuffer(oid_buffer_size_, &buffer)) { - oid_buffer_size_ = kInitialBufferSize; // Reset for next time. - return false; - } - } else { - // The buffer is not too small. - break; - } - } - DCHECK(buffer.get()); - - if (result == ERROR_SUCCESS) { - NDIS_802_11_BSSID_LIST* bssid_list = - reinterpret_cast<NDIS_802_11_BSSID_LIST*>(buffer.get()); - GetDataFromBssIdList(*bssid_list, oid_buffer_size_, data); - } - - return true; +WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() { + return new WifiDataProviderWin(); } -bool GetNetworkData(const WLAN_BSS_ENTRY& bss_entry, - AccessPointData* access_point_data) { - // Currently we get only MAC address, signal strength and SSID. - DCHECK(access_point_data); - access_point_data->mac_address = MacAddressAsString16(bss_entry.dot11Bssid); - access_point_data->radio_signal_strength = bss_entry.lRssi; - // bss_entry.dot11Ssid.ucSSID is not null-terminated. - base::UTF8ToUTF16(reinterpret_cast<const char*>(bss_entry.dot11Ssid.ucSSID), - static_cast<ULONG>(bss_entry.dot11Ssid.uSSIDLength), - &access_point_data->ssid); - // TODO(steveblock): Is it possible to get the following? - // access_point_data->signal_to_noise - // access_point_data->age - // access_point_data->channel - return true; +WifiDataProviderWin::WifiDataProviderWin() = default; + +WifiDataProviderWin::~WifiDataProviderWin() = default; + +std::unique_ptr<WifiDataProviderCommon::WlanApiInterface> +WifiDataProviderWin::CreateWlanApi() { + return WindowsWlanApi::Create(); } -bool UndefineDosDevice(const base::string16& device_name) { - // We remove only the mapping we use, that is \Device\<device_name>. - base::string16 target_path = L"\\Device\\" + device_name; - return DefineDosDevice(DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | - DDD_EXACT_MATCH_ON_REMOVE, - device_name.c_str(), target_path.c_str()) == TRUE; +std::unique_ptr<WifiPollingPolicy> WifiDataProviderWin::CreatePollingPolicy() { + return base::MakeUnique<GenericWifiPollingPolicy< + kDefaultPollingIntervalMs, kNoChangePollingIntervalMs, + kTwoNoChangePollingIntervalMs, kNoWifiPollingIntervalMs>>(); } -bool DefineDosDeviceIfNotExists(const base::string16& device_name) { - // We create a DOS device name for the device at \Device\<device_name>. - base::string16 target_path = L"\\Device\\" + device_name; - - TCHAR target[kStringLength]; - if (QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 && - target_path.compare(target) == 0) { - // Device already exists. - return true; - } - - if (GetLastError() != ERROR_FILE_NOT_FOUND) - return false; - - if (!DefineDosDevice(DDD_RAW_TARGET_PATH, device_name.c_str(), - target_path.c_str())) { - return false; - } - - // Check that the device is really there. - return QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 && - target_path.compare(target) == 0; -} - -HANDLE GetFileHandle(const base::string16& device_name) { - // We access a device with DOS path \Device\<device_name> at - // \\.\<device_name>. - base::string16 formatted_device_name = L"\\\\.\\" + device_name; - - return CreateFile(formatted_device_name.c_str(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode - 0, // security attributes - OPEN_EXISTING, - 0, // flags and attributes - INVALID_HANDLE_VALUE); -} - -int PerformQuery(HANDLE adapter_handle, - BYTE* buffer, - DWORD buffer_size, - DWORD* bytes_out) { - DWORD oid = OID_802_11_BSSID_LIST; - if (!DeviceIoControl(adapter_handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, - sizeof(oid), buffer, buffer_size, bytes_out, NULL)) { - return GetLastError(); - } - return ERROR_SUCCESS; -} - -bool ResizeBuffer(int requested_size, - std::unique_ptr<BYTE, base::FreeDeleter>* buffer) { - DCHECK_GT(requested_size, 0); - DCHECK(buffer); - if (requested_size > kMaximumBufferSize) { - buffer->reset(); - return false; - } - - buffer->reset( - reinterpret_cast<BYTE*>(realloc(buffer->release(), requested_size))); - return buffer != NULL; -} - -bool GetSystemDirectory(base::string16* path) { - DCHECK(path); - // Return value includes terminating NULL. - int buffer_size = ::GetSystemDirectory(NULL, 0); - if (buffer_size == 0) - return false; - std::unique_ptr<base::char16[]> buffer(new base::char16[buffer_size]); - - // Return value excludes terminating NULL. - int characters_written = ::GetSystemDirectory(buffer.get(), buffer_size); - if (characters_written == 0) - return false; - DCHECK_EQ(buffer_size - 1, characters_written); - - path->assign(buffer.get(), characters_written); - - if (*path->rbegin() != L'\\') - path->append(L"\\"); - DCHECK_EQ(L'\\', *path->rbegin()); - return true; -} -} // namespace - } // namespace device
diff --git a/extensions/browser/api/system_cpu/cpu_info_provider.cc b/extensions/browser/api/system_cpu/cpu_info_provider.cc index e926aaa..aca7c2a5 100644 --- a/extensions/browser/api/system_cpu/cpu_info_provider.cc +++ b/extensions/browser/api/system_cpu/cpu_info_provider.cc
@@ -6,6 +6,10 @@ #include "base/sys_info.h" +#if defined(OS_CHROMEOS) +#include "chromeos/system/cpu_temperature_reader.h" +#endif // defined(OS_CHROMEOS) + namespace extensions { using api::system_cpu::CpuInfo; @@ -39,6 +43,19 @@ // Initialize the ProcessorInfos, or return an empty array if that fails. if (!QueryCpuTimePerProcessor(&info_.processors)) info_.processors.clear(); + +#if defined(OS_CHROMEOS) + using CPUTemperatureInfo = + chromeos::system::CPUTemperatureReader::CPUTemperatureInfo; + std::vector<CPUTemperatureInfo> cpu_temp_info = + chromeos::system::CPUTemperatureReader().GetCPUTemperatures(); + info_.temperatures.clear(); + info_.temperatures.reserve(cpu_temp_info.size()); + for (const CPUTemperatureInfo& info : cpu_temp_info) { + info_.temperatures.push_back(info.temp_celsius); + } +#endif // defined(OS_CHROMEOS) + return true; }
diff --git a/extensions/browser/api/system_cpu/system_cpu_apitest.cc b/extensions/browser/api/system_cpu/system_cpu_apitest.cc index eabacff..5685db5 100644 --- a/extensions/browser/api/system_cpu/system_cpu_apitest.cc +++ b/extensions/browser/api/system_cpu/system_cpu_apitest.cc
@@ -28,6 +28,10 @@ info_.processors[0].usage.user = 2; info_.processors[0].usage.idle = 3; info_.processors[0].usage.total = 6; + + // The fractional part of these values should be exactly represented as + // floating points to avoid rounding errors. + info_.temperatures = {30.125, 40.0625}; return true; }
diff --git a/extensions/common/api/networking_private.idl b/extensions/common/api/networking_private.idl index 4e3be9b..b0b0126 100644 --- a/extensions/common/api/networking_private.idl +++ b/extensions/common/api/networking_private.idl
@@ -583,15 +583,10 @@ dictionary TetherProperties { long? BatteryPercentage; DOMString? Carrier; + boolean HasConnectedToHost; long? SignalStrength; }; - dictionary ManagedTetherProperties { - ManagedLong? BatteryPercentage; - ManagedDOMString? Carrier; - ManagedLong? SignalStrength; - }; - dictionary VPNProperties { boolean? AutoConnect; DOMString? Host; @@ -732,7 +727,7 @@ ManagedIPConfigProperties? StaticIPConfig; IPConfigProperties? SavedIPConfig; DOMString? Source; - ManagedTetherProperties? Tether; + TetherProperties? Tether; NetworkType Type; ManagedVPNProperties? VPN; ManagedWiFiProperties? WiFi;
diff --git a/extensions/common/api/system_cpu.idl b/extensions/common/api/system_cpu.idl index bb3ac85..e962261 100644 --- a/extensions/common/api/system_cpu.idl +++ b/extensions/common/api/system_cpu.idl
@@ -44,6 +44,12 @@ // Information about each logical processor. ProcessorInfo[] processors; + + // List of CPU temperature readings from each thermal zone of the CPU. + // Temperatures are in degrees Celsius. + // + // <b>Currently supported on Chrome OS only.</b> + double[] temperatures; }; callback CpuInfoCallback = void (CpuInfo info);
diff --git a/extensions/common/extension.h b/extensions/common/extension.h index b87cc5f2dd..704b7dd 100644 --- a/extensions/common/extension.h +++ b/extensions/common/extension.h
@@ -324,14 +324,19 @@ return (creation_flags_ & WAS_INSTALLED_BY_OEM) != 0; } - // Type-related queries. + // Type-related queries. These are all mutually exclusive. + // + // The differences between the types of Extension are documented here: + // https://chromium.googlesource.com/chromium/src/+/HEAD/extensions/docs/extension_and_app_types.md + bool is_platform_app() const; // aka "V2 app", "V2 packaged app" + bool is_hosted_app() const; // Hosted app (or bookmark app) + bool is_legacy_packaged_app() const; // aka "V1 packaged app" + bool is_extension() const; // Regular browser extension, not an app + bool is_shared_module() const; // Shared module + bool is_theme() const; // Theme + + // True if this is a platform app, hosted app, or legacy packaged app. bool is_app() const; - bool is_platform_app() const; - bool is_hosted_app() const; - bool is_legacy_packaged_app() const; - bool is_extension() const; - bool is_shared_module() const; - bool is_theme() const; void AddWebExtentPattern(const URLPattern& pattern); const URLPatternSet& web_extent() const { return extent_; }
diff --git a/extensions/docs/extension_and_app_types.md b/extensions/docs/extension_and_app_types.md index b409a4b..d9ce660 100644 --- a/extensions/docs/extension_and_app_types.md +++ b/extensions/docs/extension_and_app_types.md
@@ -14,6 +14,25 @@ without any UI. They may interact with the browser or tab contents, and can request more extensive permissions than apps. +A browser extension can be identified by a `manifest.json` file without any key +named `app`, `export`, or `theme`. + +## Themes + +A theme is a special kind of extension that changes the way the browser looks. +Themes are packaged like regular extensions, but they don't contain JavaScript +or HTML code. + +A theme can be identified by the presence of a `theme` key in `manifest.json`. + +## Shared Modules + +Shared modules are permissionless collections of resources that can be shared +between other extensions and apps. + +A shared module can be identified by the presence of an `export` key in +`manifest.json`. + ## Apps ### Platform app @@ -29,6 +48,10 @@ Platform apps are deprecated on non-Chrome OS platforms. +A platform app can be identified by the presence of an `app.background` key +in the manifest, which provides the script that runs when the app is +launched. + ### Packaged app (legacy) [Legacy (v1) packaged apps](https://developer.chrome.com/extensions/apps) @@ -36,40 +59,53 @@ around a website -- with the power of extension APIs. With the launch of platform apps and the app-specific APIs, legacy packaged apps are deprecated. +A packaged app can be identified by the presence of an +`app.launch.local_url` key in `manifest.json`, which identifies the resource +in the .crx that's loaded when the app is launched. + ### Hosted app A [hosted app](https://developer.chrome.com/webstore/hosted_apps) is mostly metadata: a web URL to launch, a list of associated URLs, and a list of HTML5 permissions. Chrome ask for these permissions during the app's installation, allowing the associated URL to bypass the normal Chrome permission prompts for -HTML5 features. +HTML5 features. Other than metadata in the manifest and an icon, none of a +hosted app's resources come from the extension system. + +A hosted app can be identified by the presence of an `app.launch.web_url` key in +`manifest.json`, which provides http/https URL that is loaded when the app is +launched. ### Bookmark app A bookmark app is a simplified hosted app that Chrome creates on demand. When -the user taps "Add to desktop" (or "Add to shelf" on Chrome OS) in the Chrome -menu, Chrome creates a barebones app whose manifest specifies the current tab's -URL. A shortcut to this URL appears in chrome://apps using the site's favicon. +the user taps "More Tools > Add to desktop..." (or "Add to shelf" on Chrome OS) +in the Chrome menu, Chrome creates a barebones app whose manifest specifies the +current tab's URL. A shortcut to this URL appears in chrome://apps using the +site's favicon. Chrome then creates a desktop shortcut that will open a browser window with flags that specify the app and profile. Activating the icon launches the "bookmarked" URL in a tab or a window. -## Manifest +A bookmark app's `manifest.json` identifies it as a hosted app. However, in the +C++ code, the `Extension` object will return true from its `from_bookmark()` +method. -A particular manifest key in an extension's `manifest.json` file determines what -kind of extension it is: +## Ambiguity surrounding the term "Extension" -* Platform app: `app.background.page` and/or `app.background.scripts` -* Legacy packaged app: `app.launch.local_path` -* Hosted app: `app.launch.web_url` -* Browser extension: none of the above +In the C++ code, all of the above flavors of extensions and apps are implemented +in terms of the `Extension` class type, and the `//extensions` module. This can +cause confusion, since it means that an app *is-an* `Extension`, although +`Extension::is_extension()` is false. -## Notes +In code comments, "extension" may be used to refer to non-app extensions, also +known as *browser extensions*. -`Extension` is the class type for all extensions and apps, so technically -speaking, an app *is-an* `Extension`. The word "extension" usually refers only -to non-app extensions, a.k.a. *browser extensions*. +The three categories of apps are significantly different in terms of +implementation, capabilities, process model, and restrictions. It is usually +necessary to consider them as three separate cases, rather than lumping them +together. ## See also
diff --git a/extensions/test/data/system/cpu/test_cpu_api.js b/extensions/test/data/system/cpu/test_cpu_api.js index 746b46e9..ff7f978c 100644 --- a/extensions/test/data/system/cpu/test_cpu_api.js +++ b/extensions/test/data/system/cpu/test_cpu_api.js
@@ -22,6 +22,7 @@ chrome.test.assertEq("unknown", result.modelName); chrome.test.assertEq(["mmx", "avx"], result.features); chrome.test.assertEq(expectedProcessors, result.processors); + chrome.test.assertEq([30.125, 40.0625], result.temperatures); })); } }
diff --git a/gpu/ipc/service/pass_through_image_transport_surface.cc b/gpu/ipc/service/pass_through_image_transport_surface.cc index a35c9ee..a8e7cbc 100644 --- a/gpu/ipc/service/pass_through_image_transport_surface.cc +++ b/gpu/ipc/service/pass_through_image_transport_surface.cc
@@ -170,7 +170,7 @@ g_num_swaps_in_current_swap_generation_++; bool should_override_vsync = - (g_num_swaps_in_current_swap_generation_ > 1) && + (g_num_swaps_in_current_swap_generation_ > 1) || (g_current_swap_generation_ - g_last_multi_window_swap_generation_ < kMultiWindowSwapEnableVSyncDelay); gl::GLContext::GetCurrent()->ForceSwapIntervalZero(should_override_vsync);
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg index b9cb514..903732636 100644 --- a/infra/config/cq.cfg +++ b/infra/config/cq.cfg
@@ -3,7 +3,6 @@ version: 1 cq_name: "chromium" -in_production: false cq_status_url: "https://chromium-cq-status.appspot.com" git_repo_url: "https://chromium.googlesource.com/chromium/src" commit_burst_delay: 60
diff --git a/ios/chrome/browser/ui/autofill/autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/autofill_client_ios.mm index 377e7e74f..763bc49 100644 --- a/ios/chrome/browser/ui/autofill/autofill_client_ios.mm +++ b/ios/chrome/browser/ui/autofill/autofill_client_ios.mm
@@ -118,7 +118,7 @@ infobar_manager_->AddInfoBar(CreateSaveCardInfoBarMobile( base::MakeUnique<AutofillSaveCardInfoBarDelegateMobile>( false, card, std::unique_ptr<base::DictionaryValue>(nullptr), - callback))); + callback, GetPrefs()))); } void AutofillClientIOS::ConfirmSaveCreditCardToCloud( @@ -128,7 +128,7 @@ const base::Closure& callback) { infobar_manager_->AddInfoBar(CreateSaveCardInfoBarMobile( base::MakeUnique<AutofillSaveCardInfoBarDelegateMobile>( - true, card, std::move(legal_message), callback))); + true, card, std::move(legal_message), callback, GetPrefs()))); } void AutofillClientIOS::ConfirmCreditCardFillAssist(
diff --git a/mash/simple_wm/move_event_handler.cc b/mash/simple_wm/move_event_handler.cc index 99582ed..4e1d58aa 100644 --- a/mash/simple_wm/move_event_handler.cc +++ b/mash/simple_wm/move_event_handler.cc
@@ -9,32 +9,33 @@ #include "ui/aura/mus/window_port_mus.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" +#include "ui/base/cursor/cursor.h" #include "ui/base/hit_test.h" #include "ui/events/event.h" namespace simple_wm { namespace { -ui::mojom::CursorType CursorForWindowComponent(int window_component) { +ui::CursorType CursorForWindowComponent(int window_component) { switch (window_component) { case HTBOTTOM: - return ui::mojom::CursorType::kSouthResize; + return ui::CursorType::kSouthResize; case HTBOTTOMLEFT: - return ui::mojom::CursorType::kSouthWestResize; + return ui::CursorType::kSouthWestResize; case HTBOTTOMRIGHT: - return ui::mojom::CursorType::kSouthEastResize; + return ui::CursorType::kSouthEastResize; case HTLEFT: - return ui::mojom::CursorType::kWestResize; + return ui::CursorType::kWestResize; case HTRIGHT: - return ui::mojom::CursorType::kEastResize; + return ui::CursorType::kEastResize; case HTTOP: - return ui::mojom::CursorType::kNorthResize; + return ui::CursorType::kNorthResize; case HTTOPLEFT: - return ui::mojom::CursorType::kNorthWestResize; + return ui::CursorType::kNorthWestResize; case HTTOPRIGHT: - return ui::mojom::CursorType::kNorthEastResize; + return ui::CursorType::kNorthEastResize; default: - return ui::mojom::CursorType::kNull; + return ui::CursorType::kNull; } } @@ -78,8 +79,8 @@ move_loop_ = MoveLoop::Create(window_, ht_location, *pointer_event.get()); } else if (pointer_event->type() == ui::ET_POINTER_MOVED) { const int ht_location = GetNonClientComponentForEvent(pointer_event.get()); - aura::WindowPortMus::Get(window_)->SetPredefinedCursor( - CursorForWindowComponent(ht_location)); + aura::WindowPortMus::Get(window_)->SetCursor( + ui::CursorData(CursorForWindowComponent(ht_location))); } if (had_move_loop || move_loop_) event->SetHandled();
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index 97695bee..19b1879 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -331,7 +331,7 @@ bool WebMediaPlayerImpl::SupportsOverlayFullscreenVideo() { #if defined(OS_ANDROID) - return true; + return !using_media_player_renderer_; #else return false; #endif
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc index e5d592ef..53cf47c 100644 --- a/media/filters/decoder_stream.cc +++ b/media/filters/decoder_stream.cc
@@ -289,6 +289,8 @@ decrypting_demuxer_stream_ = std::move(decrypting_demuxer_stream); stream_ = decrypting_demuxer_stream_.get(); } + if (decoder_change_observer_cb_) + decoder_change_observer_cb_.Run(decoder_.get()); // TODO(tguilbert): crbug.com/603713 support config changes on decoder reinit. if (received_config_change_during_reinit_) {
diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h index 28a11eb..97ab970 100644 --- a/media/filters/decoder_stream.h +++ b/media/filters/decoder_stream.h
@@ -106,12 +106,19 @@ // Allows callers to register for notification of config changes; this is // called immediately after receiving the 'kConfigChanged' status from the // DemuxerStream, before any action is taken to handle the config change. - typedef base::Closure ConfigChangeObserverCB; + using ConfigChangeObserverCB = base::Closure; void set_config_change_observer( - const ConfigChangeObserverCB& config_change_observer) { + ConfigChangeObserverCB config_change_observer) { config_change_observer_cb_ = config_change_observer; } + // Allows tests to keep track the currently selected decoder. + using DecoderChangeObserverCB = base::RepeatingCallback<void(Decoder*)>; + void set_decoder_change_observer_for_testing( + DecoderChangeObserverCB decoder_change_observer_cb) { + decoder_change_observer_cb_ = std::move(decoder_change_observer_cb); + } + int get_pending_buffers_size_for_testing() const { return pending_buffers_.size(); } @@ -207,6 +214,7 @@ std::unique_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream_; ConfigChangeObserverCB config_change_observer_cb_; + DecoderChangeObserverCB decoder_change_observer_cb_; // An end-of-stream buffer has been sent for decoding, no more buffers should // be sent for decoding until it completes.
diff --git a/media/filters/fake_video_decoder.cc b/media/filters/fake_video_decoder.cc index 013ceca..06c4e7f 100644 --- a/media/filters/fake_video_decoder.cc +++ b/media/filters/fake_video_decoder.cc
@@ -10,10 +10,12 @@ namespace media { -FakeVideoDecoder::FakeVideoDecoder(int decoding_delay, +FakeVideoDecoder::FakeVideoDecoder(const std::string& decoder_name, + int decoding_delay, int max_parallel_decoding_requests, const BytesDecodedCB& bytes_decoded_cb) - : decoding_delay_(decoding_delay), + : decoder_name_(decoder_name), + decoding_delay_(decoding_delay), max_parallel_decoding_requests_(max_parallel_decoding_requests), bytes_decoded_cb_(bytes_decoded_cb), state_(STATE_UNINITIALIZED), @@ -47,7 +49,7 @@ } std::string FakeVideoDecoder::GetDisplayName() const { - return "FakeVideoDecoder"; + return decoder_name_; } void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config,
diff --git a/media/filters/fake_video_decoder.h b/media/filters/fake_video_decoder.h index 3ac932f..4c5568f 100644 --- a/media/filters/fake_video_decoder.h +++ b/media/filters/fake_video_decoder.h
@@ -34,7 +34,8 @@ // Constructs an object with a decoding delay of |decoding_delay| frames. // |bytes_decoded_cb| is called after each decode. The sum of the byte // count over all calls will be equal to total_bytes_decoded(). - FakeVideoDecoder(int decoding_delay, + FakeVideoDecoder(const std::string& decoder_name, + int decoding_delay, int max_parallel_decoding_requests, const BytesDecodedCB& bytes_decoded_cb); ~FakeVideoDecoder() override; @@ -98,6 +99,7 @@ base::ThreadChecker thread_checker_; + const std::string decoder_name_; const size_t decoding_delay_; const int max_parallel_decoding_requests_; BytesDecodedCB bytes_decoded_cb_;
diff --git a/media/filters/fake_video_decoder_unittest.cc b/media/filters/fake_video_decoder_unittest.cc index 2cb7f16..7ebcf5e 100644 --- a/media/filters/fake_video_decoder_unittest.cc +++ b/media/filters/fake_video_decoder_unittest.cc
@@ -32,6 +32,7 @@ public: FakeVideoDecoderTest() : decoder_(new FakeVideoDecoder( + "FakeVideoDecoder", GetParam().decoding_delay, GetParam().max_decode_requests, base::Bind(&FakeVideoDecoderTest::OnBytesDecoded, @@ -276,9 +277,10 @@ } TEST_P(FakeVideoDecoderTest, Read_ZeroDelay) { - decoder_.reset(new FakeVideoDecoder( - 0, 1, base::Bind(&FakeVideoDecoderTest::OnBytesDecoded, - base::Unretained(this)))); + decoder_.reset( + new FakeVideoDecoder("FakeVideoDecoder", 0, 1, + base::Bind(&FakeVideoDecoderTest::OnBytesDecoded, + base::Unretained(this)))); Initialize(); while (num_input_buffers_ < kTotalBuffers) {
diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc index 0f6752d..88b5af8 100644 --- a/media/filters/video_frame_stream_unittest.cc +++ b/media/filters/video_frame_stream_unittest.cc
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "media/base/fake_demuxer_stream.h" #include "media/base/gmock_callback_support.h" #include "media/base/mock_filters.h" @@ -28,11 +29,15 @@ using ::testing::SaveArg; using ::testing::StrictMock; -static const int kNumConfigs = 4; -static const int kNumBuffersInOneConfig = 5; - namespace media { +const int kNumConfigs = 4; +const int kNumBuffersInOneConfig = 5; + +static std::string GetDecoderName(int i) { + return std::string("VideoDecoder") + base::IntToString(i); +} + struct VideoFrameStreamTestParams { VideoFrameStreamTestParams(bool is_encrypted, bool has_decryptor, @@ -70,30 +75,32 @@ BytesDecodedCB bytes_decoded_cb = base::Bind( &VideoFrameStreamTest::OnBytesDecoded, base::Unretained(this)); - decoder1_ = new FakeVideoDecoder(decoding_delay, parallel_decoding, - bytes_decoded_cb); - decoder2_ = new FakeVideoDecoder(decoding_delay, parallel_decoding, - bytes_decoded_cb); - decoder3_ = new FakeVideoDecoder(decoding_delay, parallel_decoding, - bytes_decoded_cb); - + // Provide 3 decoders to test fallback cases. // TODO(xhwang): We should test the case where only certain decoder // supports encrypted streams. Currently this is hard to test because we use // parameterized tests which need to pass in all combinations. - if (GetParam().is_encrypted && !GetParam().has_decryptor) { - decoder1_->EnableEncryptedConfigSupport(); - decoder2_->EnableEncryptedConfigSupport(); - decoder3_->EnableEncryptedConfigSupport(); - } - ScopedVector<VideoDecoder> decoders; - decoders.push_back(decoder1_); - decoders.push_back(decoder2_); - decoders.push_back(decoder3_); + for (int i = 0; i < 3; ++i) { + FakeVideoDecoder* decoder = + new FakeVideoDecoder(GetDecoderName(i), decoding_delay, + parallel_decoding, bytes_decoded_cb); + + if (GetParam().is_encrypted && !GetParam().has_decryptor) + decoder->EnableEncryptedConfigSupport(); + + decoders.push_back(decoder); + + // Keep a copy of the raw pointers so we can change the behavior of each + // decoder. + decoders_.push_back(decoder); + } video_frame_stream_.reset(new VideoFrameStream( message_loop_.task_runner(), std::move(decoders), &media_log_)); + video_frame_stream_->set_decoder_change_observer_for_testing(base::Bind( + &VideoFrameStreamTest::OnDecoderChanged, base::Unretained(this))); + if (GetParam().is_encrypted && GetParam().has_decryptor) { decryptor_.reset(new NiceMock<MockDecryptor>()); @@ -118,9 +125,7 @@ EXPECT_EQ(num_decoded_bytes_unreported_, 0); is_initialized_ = false; - decoder1_ = NULL; - decoder2_ = NULL; - decoder3_ = NULL; + decoders_.clear(); video_frame_stream_.reset(); base::RunLoop().RunUntilIdle(); @@ -140,6 +145,11 @@ num_decoded_bytes_unreported_ += count; } + void SimulateDecoderInitFailure(const std::vector<int>& decoder_indices) { + for (const auto& i : decoder_indices) + decoders_[i]->SimulateFailureToInit(); + } + void OnInitialized(bool success) { DCHECK(!pending_read_); DCHECK(!pending_reset_); @@ -147,14 +157,11 @@ pending_initialize_ = false; is_initialized_ = success; - if (!success) { - decoder1_ = NULL; - decoder2_ = NULL; - decoder3_ = NULL; - } + if (!success) + decoders_.clear(); } - void InitializeVideoFrameStream() { + void Initialize() { pending_initialize_ = true; video_frame_stream_->Initialize( demuxer_stream_.get(), base::Bind(&VideoFrameStreamTest::OnInitialized, @@ -166,6 +173,18 @@ base::RunLoop().RunUntilIdle(); } + void OnDecoderChanged(VideoDecoder* decoder) { + if (!decoder) { + decoder_ = nullptr; + return; + } + + std::string name = decoder->GetDisplayName(); + ASSERT_TRUE(GetDecoderName(0) == name || GetDecoderName(1) == name || + GetDecoderName(2) == name); + decoder_ = static_cast<FakeVideoDecoder*>(decoder); + } + // Fake Decrypt() function used by DecryptingDemuxerStream. It does nothing // but removes the DecryptConfig to make the buffer unencrypted. void Decrypt(Decryptor::StreamType stream_type, @@ -240,17 +259,12 @@ DEMUXER_READ_NORMAL, DEMUXER_READ_CONFIG_CHANGE, DECRYPTOR_NO_KEY, - DECODER_INIT, DECODER_REINIT, DECODER_DECODE, DECODER_RESET }; void EnterPendingState(PendingState state) { - EnterPendingState(state, decoder1_); - } - - void EnterPendingState(PendingState state, FakeVideoDecoder* decoder) { DCHECK_NE(state, NOT_PENDING); switch (state) { case DEMUXER_READ_NORMAL: @@ -271,23 +285,18 @@ ReadOneFrame(); break; - case DECODER_INIT: - decoder->HoldNextInit(); - InitializeVideoFrameStream(); - break; - case DECODER_REINIT: - decoder->HoldNextInit(); + decoder_->HoldNextInit(); ReadUntilPending(); break; case DECODER_DECODE: - decoder->HoldDecode(); + decoder_->HoldDecode(); ReadUntilPending(); break; case DECODER_RESET: - decoder->HoldNextReset(); + decoder_->HoldNextReset(); pending_reset_ = true; video_frame_stream_->Reset(base::Bind(&VideoFrameStreamTest::OnReset, base::Unretained(this))); @@ -301,10 +310,6 @@ } void SatisfyPendingCallback(PendingState state) { - SatisfyPendingCallback(state, decoder1_); - } - - void SatisfyPendingCallback(PendingState state, FakeVideoDecoder* decoder) { DCHECK_NE(state, NOT_PENDING); switch (state) { case DEMUXER_READ_NORMAL: @@ -318,20 +323,16 @@ NOTREACHED(); break; - case DECODER_INIT: - decoder->SatisfyInit(); - break; - case DECODER_REINIT: - decoder->SatisfyInit(); + decoder_->SatisfyInit(); break; case DECODER_DECODE: - decoder->SatisfyDecode(); + decoder_->SatisfyDecode(); break; case DECODER_RESET: - decoder->SatisfyReset(); + decoder_->SatisfyReset(); break; case NOT_PENDING: @@ -342,11 +343,6 @@ base::RunLoop().RunUntilIdle(); } - void Initialize() { - EnterPendingState(DECODER_INIT); - SatisfyPendingCallback(DECODER_INIT); - } - void Read() { EnterPendingState(DECODER_DECODE); SatisfyPendingCallback(DECODER_DECODE); @@ -357,9 +353,9 @@ SatisfyPendingCallback(DECODER_RESET); } - void ReadUntilDecoderReinitialized(FakeVideoDecoder* decoder) { - EnterPendingState(DECODER_REINIT, decoder); - SatisfyPendingCallback(DECODER_REINIT, decoder); + void ReadUntilDecoderReinitialized() { + EnterPendingState(DECODER_REINIT); + SatisfyPendingCallback(DECODER_REINIT); } base::MessageLoop message_loop_; @@ -373,11 +369,13 @@ // e.g. RegisterNewKeyCB(). std::unique_ptr<NiceMock<MockDecryptor>> decryptor_; + // Raw pointers to the list of decoders to be select from by DecoderSelector. // Three decoders are needed to test that decoder fallback can occur more than // once on a config change. They are owned by |video_frame_stream_|. - FakeVideoDecoder* decoder1_; - FakeVideoDecoder* decoder2_; - FakeVideoDecoder* decoder3_; + std::vector<FakeVideoDecoder*> decoders_; + + // The current decoder used by |video_frame_stream_|. + FakeVideoDecoder* decoder_; bool is_initialized_; int num_decoded_frames_; @@ -425,16 +423,13 @@ } TEST_P(VideoFrameStreamTest, AllDecoderInitializationFails) { - decoder1_->SimulateFailureToInit(); - decoder2_->SimulateFailureToInit(); - decoder3_->SimulateFailureToInit(); + SimulateDecoderInitFailure({0, 1, 2}); Initialize(); EXPECT_FALSE(is_initialized_); } TEST_P(VideoFrameStreamTest, PartialDecoderInitializationFails) { - decoder1_->SimulateFailureToInit(); - decoder2_->SimulateFailureToInit(); + SimulateDecoderInitFailure({0, 1}); Initialize(); EXPECT_TRUE(is_initialized_); } @@ -493,7 +488,7 @@ Initialize(); demuxer_stream_->HoldNextRead(); - decoder1_->HoldDecode(); + decoder_->HoldDecode(); ReadOneFrame(); EXPECT_TRUE(pending_read_); @@ -508,7 +503,7 @@ // Always keep one decode request pending. if (demuxed_buffers > 1) { - decoder1_->SatisfySingleDecode(); + decoder_->SatisfySingleDecode(); base::RunLoop().RunUntilIdle(); } } @@ -518,12 +513,12 @@ // Unblocking one decode request should unblock read even when demuxer is // still blocked. - decoder1_->SatisfySingleDecode(); + decoder_->SatisfySingleDecode(); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(pending_read_); // Stream should still be blocked on the demuxer after unblocking the decoder. - decoder1_->SatisfyDecode(); + decoder_->SatisfyDecode(); ReadUntilPending(); EXPECT_TRUE(pending_read_); @@ -544,7 +539,7 @@ return; Initialize(); - decoder1_->HoldDecode(); + decoder_->HoldDecode(); // Read all of the frames up to end of stream. Since parallel decoding is // enabled, the end of stream buffer will be sent to the decoder immediately, @@ -553,7 +548,7 @@ for (int frame = 0; frame < kNumBuffersInOneConfig; frame++) { ReadOneFrame(); while (pending_read_) { - decoder1_->SatisfySingleDecode(); + decoder_->SatisfySingleDecode(); base::RunLoop().RunUntilIdle(); } } @@ -564,7 +559,7 @@ ASSERT_TRUE(pending_read_); // Satisfy decoding of the end of stream buffer. The read should complete. - decoder1_->SatisfySingleDecode(); + decoder_->SatisfySingleDecode(); base::RunLoop().RunUntilIdle(); ASSERT_FALSE(pending_read_); EXPECT_EQ(last_read_status_, VideoFrameStream::OK); @@ -665,7 +660,8 @@ } TEST_P(VideoFrameStreamTest, Destroy_DuringInitialization) { - EnterPendingState(DECODER_INIT); + decoders_[0]->HoldNextInit(); + Initialize(); } TEST_P(VideoFrameStreamTest, Destroy_AfterInitialization) { @@ -748,17 +744,20 @@ Reset(); } +// The following tests cover the fallback logic. + TEST_P(VideoFrameStreamTest, FallbackDecoder_SelectedOnInitialDecodeError) { Initialize(); - decoder1_->SimulateError(); + decoder_->SimulateError(); ReadOneFrame(); - // |video_frame_stream_| should have fallen back to |decoder2_|. + // |video_frame_stream_| should have fallen back to a new decoder. + ASSERT_EQ(GetDecoderName(1), decoder_->GetDisplayName()); ASSERT_FALSE(pending_read_); ASSERT_EQ(VideoFrameStream::OK, last_read_status_); - // Can't check |decoder1_| right now, it might have been destroyed already. - ASSERT_GT(decoder2_->total_bytes_decoded(), 0); + // Check that we fallbacked to Decoder2. + ASSERT_GT(decoder_->total_bytes_decoded(), 0); // Verify no frame was dropped. ReadAllFrames(); @@ -771,14 +770,14 @@ return; Initialize(); - decoder1_->HoldDecode(); + decoder_->HoldDecode(); ReadOneFrame(); // One buffer should have already pulled from the demuxer stream. Set the next // one to be an EOS. demuxer_stream_->SeekToEndOfStream(); - decoder1_->SatisfySingleDecode(); + decoder_->SatisfySingleDecode(); base::RunLoop().RunUntilIdle(); // |video_frame_stream_| should not have emited a frame. @@ -787,15 +786,17 @@ // Pending buffers should contain a regular buffer and an EOS buffer. EXPECT_EQ(video_frame_stream_->get_pending_buffers_size_for_testing(), 2); - decoder1_->SimulateError(); + decoder_->SimulateError(); base::RunLoop().RunUntilIdle(); - // A frame should have been emited + ASSERT_EQ(GetDecoderName(1), decoder_->GetDisplayName()); + + // A frame should have been emitted. EXPECT_FALSE(pending_read_); EXPECT_EQ(last_read_status_, VideoFrameStream::OK); EXPECT_FALSE( frame_read_->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM)); - EXPECT_GT(decoder2_->total_bytes_decoded(), 0); + EXPECT_GT(decoder_->total_bytes_decoded(), 0); ReadOneFrame(); @@ -811,7 +812,7 @@ return; Initialize(); - decoder1_->HoldDecode(); + decoder_->HoldDecode(); // Queue one read, defer the second. frame_read_ = nullptr; @@ -822,43 +823,48 @@ // Force an error to occur on the first decode, but ensure it isn't propagated // until after the next read has been started. - decoder1_->SimulateError(); - decoder2_->HoldDecode(); + decoder_->SimulateError(); + decoders_[1]->HoldDecode(); // Complete the fallback to the second decoder with the read still pending. base::RunLoop().RunUntilIdle(); - // Can't check |decoder1_| right now, it might have been destroyed already. - // Verify that there was nothing decoded until we kicked the decoder. - EXPECT_EQ(decoder2_->total_bytes_decoded(), 0); - decoder2_->SatisfyDecode(); - const int first_decoded_bytes = decoder2_->total_bytes_decoded(); + ASSERT_EQ(GetDecoderName(1), decoder_->GetDisplayName()); + + // Can't check the original decoder right now, it might have been destroyed + // already. Verify that there was nothing decoded until we kicked the decoder. + EXPECT_EQ(decoder_->total_bytes_decoded(), 0); + decoder_->SatisfyDecode(); + const int first_decoded_bytes = decoder_->total_bytes_decoded(); ASSERT_GT(first_decoded_bytes, 0); // Satisfy the previously pending read and ensure it is decoded. demuxer_stream_->SatisfyRead(); base::RunLoop().RunUntilIdle(); - ASSERT_GT(decoder2_->total_bytes_decoded(), first_decoded_bytes); + ASSERT_GT(decoder_->total_bytes_decoded(), first_decoded_bytes); } TEST_P(VideoFrameStreamTest, FallbackDecoder_SelectedOnInitialDecodeError_Twice) { Initialize(); - decoder1_->SimulateError(); - decoder2_->HoldNextInit(); + decoder_->SimulateError(); + + decoders_[1]->HoldNextInit(); ReadOneFrame(); - decoder2_->SatisfyInit(); - decoder2_->SimulateError(); + decoders_[1]->SatisfyInit(); + decoders_[1]->SimulateError(); base::RunLoop().RunUntilIdle(); - // |video_frame_stream_| should have fallen back to |decoder3_|. + ASSERT_EQ(GetDecoderName(2), decoder_->GetDisplayName()); + + // |video_frame_stream_| should have fallen back to |decoders_[2]|. ASSERT_FALSE(pending_read_); ASSERT_EQ(VideoFrameStream::OK, last_read_status_); - // Can't check |decoder1_| or |decoder2_| right now, they might have been + // Can't check previously selected decoder(s) right now, they might have been // destroyed already. - ASSERT_GT(decoder3_->total_bytes_decoded(), 0); + ASSERT_GT(decoder_->total_bytes_decoded(), 0); // Verify no frame was dropped. ReadAllFrames(); @@ -891,20 +897,20 @@ EnterPendingState(DEMUXER_READ_CONFIG_CHANGE); EXPECT_GT(video_frame_stream_->get_pending_buffers_size_for_testing(), 0); - decoder1_->HoldDecode(); + decoder_->HoldDecode(); SatisfyPendingCallback(DEMUXER_READ_CONFIG_CHANGE); // The flush request should have been sent and held. EXPECT_EQ(video_frame_stream_->get_pending_buffers_size_for_testing(), 0); EXPECT_TRUE(pending_read_); - // Triggering an error here will cause the frames in |decoder1_| to be lost. - // There are no pending buffers buffers to give to give to |decoder2_| due to - // crbug.com/603713. - decoder1_->SimulateError(); + // Triggering an error here will cause the frames in selected decoder to be + // lost. There are no pending buffers to give to |decoders_[1]| due to + // http://crbug.com/603713 + decoder_->SimulateError(); base::RunLoop().RunUntilIdle(); - // We want to make sure that |decoder2_| can decode the rest of the frames + // We want to make sure the fallback decoder can decode the rest of the frames // in the demuxer stream. ReadAllFrames(kNumBuffersInOneConfig * (kNumConfigs - 1)); } @@ -923,7 +929,7 @@ // Block on demuxer read and decoder decode so we can step through. demuxer_stream_->HoldNextRead(); - decoder1_->HoldDecode(); + decoder_->HoldDecode(); ReadOneFrame(); int demuxer_reads_satisfied = 0; @@ -936,7 +942,7 @@ ++demuxer_reads_satisfied; // Decode one buffer. - decoder1_->SatisfySingleDecode(); + decoder_->SatisfySingleDecode(); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(pending_read_); EXPECT_EQ(demuxer_reads_satisfied, @@ -948,18 +954,21 @@ // Hold the init before triggering the error, to verify internal state. demuxer_stream_->SatisfyReadAndHoldNext(); ++demuxer_reads_satisfied; - decoder2_->HoldNextInit(); - decoder1_->SimulateError(); + + decoder_->SimulateError(); + decoders_[1]->HoldNextInit(); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(pending_read_); EXPECT_EQ(demuxer_reads_satisfied, video_frame_stream_->get_pending_buffers_size_for_testing()); - decoder2_->SatisfyInit(); - decoder2_->HoldDecode(); + decoders_[1]->SatisfyInit(); + decoders_[1]->HoldDecode(); base::RunLoop().RunUntilIdle(); + ASSERT_EQ(GetDecoderName(1), decoder_->GetDisplayName()); + // Make sure the pending buffers have been transfered to fallback buffers. // One call to Decode() during the initialization process, so we expect one // buffer to already have been consumed from the fallback buffers. @@ -969,11 +978,11 @@ EXPECT_EQ(demuxer_reads_satisfied, video_frame_stream_->get_pending_buffers_size_for_testing()); - decoder2_->SatisfyDecode(); + decoder_->SatisfyDecode(); base::RunLoop().RunUntilIdle(); - // Make sure all buffers consumed by |decoder2_| have come from the fallback. - // Pending buffers should not have been cleared yet. + // Make sure all buffers consumed by |decoders_[1]| have come from the + // fallback. Pending buffers should not have been cleared yet. EXPECT_EQ(0, video_frame_stream_->get_fallback_buffers_size_for_testing()); EXPECT_EQ(demuxer_reads_satisfied, video_frame_stream_->get_pending_buffers_size_for_testing()); @@ -995,37 +1004,43 @@ TEST_P(VideoFrameStreamTest, FallbackDecoder_SelectedOnDecodeThenInitErrors) { Initialize(); - decoder1_->SimulateError(); - decoder2_->SimulateFailureToInit(); + decoder_->SimulateError(); + SimulateDecoderInitFailure({1}); ReadOneFrame(); - // |video_frame_stream_| should have fallen back to |decoder3_| + ASSERT_EQ(GetDecoderName(2), decoder_->GetDisplayName()); + + // |video_frame_stream_| should have fallen back to |decoders_[2]| ASSERT_FALSE(pending_read_); ASSERT_EQ(VideoFrameStream::OK, last_read_status_); - // Can't check |decoder1_| or |decoder2_| right now, they might have been + // Can't check previously selected decoder(s) right now, they might have been // destroyed already. - ASSERT_GT(decoder3_->total_bytes_decoded(), 0); + ASSERT_GT(decoder_->total_bytes_decoded(), 0); // Verify no frame was dropped. ReadAllFrames(); } TEST_P(VideoFrameStreamTest, FallbackDecoder_SelectedOnInitThenDecodeErrors) { - decoder1_->SimulateFailureToInit(); - decoder2_->HoldDecode(); + SimulateDecoderInitFailure({0}); Initialize(); + ASSERT_EQ(GetDecoderName(1), decoder_->GetDisplayName()); + + decoder_->HoldDecode(); ReadOneFrame(); - decoder2_->SimulateError(); + decoder_->SimulateError(); base::RunLoop().RunUntilIdle(); - // |video_frame_stream_| should have fallen back to |decoder3_| + // |video_frame_stream_| should have fallen back to |decoders_[2]| + ASSERT_EQ(GetDecoderName(2), decoder_->GetDisplayName()); + ASSERT_FALSE(pending_read_); ASSERT_EQ(VideoFrameStream::OK, last_read_status_); - // Can't check |decoder1_| or |decoder2_| right now, they might have been + // Can't check previously selected decoder(s) right now, they might have been // destroyed already. - ASSERT_GT(decoder3_->total_bytes_decoded(), 0); + ASSERT_GT(decoder_->total_bytes_decoded(), 0); // Verify no frame was dropped. ReadAllFrames(); @@ -1038,9 +1053,9 @@ // Successfully received a frame. EXPECT_FALSE(pending_read_); - ASSERT_GT(decoder1_->total_bytes_decoded(), 0); + ASSERT_GT(decoder_->total_bytes_decoded(), 0); - decoder1_->SimulateError(); + decoder_->SimulateError(); // The error must surface from Read() as DECODE_ERROR. while (last_read_status_ == VideoFrameStream::OK) { @@ -1049,26 +1064,26 @@ EXPECT_FALSE(pending_read_); } - // Verify the error was surfaced, rather than falling back to |decoder2_|. + // Verify the error was surfaced, rather than falling back to other decoders. + ASSERT_EQ(GetDecoderName(0), decoder_->GetDisplayName()); EXPECT_FALSE(pending_read_); - ASSERT_EQ(decoder2_->total_bytes_decoded(), 0); ASSERT_EQ(VideoFrameStream::DECODE_ERROR, last_read_status_); } TEST_P(VideoFrameStreamTest, DecoderErrorWhenNotReading) { Initialize(); - decoder1_->HoldDecode(); + decoder_->HoldDecode(); ReadOneFrame(); EXPECT_TRUE(pending_read_); // Satisfy decode requests until we get the first frame out. while (pending_read_) { - decoder1_->SatisfySingleDecode(); + decoder_->SatisfySingleDecode(); base::RunLoop().RunUntilIdle(); } // Trigger an error in the decoding. - decoder1_->SimulateError(); + decoder_->SimulateError(); // The error must surface from Read() as DECODE_ERROR. while (last_read_status_ == VideoFrameStream::OK) { @@ -1081,29 +1096,31 @@ TEST_P(VideoFrameStreamTest, FallbackDecoderSelectedOnFailureToReinitialize) { Initialize(); - decoder1_->SimulateFailureToInit(); - ReadUntilDecoderReinitialized(decoder1_); + decoder_->SimulateFailureToInit(); + ReadUntilDecoderReinitialized(); + ASSERT_EQ(GetDecoderName(1), decoder_->GetDisplayName()); ReadAllFrames(); - ASSERT_GT(decoder2_->total_bytes_decoded(), 0); + ASSERT_GT(decoder_->total_bytes_decoded(), 0); } TEST_P(VideoFrameStreamTest, FallbackDecoderSelectedOnFailureToReinitialize_Twice) { Initialize(); - decoder1_->SimulateFailureToInit(); - ReadUntilDecoderReinitialized(decoder1_); + decoder_->SimulateFailureToInit(); + ReadUntilDecoderReinitialized(); + ASSERT_EQ(GetDecoderName(1), decoder_->GetDisplayName()); ReadOneFrame(); - decoder2_->SimulateFailureToInit(); - ReadUntilDecoderReinitialized(decoder2_); + decoder_->SimulateFailureToInit(); + ReadUntilDecoderReinitialized(); + ASSERT_EQ(GetDecoderName(2), decoder_->GetDisplayName()); ReadAllFrames(); } TEST_P(VideoFrameStreamTest, DecodeErrorAfterFallbackDecoderSelectionFails) { Initialize(); - decoder1_->SimulateFailureToInit(); - decoder2_->SimulateFailureToInit(); - decoder3_->SimulateFailureToInit(); - ReadUntilDecoderReinitialized(decoder1_); + decoder_->SimulateFailureToInit(); + SimulateDecoderInitFailure({1, 2}); + ReadUntilDecoderReinitialized(); // The error will surface from Read() as DECODE_ERROR. while (last_read_status_ == VideoFrameStream::OK) { ReadOneFrame(); @@ -1115,9 +1132,9 @@ TEST_P(VideoFrameStreamTest, Destroy_DuringFallbackDecoderSelection) { Initialize(); - decoder1_->SimulateFailureToInit(); + decoder_->SimulateFailureToInit(); EnterPendingState(DECODER_REINIT); - decoder2_->HoldNextInit(); + decoders_[1]->HoldNextInit(); SatisfyPendingCallback(DECODER_REINIT); }
diff --git a/mojo/public/js/associated_bindings.js b/mojo/public/js/associated_bindings.js index 18ac452..869eedb 100644 --- a/mojo/public/js/associated_bindings.js +++ b/mojo/public/js/associated_bindings.js
@@ -116,6 +116,13 @@ this.reset(); }; + // Indicates whether an error has been encountered. If true, method calls + // on this interface will be dropped (and may already have been dropped). + AssociatedInterfacePtrController.prototype.getEncounteredError = function() { + return this.interfaceEndpointClient_ ? + this.interfaceEndpointClient_.getEncounteredError() : false; + }; + AssociatedInterfacePtrController.prototype.setConnectionErrorHandler = function(callback) { if (!this.isBound()) {
diff --git a/mojo/public/js/lib/interface_endpoint_client.js b/mojo/public/js/lib/interface_endpoint_client.js index b74b6d2..3235434d 100644 --- a/mojo/public/js/lib/interface_endpoint_client.js +++ b/mojo/public/js/lib/interface_endpoint_client.js
@@ -232,6 +232,10 @@ this.controlMessageProxy_.requireVersion(version); }; + InterfaceEndpointClient.prototype.getEncounteredError = function() { + return this.encounteredError_; + }; + var exports = {}; exports.InterfaceEndpointClient = InterfaceEndpointClient;
diff --git a/net/BUILD.gn b/net/BUILD.gn index 4a6d7da..66ba36e9 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -1424,8 +1424,6 @@ "reporting/reporting_client.h", "reporting/reporting_context.cc", "reporting/reporting_context.h", - "reporting/reporting_delegate.cc", - "reporting/reporting_delegate.h", "reporting/reporting_delivery_agent.cc", "reporting/reporting_delivery_agent.h", "reporting/reporting_endpoint_manager.cc",
diff --git a/net/data/ssl/certificates/quic_test.example.com.key.pkcs8.pem b/net/data/ssl/certificates/quic_test.example.com.key.pkcs8.pem new file mode 100644 index 0000000..e52b455f --- /dev/null +++ b/net/data/ssl/certificates/quic_test.example.com.key.pkcs8.pem
@@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDVyhl5jqmrRvBO +t1hts6OaaBBSr/AAlK40vbRQH6MmpJ4ckDdbPejXO7yT+wD7x0lUm/HQmvJRhHtZ +i71m866SWrljjGSn0J7jDFDSz5Od6UoRV5PB3q97WkQdCowiph3GremPFo1OkfHT +8fOC/vZV3HLxEQd17LvpOjWHQ4Fe3ENKt3yhGtXSwUA5aX2JrWQbMTSo6p5eJvxx +0sZr5cJzMD9ZpzWNqaXpPUNBvVTyKuEVDDUwa4vyd8pcB49Y9FR3Xq/OscErp7vA +6X3vGtcD7o9nrcbmHannkT9B59aGIIxTs9h5CeJLFVrYkjtiT2jky9CkTrZ9Pl+w +JOpiYc97AgMBAAECggEAEjCHylfhB7mZaJkg5PSLzu9btC1T9jiwObyKQubuMrN+ +4F9E1naGAQoMGWsZwlJKYvCBuoX0aAslk5DYJJJHIByn+VhQmBaf7iF2HvmaTa0z +qBYTdENGGvCrKu1izu/jSKwzWwFINI8mTCoh1dtrihKflPMl91qVAlr5gvCzaSac +ovZwe8cm51rN5XclJx+o6SONhPUdlUWJ5yEpA4mjV3eC6/IvPOoMmr8GRS9oBB6k +m7yhcaGrSUClc+K3lpFF+3gXD57ABtT23usrNGnti6xnURDYDm+fUX2j8kZEREvj +YGrCNGp+EecrTzhjgaFukysyRXRp7mLvGEqekodcgQKBgQDm1bmKZmE+0FZJIDXD +4xMiipc+srd6KuaCYdJ5i0xt9xTC5KJA5eSmoQn0+hWa8065A91tHiR8u49Ql5xP +6oQw8kA3dpZliZJSL/o7V+aXoMO9/R3H8tbiZn0y7cMYaYr7PGmXC/giSQ5Yi7qE ++yKjKgx35DGEiTajt4FWJ6/siQKBgQDtGKlPyT/k8XGz305qw2W7d8nFFsR4kSJl +pbbWBwrfouiw0hOARCzevZDq6zSGx9QK8Sv5ACM06TrOxSVNsljKayFK0E+Hc5N/ +bNjCDxJd+4CgUNhM2Ta4wvZqW8FGQgphJVUnYu/YahjETWhMiAEOPcm/j7E9k/HQ +BiZixroC4wKBgB3zBuKtC9rxfvB37GHg+V+W6a6p02JXZJbwCDXa2+y8jQYIUgDn +kvYHmNofBGSZQtKAbN82dPd2Ak8rjI1V2Rbcp3ZKvZKo+cIOFYJTkkiEBEGHMLD7 +kePH9mCANrrZHr4gBXcih2wzXFgisO2GA+V1lC6N/dq7TsqJCY/bEFk5AoGBAMAI +nnHCBd9P85EFiAUPGCHb5u+b/ivNGXgM3WbCs3ro/uDgde0IyvLpxSuQr62Owl7O +cZgvFVTwprH8mbcxgZsJZCCtUgzafpfRuEqNXIoEf2zZrieoMxs4xc7lXEikirWe +QDczeiHl5QNx0s1RxtEbGIHwR1Uhs9SSdprAbL6TAoGBAMT3QpWdPNlDoPbSkAC9 +hoUIaRZS8rN/8Ls1lwYf5RxaiTcEKuQ2IYphMRsSzqHbpDxLtWbsWJGd9VARbgc8 +W5DzCmditgUlt9FsawbxqDGO7bkqD4QEkZS67zehDzM2Ir8sy00QZxCi1dJXEBR2 +DUChLmnVRf1yCYz0xmGSRskj +-----END PRIVATE KEY-----
diff --git a/net/reporting/reporting_context.cc b/net/reporting/reporting_context.cc index 047a4a3..c6f01fd 100644 --- a/net/reporting/reporting_context.cc +++ b/net/reporting/reporting_context.cc
@@ -15,7 +15,6 @@ #include "base/time/time.h" #include "net/base/backoff_entry.h" #include "net/reporting/reporting_cache.h" -#include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_delivery_agent.h" #include "net/reporting/reporting_endpoint_manager.h" #include "net/reporting/reporting_garbage_collector.h" @@ -34,10 +33,8 @@ class ReportingContextImpl : public ReportingContext { public: ReportingContextImpl(const ReportingPolicy& policy, - std::unique_ptr<ReportingDelegate> delegate, URLRequestContext* request_context) : ReportingContext(policy, - std::move(delegate), base::MakeUnique<base::DefaultClock>(), base::MakeUnique<base::DefaultTickClock>(), ReportingUploader::Create(request_context)) {} @@ -48,29 +45,12 @@ // static std::unique_ptr<ReportingContext> ReportingContext::Create( const ReportingPolicy& policy, - std::unique_ptr<ReportingDelegate> delegate, URLRequestContext* request_context) { - return base::MakeUnique<ReportingContextImpl>(policy, std::move(delegate), - request_context); + return base::MakeUnique<ReportingContextImpl>(policy, request_context); } ReportingContext::~ReportingContext() {} -void ReportingContext::Initialize() { - DCHECK(!initialized_); - - // This order isn't *critical*, but things will work better with it in this - // order: with the DeliveryAgent after the Persister, it can schedule delivery - // of persisted reports instead of waiting for a new one to be generated, and - // with the GarbageCollector in between, it won't bother scheduling delivery - // of reports that should be discarded instead. - persister_->Initialize(); - garbage_collector_->Initialize(); - delivery_agent_->Initialize(); - - initialized_ = true; -} - void ReportingContext::AddObserver(ReportingObserver* observer) { DCHECK(!observers_.HasObserver(observer)); observers_.AddObserver(observer); @@ -82,24 +62,18 @@ } void ReportingContext::NotifyCacheUpdated() { - if (!initialized_) - return; - for (auto& observer : observers_) observer.OnCacheUpdated(); } ReportingContext::ReportingContext(const ReportingPolicy& policy, - std::unique_ptr<ReportingDelegate> delegate, std::unique_ptr<base::Clock> clock, std::unique_ptr<base::TickClock> tick_clock, std::unique_ptr<ReportingUploader> uploader) : policy_(policy), - delegate_(std::move(delegate)), clock_(std::move(clock)), tick_clock_(std::move(tick_clock)), uploader_(std::move(uploader)), - initialized_(false), cache_(base::MakeUnique<ReportingCache>(this)), endpoint_manager_(base::MakeUnique<ReportingEndpointManager>(this)), delivery_agent_(ReportingDeliveryAgent::Create(this)),
diff --git a/net/reporting/reporting_context.h b/net/reporting/reporting_context.h index ca495a7..34e95d3 100644 --- a/net/reporting/reporting_context.h +++ b/net/reporting/reporting_context.h
@@ -21,7 +21,6 @@ namespace net { class ReportingCache; -class ReportingDelegate; class ReportingDeliveryAgent; class ReportingEndpointManager; class ReportingGarbageCollector; @@ -37,23 +36,11 @@ public: static std::unique_ptr<ReportingContext> Create( const ReportingPolicy& policy, - std::unique_ptr<ReportingDelegate> delegate, URLRequestContext* request_context); ~ReportingContext(); - // Initializes the ReportingContext. This may take a while (e.g. it may - // involve reloading state persisted to disk). Should be called only once. - // - // Components of the ReportingContext won't reference their dependencies (e.g. - // the Clock/TickClock or Timers inside the individual components) until - // during/after the call to Init. - void Initialize(); - - bool initialized() const { return initialized_; } - const ReportingPolicy& policy() { return policy_; } - ReportingDelegate* delegate() { return delegate_.get(); } base::Clock* clock() { return clock_.get(); } base::TickClock* tick_clock() { return tick_clock_.get(); } @@ -77,21 +64,18 @@ protected: ReportingContext(const ReportingPolicy& policy, - std::unique_ptr<ReportingDelegate> delegate, std::unique_ptr<base::Clock> clock, std::unique_ptr<base::TickClock> tick_clock, std::unique_ptr<ReportingUploader> uploader); private: ReportingPolicy policy_; - std::unique_ptr<ReportingDelegate> delegate_; std::unique_ptr<base::Clock> clock_; std::unique_ptr<base::TickClock> tick_clock_; std::unique_ptr<ReportingUploader> uploader_; base::ObserverList<ReportingObserver, /* check_empty= */ true> observers_; - bool initialized_; std::unique_ptr<ReportingCache> cache_; @@ -102,8 +86,7 @@ // and |endpoint_manager_|. std::unique_ptr<ReportingDeliveryAgent> delivery_agent_; - // |persister_| must come after |delegate_|, |clock_|, |tick_clock_|, and - // |cache_|. + // |persister_| must come after |clock_|, |tick_clock_|, and |cache_|. std::unique_ptr<ReportingPersister> persister_; // |garbage_collector_| must come after |tick_clock_| and |cache_|.
diff --git a/net/reporting/reporting_delegate.cc b/net/reporting/reporting_delegate.cc deleted file mode 100644 index cef5baf..0000000 --- a/net/reporting/reporting_delegate.cc +++ /dev/null
@@ -1,13 +0,0 @@ -// 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 "net/reporting/reporting_delegate.h" - -namespace net { - -ReportingDelegate::~ReportingDelegate() {} - -ReportingDelegate::ReportingDelegate() {} - -} // namespace net
diff --git a/net/reporting/reporting_delegate.h b/net/reporting/reporting_delegate.h deleted file mode 100644 index 57d01ab..0000000 --- a/net/reporting/reporting_delegate.h +++ /dev/null
@@ -1,45 +0,0 @@ -// 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 NET_REPORTING_REPORTING_DELEGATE_H_ -#define NET_REPORTING_REPORTING_DELEGATE_H_ - -#include <memory> - -#include "base/macros.h" -#include "net/base/net_export.h" - -namespace base { -class Value; -} // namespace base - -namespace net { - -// Delegate for things that the Reporting system can't do by itself, like -// persisting data across embedder restarts. -class NET_EXPORT ReportingDelegate { - public: - virtual ~ReportingDelegate(); - - // Gets previously persisted data, if any is available. Returns a null pointer - // if no data is available. Can be called any number of times. - virtual std::unique_ptr<const base::Value> GetPersistedData() = 0; - - // Sets data to be persisted across embedder restarts. Ideally, this data will - // be returned by any future calls to GetPersistedData() in this or future - // sessions (until newer data is persisted), but no guarantee is made, since - // the underlying persistence mechanism may or may not be reliable. - virtual void PersistData( - std::unique_ptr<const base::Value> persisted_data) = 0; - - protected: - ReportingDelegate(); - - private: - DISALLOW_COPY_AND_ASSIGN(ReportingDelegate); -}; - -} // namespace net - -#endif // NET_REPORTING_REPORTING_DELEGATE_H_
diff --git a/net/reporting/reporting_delivery_agent.cc b/net/reporting/reporting_delivery_agent.cc index e614aa1..209ea8f 100644 --- a/net/reporting/reporting_delivery_agent.cc +++ b/net/reporting/reporting_delivery_agent.cc
@@ -62,11 +62,6 @@ ~ReportingDeliveryAgentImpl() override { context_->RemoveObserver(this); } - void Initialize() override { - if (CacheHasReports()) - StartTimer(); - } - void SetTimerForTesting(std::unique_ptr<base::Timer> timer) override { DCHECK(!timer_->IsRunning()); timer_ = std::move(timer);
diff --git a/net/reporting/reporting_delivery_agent.h b/net/reporting/reporting_delivery_agent.h index e4ed370..d071b7e 100644 --- a/net/reporting/reporting_delivery_agent.h +++ b/net/reporting/reporting_delivery_agent.h
@@ -55,11 +55,6 @@ virtual ~ReportingDeliveryAgent(); - // Initializes the DeliveryAgent, which schedules delivery (after the Policy's - // delivery_interval) for any previously-persisted reports that can still be - // delivered. - virtual void Initialize() = 0; - // Replaces the internal Timer used for scheduling report delivery attempts // with a caller-specified one so that unittests can provide a MockTimer. virtual void SetTimerForTesting(std::unique_ptr<base::Timer> timer) = 0;
diff --git a/net/reporting/reporting_garbage_collector.cc b/net/reporting/reporting_garbage_collector.cc index 76dbf3a..b6486b4 100644 --- a/net/reporting/reporting_garbage_collector.cc +++ b/net/reporting/reporting_garbage_collector.cc
@@ -24,28 +24,22 @@ public ReportingObserver { public: ReportingGarbageCollectorImpl(ReportingContext* context) - : context_(context), timer_(base::MakeUnique<base::OneShotTimer>()) {} + : context_(context), timer_(base::MakeUnique<base::OneShotTimer>()) { + context_->AddObserver(this); + } // ReportingGarbageCollector implementation: ~ReportingGarbageCollectorImpl() override { - DCHECK(context_->initialized()); context_->RemoveObserver(this); } - void Initialize() override { - context_->AddObserver(this); - CollectGarbage(); - } - void SetTimerForTesting(std::unique_ptr<base::Timer> timer) override { - DCHECK(!context_->initialized()); timer_ = std::move(timer); } // ReportingObserver implementation: void OnCacheUpdated() override { - DCHECK(context_->initialized()); if (!timer_->IsRunning()) StartTimer(); }
diff --git a/net/reporting/reporting_garbage_collector.h b/net/reporting/reporting_garbage_collector.h index 17bd9ab..228f14e 100644 --- a/net/reporting/reporting_garbage_collector.h +++ b/net/reporting/reporting_garbage_collector.h
@@ -28,10 +28,6 @@ virtual ~ReportingGarbageCollector(); - // Initializes the GarbageCollector, which performs an initial garbage - // collection pass over any data already in the Cache. - virtual void Initialize() = 0; - // Replaces the internal Timer used for scheduling garbage collection passes // with a caller-specified one so that unittests can provide a MockTimer. virtual void SetTimerForTesting(std::unique_ptr<base::Timer> timer) = 0;
diff --git a/net/reporting/reporting_persister.cc b/net/reporting/reporting_persister.cc index ec2a37b..4dcc032 100644 --- a/net/reporting/reporting_persister.cc +++ b/net/reporting/reporting_persister.cc
@@ -16,7 +16,6 @@ #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_client.h" #include "net/reporting/reporting_context.h" -#include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_observer.h" #include "net/reporting/reporting_policy.h" #include "net/reporting/reporting_report.h" @@ -61,49 +60,15 @@ return true; } -class ReportingPersisterImpl : public ReportingPersister, - public ReportingObserver { +class ReportingPersisterImpl : public ReportingPersister { public: - ReportingPersisterImpl(ReportingContext* context) - : context_(context), timer_(base::MakeUnique<base::OneShotTimer>()) {} + ReportingPersisterImpl(ReportingContext* context) : context_(context) {} // ReportingPersister implementation: - ~ReportingPersisterImpl() override { - DCHECK(context_->initialized()); - context_->RemoveObserver(this); - } - - void Initialize() override { - std::unique_ptr<const base::Value> persisted_data = - context_->delegate()->GetPersistedData(); - if (persisted_data) - Deserialize(*persisted_data); - context_->AddObserver(this); - } - - void SetTimerForTesting(std::unique_ptr<base::Timer> timer) override { - DCHECK(!context_->initialized()); - timer_ = std::move(timer); - } - - // ReportingObserver implementation: - - void OnCacheUpdated() override { - DCHECK(context_->initialized()); - if (!timer_->IsRunning()) - StartTimer(); - } + ~ReportingPersisterImpl() override {} private: - void StartTimer() { - timer_->Start( - FROM_HERE, context_->policy().persistence_interval, - base::Bind(&ReportingPersisterImpl::Persist, base::Unretained(this))); - } - - void Persist() { delegate()->PersistData(Serialize()); } - std::string SerializeTicks(base::TimeTicks time_ticks) { base::Time time = time_ticks - tick_clock()->NowTicks() + clock()->Now(); return base::Int64ToString(time.ToInternalValue()); @@ -336,13 +301,11 @@ } const ReportingPolicy& policy() { return context_->policy(); } - ReportingDelegate* delegate() { return context_->delegate(); } base::Clock* clock() { return context_->clock(); } base::TickClock* tick_clock() { return context_->tick_clock(); } ReportingCache* cache() { return context_->cache(); } ReportingContext* context_; - std::unique_ptr<base::Timer> timer_; }; } // namespace
diff --git a/net/reporting/reporting_persister.h b/net/reporting/reporting_persister.h index 27463a5..c6b52f87 100644 --- a/net/reporting/reporting_persister.h +++ b/net/reporting/reporting_persister.h
@@ -9,30 +9,18 @@ #include "net/base/net_export.h" -namespace base { -class Timer; -} // namespace base - namespace net { class ReportingContext; -// Periodically persists the state of the Reporting system to (reasonably) -// stable storage using the methods provided by the ReportingDelegate. +// Will persist the state of the Reporting system to (reasonably) stable +// storage using an as-yet-unwritten persistence mechanism within //net. class NET_EXPORT ReportingPersister { public: // Creates a ReportingPersister. |context| must outlive the persister. static std::unique_ptr<ReportingPersister> Create(ReportingContext* context); virtual ~ReportingPersister(); - - // Initializes the Persister, which deserializes any previously-persisted data - // that is available through the Context's Delegate. - virtual void Initialize() = 0; - - // Replaces the internal Timer used for scheduling writes to stable storage - // with a caller-specified one so that unittests can provide a MockTimer. - virtual void SetTimerForTesting(std::unique_ptr<base::Timer> timer) = 0; }; } // namespace net
diff --git a/net/reporting/reporting_persister_unittest.cc b/net/reporting/reporting_persister_unittest.cc index ed109ed..c0bda9f 100644 --- a/net/reporting/reporting_persister_unittest.cc +++ b/net/reporting/reporting_persister_unittest.cc
@@ -30,7 +30,8 @@ const std::string kType_ = "default"; }; -TEST_F(ReportingPersisterTest, Test) { +// Disabled because the Persister has no persistence layer to use yet. +TEST_F(ReportingPersisterTest, DISABLED_Test) { ReportingPolicy policy; policy.persist_reports_across_restarts = true; policy.persist_clients_across_restarts = true; @@ -49,8 +50,7 @@ kGroup_, tick_clock()->NowTicks() + base::TimeDelta::FromDays(1)); - EXPECT_TRUE(persistence_timer()->IsRunning()); - persistence_timer()->Fire(); + // TODO: Actually trigger persistence, once it's possible. SimulateRestart(/* delta= */ base::TimeDelta::FromHours(1), /* delta_ticks= */ base::TimeDelta::FromHours(-3));
diff --git a/net/reporting/reporting_service.cc b/net/reporting/reporting_service.cc index 6d2b215..4dcee9da 100644 --- a/net/reporting/reporting_service.cc +++ b/net/reporting/reporting_service.cc
@@ -14,7 +14,6 @@ #include "base/values.h" #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_context.h" -#include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_header_parser.h" #include "url/gurl.h" @@ -25,11 +24,7 @@ class ReportingServiceImpl : public ReportingService { public: ReportingServiceImpl(std::unique_ptr<ReportingContext> context) - : context_(std::move(context)) { - // TODO(juliatuttle): This can be slow, so it might be better to expose it - // as a separate method and call it separately from constructing everything. - context_->Initialize(); - } + : context_(std::move(context)) {} ~ReportingServiceImpl() override {} @@ -37,14 +32,12 @@ const std::string& group, const std::string& type, std::unique_ptr<const base::Value> body) override { - DCHECK(context_->initialized()); context_->cache()->AddReport(url, group, type, std::move(body), context_->tick_clock()->NowTicks(), 0); } void ProcessHeader(const GURL& url, const std::string& header_value) override { - DCHECK(context_->initialized()); ReportingHeaderParser::ParseHeader(context_.get(), url, header_value); } @@ -61,10 +54,9 @@ // static std::unique_ptr<ReportingService> ReportingService::Create( const ReportingPolicy& policy, - URLRequestContext* request_context, - std::unique_ptr<ReportingDelegate> delegate) { + URLRequestContext* request_context) { return base::MakeUnique<ReportingServiceImpl>( - ReportingContext::Create(policy, std::move(delegate), request_context)); + ReportingContext::Create(policy, request_context)); } // static
diff --git a/net/reporting/reporting_service.h b/net/reporting/reporting_service.h index c305410..831e0711 100644 --- a/net/reporting/reporting_service.h +++ b/net/reporting/reporting_service.h
@@ -21,7 +21,6 @@ namespace net { class ReportingContext; -class ReportingDelegate; struct ReportingPolicy; class URLRequestContext; @@ -32,12 +31,10 @@ virtual ~ReportingService(); // Creates a ReportingService. |policy| will be copied. |request_context| must - // outlive the ReportingService. The ReportingService will take ownership of - // |delegate| and destroy it when the service is destroyed. + // outlive the ReportingService. static std::unique_ptr<ReportingService> Create( const ReportingPolicy& policy, - URLRequestContext* request_context, - std::unique_ptr<ReportingDelegate> delegate); + URLRequestContext* request_context); // Creates a ReportingService for testing purposes using an // already-constructed ReportingContext. The ReportingService will take
diff --git a/net/reporting/reporting_service_unittest.cc b/net/reporting/reporting_service_unittest.cc index 20c8656..064700e 100644 --- a/net/reporting/reporting_service_unittest.cc +++ b/net/reporting/reporting_service_unittest.cc
@@ -12,7 +12,6 @@ #include "base/values.h" #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_context.h" -#include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_policy.h" #include "net/reporting/reporting_report.h" #include "net/reporting/reporting_service.h"
diff --git a/net/reporting/reporting_test_util.cc b/net/reporting/reporting_test_util.cc index 74d0cb4..2a7d1e0c 100644 --- a/net/reporting/reporting_test_util.cc +++ b/net/reporting/reporting_test_util.cc
@@ -17,7 +17,6 @@ #include "net/reporting/reporting_cache.h" #include "net/reporting/reporting_client.h" #include "net/reporting/reporting_context.h" -#include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_delivery_agent.h" #include "net/reporting/reporting_garbage_collector.h" #include "net/reporting/reporting_persister.h" @@ -91,20 +90,6 @@ return nullptr; } -TestReportingDelegate::TestReportingDelegate() {} -TestReportingDelegate::~TestReportingDelegate() {} - -void TestReportingDelegate::PersistData( - std::unique_ptr<const base::Value> persisted_data) { - persisted_data_ = std::move(persisted_data); -} - -std::unique_ptr<const base::Value> TestReportingDelegate::GetPersistedData() { - if (!persisted_data_) - return std::unique_ptr<const base::Value>(); - return persisted_data_->CreateDeepCopy(); -} - TestReportingUploader::PendingUpload::~PendingUpload() {} TestReportingUploader::PendingUpload::PendingUpload() {} @@ -120,18 +105,14 @@ TestReportingContext::TestReportingContext(const ReportingPolicy& policy) : ReportingContext(policy, - base::MakeUnique<TestReportingDelegate>(), base::MakeUnique<base::SimpleTestClock>(), base::MakeUnique<base::SimpleTestTickClock>(), base::MakeUnique<TestReportingUploader>()), delivery_timer_(new base::MockTimer(/* retain_user_task= */ false, /* is_repeating= */ false)), - persistence_timer_(new base::MockTimer(/* retain_user_task= */ false, - /* is_repeating= */ false)), garbage_collection_timer_( new base::MockTimer(/* retain_user_task= */ false, /* is_repeating= */ false)) { - persister()->SetTimerForTesting(base::WrapUnique(persistence_timer_)); garbage_collector()->SetTimerForTesting( base::WrapUnique(garbage_collection_timer_)); delivery_agent()->SetTimerForTesting(base::WrapUnique(delivery_timer_)); @@ -139,7 +120,6 @@ TestReportingContext::~TestReportingContext() { delivery_timer_ = nullptr; - persistence_timer_ = nullptr; garbage_collection_timer_ = nullptr; } @@ -148,34 +128,27 @@ ReportingPolicy policy; policy.endpoint_backoff_policy.jitter_factor = 0.0; - CreateAndInitializeContext(policy, std::unique_ptr<const base::Value>(), - base::Time::Now(), base::TimeTicks::Now()); + CreateContext(policy, base::Time::Now(), base::TimeTicks::Now()); } ReportingTestBase::~ReportingTestBase() {} void ReportingTestBase::UsePolicy(const ReportingPolicy& new_policy) { - CreateAndInitializeContext(new_policy, delegate()->GetPersistedData(), - clock()->Now(), tick_clock()->NowTicks()); + CreateContext(new_policy, clock()->Now(), tick_clock()->NowTicks()); } void ReportingTestBase::SimulateRestart(base::TimeDelta delta, base::TimeDelta delta_ticks) { - CreateAndInitializeContext(policy(), delegate()->GetPersistedData(), - clock()->Now() + delta, - tick_clock()->NowTicks() + delta_ticks); + CreateContext(policy(), clock()->Now() + delta, + tick_clock()->NowTicks() + delta_ticks); } -void ReportingTestBase::CreateAndInitializeContext( - const ReportingPolicy& policy, - std::unique_ptr<const base::Value> persisted_data, - base::Time now, - base::TimeTicks now_ticks) { +void ReportingTestBase::CreateContext(const ReportingPolicy& policy, + base::Time now, + base::TimeTicks now_ticks) { context_ = base::MakeUnique<TestReportingContext>(policy); - delegate()->PersistData(std::move(persisted_data)); clock()->SetNow(now); tick_clock()->SetNowTicks(now_ticks); - context_->Initialize(); } base::TimeTicks ReportingTestBase::yesterday() {
diff --git a/net/reporting/reporting_test_util.h b/net/reporting/reporting_test_util.h index 2fa0d46c..48b63d9 100644 --- a/net/reporting/reporting_test_util.h +++ b/net/reporting/reporting_test_util.h
@@ -11,7 +11,6 @@ #include "base/macros.h" #include "net/reporting/reporting_context.h" -#include "net/reporting/reporting_delegate.h" #include "net/reporting/reporting_uploader.h" #include "testing/gtest/include/gtest/gtest.h" @@ -40,24 +39,6 @@ const url::Origin& origin, const GURL& endpoint); -// A simple implementation of ReportingDelegate that only persists data in RAM. -class TestReportingDelegate : public ReportingDelegate { - public: - TestReportingDelegate(); - - ~TestReportingDelegate() override; - - // ReportingDelegate implementation: - std::unique_ptr<const base::Value> GetPersistedData() override; - - void PersistData(std::unique_ptr<const base::Value> persisted_data) override; - - private: - std::unique_ptr<const base::Value> persisted_data_; - - DISALLOW_COPY_AND_ASSIGN(TestReportingDelegate); -}; - // A test implementation of ReportingUploader that holds uploads for tests to // examine and complete with a specified outcome. class TestReportingUploader : public ReportingUploader { @@ -95,15 +76,12 @@ }; // A test implementation of ReportingContext that uses test versions of -// ReportingDelegate, Clock, TickClock, and ReportingUploader. +// Clock, TickClock, Timer, and ReportingUploader. class TestReportingContext : public ReportingContext { public: TestReportingContext(const ReportingPolicy& policy); ~TestReportingContext(); - TestReportingDelegate* test_delegate() { - return reinterpret_cast<TestReportingDelegate*>(delegate()); - } base::SimpleTestClock* test_clock() { return reinterpret_cast<base::SimpleTestClock*>(clock()); } @@ -111,7 +89,6 @@ return reinterpret_cast<base::SimpleTestTickClock*>(tick_clock()); } base::MockTimer* test_delivery_timer() { return delivery_timer_; } - base::MockTimer* test_persistence_timer() { return persistence_timer_; } base::MockTimer* test_garbage_collection_timer() { return garbage_collection_timer_; } @@ -124,7 +101,6 @@ // here to preserve type: base::MockTimer* delivery_timer_; - base::MockTimer* persistence_timer_; base::MockTimer* garbage_collection_timer_; DISALLOW_COPY_AND_ASSIGN(TestReportingContext); @@ -139,8 +115,7 @@ void UsePolicy(const ReportingPolicy& policy); - // Simulates an embedder restart, preserving the ReportingPolicy and any data - // persisted via the TestReportingDelegate, but nothing else. + // Simulates an embedder restart, preserving the ReportingPolicy. // // Advances the Clock by |delta|, and the TickClock by |delta_ticks|. Both can // be zero or negative. @@ -150,15 +125,11 @@ const ReportingPolicy& policy() { return context_->policy(); } - TestReportingDelegate* delegate() { return context_->test_delegate(); } base::SimpleTestClock* clock() { return context_->test_clock(); } base::SimpleTestTickClock* tick_clock() { return context_->test_tick_clock(); } base::MockTimer* delivery_timer() { return context_->test_delivery_timer(); } - base::MockTimer* persistence_timer() { - return context_->test_persistence_timer(); - } base::MockTimer* garbage_collection_timer() { return context_->test_garbage_collection_timer(); } @@ -187,11 +158,9 @@ } private: - void CreateAndInitializeContext( - const ReportingPolicy& policy, - std::unique_ptr<const base::Value> persisted_data, - base::Time now, - base::TimeTicks now_ticks); + void CreateContext(const ReportingPolicy& policy, + base::Time now, + base::TimeTicks now_ticks); std::unique_ptr<TestReportingContext> context_;
diff --git a/net/url_request/url_request_test_job.cc b/net/url_request/url_request_test_job.cc index ab359b4..a3512f9 100644 --- a/net/url_request/url_request_test_job.cc +++ b/net/url_request/url_request_test_job.cc
@@ -296,12 +296,6 @@ load_timing_info->request_start_time = request_start_time; } -int URLRequestTestJob::GetResponseCode() const { - if (response_headers_.get()) - return response_headers_->response_code(); - return -1; -} - int64_t URLRequestTestJob::GetTotalReceivedBytes() const { return response_headers_length_ + offset_; }
diff --git a/net/url_request/url_request_test_job.h b/net/url_request/url_request_test_job.h index 7082678..cd899bc 100644 --- a/net/url_request/url_request_test_job.h +++ b/net/url_request/url_request_test_job.h
@@ -138,7 +138,6 @@ bool GetMimeType(std::string* mime_type) const override; void GetResponseInfo(HttpResponseInfo* info) override; void GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override; - int GetResponseCode() const override; int64_t GetTotalReceivedBytes() const override; bool IsRedirectResponse(GURL* location, int* http_status_code) override;
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn index f196463b..b46d035 100644 --- a/remoting/host/BUILD.gn +++ b/remoting/host/BUILD.gn
@@ -96,6 +96,8 @@ "continue_window_linux.cc", "continue_window_mac.mm", "continue_window_win.cc", + "current_process_stats_agent.cc", + "current_process_stats_agent.h", "curtain_mode.h", "curtain_mode_linux.cc", "curtain_mode_mac.cc", @@ -131,6 +133,8 @@ "disconnect_window_win.cc", "dns_blackhole_checker.cc", "dns_blackhole_checker.h", + "forward_process_stats_agent.cc", + "forward_process_stats_agent.h", "gcd_rest_client.cc", "gcd_rest_client.h", "gcd_state_updater.cc", @@ -223,6 +227,11 @@ "policy_watcher.h", "posix/signal_handler.cc", "posix/signal_handler.h", + "process_stats_agent.h", + "process_stats_sender.cc", + "process_stats_sender.h", + "process_stats_util.cc", + "process_stats_util.h", "register_support_host_request.cc", "register_support_host_request.h", "remote_input_filter.cc", @@ -460,6 +469,7 @@ "pairing_registry_delegate_win_unittest.cc", "pin_hash_unittest.cc", "policy_watcher_unittest.cc", + "process_stats_sender_unittest.cc", "register_support_host_request_unittest.cc", "remote_input_filter_unittest.cc", "resizing_host_observer_unittest.cc",
diff --git a/remoting/host/current_process_stats_agent.cc b/remoting/host/current_process_stats_agent.cc new file mode 100644 index 0000000..35ff5ac --- /dev/null +++ b/remoting/host/current_process_stats_agent.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 "remoting/host/current_process_stats_agent.h" + +#include "base/process/process_metrics.h" + +namespace remoting { + +CurrentProcessStatsAgent::CurrentProcessStatsAgent( + const std::string& process_name) + : process_name_(process_name), + metrics_(base::ProcessMetrics::CreateCurrentProcessMetrics()) {} + +CurrentProcessStatsAgent::~CurrentProcessStatsAgent() = default; + +protocol::ProcessResourceUsage CurrentProcessStatsAgent::GetResourceUsage() { + protocol::ProcessResourceUsage current; + current.set_process_name(process_name_); + current.set_processor_usage(metrics_->GetPlatformIndependentCPUUsage()); + current.set_working_set_size(metrics_->GetWorkingSetSize()); + current.set_pagefile_size(metrics_->GetPagefileUsage()); + return current; +} + +} // namespace remoting
diff --git a/remoting/host/current_process_stats_agent.h b/remoting/host/current_process_stats_agent.h new file mode 100644 index 0000000..82e1163 --- /dev/null +++ b/remoting/host/current_process_stats_agent.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 REMOTING_HOST_CURRENT_PROCESS_STATS_AGENT_H_ +#define REMOTING_HOST_CURRENT_PROCESS_STATS_AGENT_H_ + +#include <memory> +#include <string> + +#include "remoting/host/process_stats_agent.h" +#include "remoting/proto/process_stats.pb.h" + +namespace base { +class ProcessMetrics; +} // namespace base + +namespace remoting { + +// A component to report statistic data of the current process. +class CurrentProcessStatsAgent final : public ProcessStatsAgent { + public: + explicit CurrentProcessStatsAgent(const std::string& process_name); + ~CurrentProcessStatsAgent() override; + + // ProcessStatsAgent implementation. + protocol::ProcessResourceUsage GetResourceUsage() override; + + private: + const std::string process_name_; + const std::unique_ptr<base::ProcessMetrics> metrics_; +}; + +} // namespace remoting + +#endif // REMOTING_HOST_CURRENT_PROCESS_STATS_AGENT_H_
diff --git a/remoting/host/forward_process_stats_agent.cc b/remoting/host/forward_process_stats_agent.cc new file mode 100644 index 0000000..c75bc517 --- /dev/null +++ b/remoting/host/forward_process_stats_agent.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 "remoting/host/forward_process_stats_agent.h" + +#include "base/logging.h" + +namespace remoting { + +ForwardProcessStatsAgent::ForwardProcessStatsAgent() = default; +ForwardProcessStatsAgent::~ForwardProcessStatsAgent() = default; + +protocol::ProcessResourceUsage ForwardProcessStatsAgent::GetResourceUsage() { + DCHECK(thread_checker_.CalledOnValidThread()); + return usage_; +} + +void ForwardProcessStatsAgent::OnProcessStats( + const protocol::ProcessResourceUsage& usage) { + DCHECK(thread_checker_.CalledOnValidThread()); + usage_ = usage; +} + +} // namespace remoting
diff --git a/remoting/host/forward_process_stats_agent.h b/remoting/host/forward_process_stats_agent.h new file mode 100644 index 0000000..321f5ad --- /dev/null +++ b/remoting/host/forward_process_stats_agent.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 REMOTING_HOST_FORWARD_PROCESS_STATS_AGENT_H_ +#define REMOTING_HOST_FORWARD_PROCESS_STATS_AGENT_H_ + +#include "base/threading/thread_checker.h" +#include "remoting/host/process_stats_agent.h" +#include "remoting/proto/process_stats.pb.h" + +namespace remoting { + +// ProcessStatsAgent implementation that returns stats passed to +// OnProcessStats(). Used to collect stats from processes other than the current +// one. All public functions, not including constructor and destructor, of the +// object of ForwardProcessStatsAgent are expected to be called in a same +// thread. +class ForwardProcessStatsAgent final : public ProcessStatsAgent { + public: + ForwardProcessStatsAgent(); + ~ForwardProcessStatsAgent() override; + + void OnProcessStats(const protocol::ProcessResourceUsage& usage); + + // ProcessStatsAgent implementation. + protocol::ProcessResourceUsage GetResourceUsage() override; + + private: + base::ThreadChecker thread_checker_; + protocol::ProcessResourceUsage usage_; +}; + +} // namespace remoting + +#endif // REMOTING_HOST_FORWARD_PROCESS_STATS_AGENT_H_
diff --git a/remoting/host/process_stats_agent.h b/remoting/host/process_stats_agent.h new file mode 100644 index 0000000..dc242d3 --- /dev/null +++ b/remoting/host/process_stats_agent.h
@@ -0,0 +1,26 @@ +// 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 REMOTING_HOST_PROCESS_STATS_AGENT_H_ +#define REMOTING_HOST_PROCESS_STATS_AGENT_H_ + +#include "remoting/proto/process_stats.pb.h" + +namespace remoting { + +// An interface to report the process statistic data. +class ProcessStatsAgent { + public: + ProcessStatsAgent() = default; + virtual ~ProcessStatsAgent() = default; + + // This function is expected to be executed in an IO-disallowed thread: if the + // implementation requires IO access or may cost a significant amount of time, + // using a background thread is preferred. + virtual protocol::ProcessResourceUsage GetResourceUsage() = 0; +}; + +} // namespace remoting + +#endif // REMOTING_HOST_PROCESS_STATS_AGENT_H_
diff --git a/remoting/host/process_stats_sender.cc b/remoting/host/process_stats_sender.cc new file mode 100644 index 0000000..a734877 --- /dev/null +++ b/remoting/host/process_stats_sender.cc
@@ -0,0 +1,51 @@ +// 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 "remoting/host/process_stats_sender.h" + +#include <utility> + +#include "base/location.h" +#include "base/logging.h" +#include "remoting/host/process_stats_agent.h" +#include "remoting/host/process_stats_util.h" + +namespace remoting { + +ProcessStatsSender::ProcessStatsSender( + protocol::ProcessStatsStub* host_stats_stub, + base::TimeDelta interval, + std::initializer_list<ProcessStatsAgent*> agents) + : host_stats_stub_(host_stats_stub), + agents_(agents), + thread_checker_() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(host_stats_stub_); + DCHECK(!interval.is_zero()); + DCHECK(!agents_.empty()); + + timer_.Start(FROM_HERE, interval, this, &ProcessStatsSender::ReportUsage); +} + +ProcessStatsSender::~ProcessStatsSender() { + DCHECK(thread_checker_.CalledOnValidThread()); + timer_.Stop(); +} + +void ProcessStatsSender::ReportUsage() { + DCHECK(thread_checker_.CalledOnValidThread()); + + std::vector<protocol::ProcessResourceUsage> usages; + for (auto* const agent : agents_) { + DCHECK(agent); + protocol::ProcessResourceUsage usage = agent->GetResourceUsage(); + if (!IsEmptyProcessResourceUsage(usage)) { + usages.push_back(std::move(usage)); + } + } + + host_stats_stub_->OnProcessStats(AggregateProcessResourceUsage(usages)); +} + +} // namespace remoting
diff --git a/remoting/host/process_stats_sender.h b/remoting/host/process_stats_sender.h new file mode 100644 index 0000000..c33af89 --- /dev/null +++ b/remoting/host/process_stats_sender.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 REMOTING_HOST_PROCESS_STATS_SENDER_H_ +#define REMOTING_HOST_PROCESS_STATS_SENDER_H_ + +#include <initializer_list> +#include <vector> + +#include "base/threading/thread_checker.h" +#include "base/time/time.h" +#include "base/timer/timer.h" +#include "remoting/proto/process_stats.pb.h" +#include "remoting/protocol/process_stats_stub.h" + +namespace remoting { + +class ProcessStatsAgent; + +// A component to report process statistic data regularly, it starts immediately +// after construction, and stops after destruction. +// All public functions, including constructor and destructor of the object of +// ProcessStatsSender need to be executed in a same thread. +class ProcessStatsSender final { + public: + // ProcessStatsSender reports statistic data to |host_stats_stub| once per + // |interval|. + // ProcessStatsSender does not take the ownership of both |host_stats_stub| + // and |agents|. They must outlive the ProcessStatsSender object. + ProcessStatsSender(protocol::ProcessStatsStub* host_stats_stub, + base::TimeDelta interval, + std::initializer_list<ProcessStatsAgent*> agents); + + ~ProcessStatsSender(); + private: + void ReportUsage(); + + protocol::ProcessStatsStub* const host_stats_stub_; + std::vector<ProcessStatsAgent*> agents_; + base::RepeatingTimer timer_; + const base::ThreadChecker thread_checker_; +}; + +} // namespace remoting + +#endif // REMOTING_HOST_PROCESS_STATS_SENDER_H_
diff --git a/remoting/host/process_stats_sender_unittest.cc b/remoting/host/process_stats_sender_unittest.cc new file mode 100644 index 0000000..6d08818c --- /dev/null +++ b/remoting/host/process_stats_sender_unittest.cc
@@ -0,0 +1,180 @@ +// 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 "remoting/host/process_stats_sender.h" + +#include <stdint.h> + +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/location.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/time/time.h" +#include "remoting/host/process_stats_agent.h" +#include "remoting/proto/process_stats.pb.h" +#include "remoting/protocol/process_stats_stub.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace remoting { + +namespace { + +class FakeProcessStatsStub : public protocol::ProcessStatsStub { + public: + FakeProcessStatsStub() = default; + ~FakeProcessStatsStub() override = default; + + void OnProcessStats( + const protocol::AggregatedProcessResourceUsage& usage) override { + received_.push_back(usage); + DCHECK_LE(received_.size(), expected_usage_count_); + DCHECK(!quit_closure_.is_null()); + if (received_.size() == expected_usage_count_) { + quit_closure_.Run(); + } + } + + const std::vector<protocol::AggregatedProcessResourceUsage>& received() + const { + return received_; + } + + void set_quit_closure(base::Closure quit_closure) { + quit_closure_ = quit_closure; + } + + void set_expected_usage_count(size_t expected_usage_count) { + expected_usage_count_ = expected_usage_count; + } + + private: + std::vector<protocol::AggregatedProcessResourceUsage> received_; + size_t expected_usage_count_ = 0; + base::Closure quit_closure_; +}; + +class FakeProcessStatsAgent : public ProcessStatsAgent { + public: + FakeProcessStatsAgent() = default; + ~FakeProcessStatsAgent() override = default; + + protocol::ProcessResourceUsage GetResourceUsage() override { + protocol::ProcessResourceUsage usage; + usage.set_process_name("FakeProcessStatsAgent"); + usage.set_processor_usage(index_); + usage.set_working_set_size(index_); + usage.set_pagefile_size(index_); + index_++; + return usage; + } + + // Checks the expected usage based on index. + static void AssertExpected( + const protocol::AggregatedProcessResourceUsage& usage, + size_t index) { + ASSERT_EQ(usage.processor_usage(), index); + ASSERT_EQ(usage.working_set_size(), index); + ASSERT_EQ(usage.pagefile_size(), index); + } + + static void AssertExpected(const protocol::ProcessResourceUsage& usage, + size_t index) { + ASSERT_EQ(usage.processor_usage(), index); + ASSERT_EQ(usage.working_set_size(), index); + ASSERT_EQ(usage.pagefile_size(), index); + } + + size_t issued_times() const { return index_; } + + private: + size_t index_ = 0; +}; + +} // namespace + +TEST(ProcessStatsSenderTest, ReportUsage) { + base::MessageLoop message_loop; + base::RunLoop run_loop; + FakeProcessStatsStub stub; + std::unique_ptr<ProcessStatsSender> stats; + FakeProcessStatsAgent agent; + + stub.set_expected_usage_count(10); + stub.set_quit_closure(base::Bind( + [](std::unique_ptr<ProcessStatsSender>* stats, + const FakeProcessStatsStub& stub, const FakeProcessStatsAgent& agent, + base::RunLoop* run_loop) -> void { + ASSERT_EQ(stub.received().size(), agent.issued_times()); + stats->reset(); + run_loop->Quit(); + }, + base::Unretained(&stats), base::ConstRef(stub), base::ConstRef(agent), + base::Unretained(&run_loop))); + message_loop.task_runner()->PostTask( + FROM_HERE, + base::Bind( + [](std::unique_ptr<ProcessStatsSender>* stats, + FakeProcessStatsStub* stub, FakeProcessStatsAgent* agent) -> void { + stats->reset(new ProcessStatsSender( + stub, base::TimeDelta::FromMilliseconds(1), { agent })); + }, + base::Unretained(&stats), base::Unretained(&stub), + base::Unretained(&agent))); + run_loop.Run(); + + ASSERT_EQ(stub.received().size(), 10U); + for (size_t i = 0; i < stub.received().size(); i++) { + FakeProcessStatsAgent::AssertExpected(stub.received()[i], i); + } +} + +TEST(ProcessStatsSenderTest, MergeUsage) { + base::MessageLoop message_loop; + base::RunLoop run_loop; + FakeProcessStatsStub stub; + std::unique_ptr<ProcessStatsSender> stats; + // Owned by |stats|. + FakeProcessStatsAgent agent1; + FakeProcessStatsAgent agent2; + + stub.set_expected_usage_count(10); + stub.set_quit_closure(base::Bind( + [](std::unique_ptr<ProcessStatsSender>* stats, + const FakeProcessStatsStub& stub, const FakeProcessStatsAgent& agent1, + const FakeProcessStatsAgent& agent2, base::RunLoop* run_loop) -> void { + ASSERT_EQ(stub.received().size(), agent1.issued_times()); + ASSERT_EQ(stub.received().size(), agent2.issued_times()); + stats->reset(); + run_loop->Quit(); + }, + base::Unretained(&stats), base::ConstRef(stub), base::ConstRef(agent1), + base::ConstRef(agent2), base::Unretained(&run_loop))); + message_loop.task_runner()->PostTask( + FROM_HERE, + base::Bind( + [](std::unique_ptr<ProcessStatsSender>* stats, + FakeProcessStatsStub* stub, FakeProcessStatsAgent* agent1, + FakeProcessStatsAgent* agent2) -> void { + stats->reset(new ProcessStatsSender( + stub, base::TimeDelta::FromMilliseconds(1), + { agent1, agent2 } )); + }, + base::Unretained(&stats), base::Unretained(&stub), + base::Unretained(&agent1), base::Unretained(&agent2))); + run_loop.Run(); + + ASSERT_EQ(stub.received().size(), 10U); + for (size_t i = 0; i < stub.received().size(); i++) { + FakeProcessStatsAgent::AssertExpected(stub.received()[i], i * 2); + for (int j = 0; j < stub.received()[i].usages_size(); j++) { + FakeProcessStatsAgent::AssertExpected( + stub.received()[i].usages().Get(j), i); + } + } +} + +} // namespace remoting
diff --git a/remoting/host/process_stats_util.cc b/remoting/host/process_stats_util.cc new file mode 100644 index 0000000..b87402f --- /dev/null +++ b/remoting/host/process_stats_util.cc
@@ -0,0 +1,56 @@ +// 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 "remoting/host/process_stats_util.h" + +#include <stdint.h> + +#include <string> +#include <utility> + +namespace remoting { + +bool IsEmptyProcessResourceUsage(const protocol::ProcessResourceUsage& usage) { + return !usage.has_process_name() && !usage.has_processor_usage() && + !usage.has_working_set_size() && !usage.has_pagefile_size(); +} + +protocol::AggregatedProcessResourceUsage AggregateProcessResourceUsage( + const std::vector<protocol::ProcessResourceUsage>& usages) { + if (usages.empty()) { + return protocol::AggregatedProcessResourceUsage(); + } + + if (usages.size() == 1) { + const protocol::ProcessResourceUsage& usage = usages[0]; + protocol::AggregatedProcessResourceUsage aggregated; + aggregated.set_name(usage.process_name()); + aggregated.set_processor_usage(usage.processor_usage()); + aggregated.set_working_set_size(usage.working_set_size()); + aggregated.set_pagefile_size(usage.pagefile_size()); + return aggregated; + } + + std::string name = "aggregate { "; + double processor_usage = 0; + uint64_t working_set_size = 0; + uint64_t pagefile_size = 0; + protocol::AggregatedProcessResourceUsage aggregated; + for (const auto& usage : usages) { + name.append(usage.process_name()).append(", "); + processor_usage += usage.processor_usage(); + working_set_size += usage.working_set_size(); + pagefile_size += usage.pagefile_size(); + *aggregated.add_usages() = usage; + } + name += " }"; + aggregated.set_name(std::move(name)); + aggregated.set_processor_usage(processor_usage); + aggregated.set_working_set_size(working_set_size); + aggregated.set_pagefile_size(pagefile_size); + + return aggregated; +} + +} // namespace remoting
diff --git a/remoting/host/process_stats_util.h b/remoting/host/process_stats_util.h new file mode 100644 index 0000000..6ad9739 --- /dev/null +++ b/remoting/host/process_stats_util.h
@@ -0,0 +1,24 @@ +// 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 REMOTING_HOST_PROCESS_STATS_UTIL_H_ +#define REMOTING_HOST_PROCESS_STATS_UTIL_H_ + +#include <vector> + +#include "remoting/proto/process_stats.pb.h" + +namespace remoting { + +// Whether the |usage| is empty, i.e. all fields hold initial values. +bool IsEmptyProcessResourceUsage(const protocol::ProcessResourceUsage& usage); + +// Merges several ProcessResourceUsage instances into one +// AggregatedProcessResourceUsage. +protocol::AggregatedProcessResourceUsage AggregateProcessResourceUsage( + const std::vector<protocol::ProcessResourceUsage>& usages); + +} // namespace remoting + +#endif // REMOTING_HOST_PROCESS_STATS_UTIL_H_
diff --git a/remoting/proto/BUILD.gn b/remoting/proto/BUILD.gn index 853267e..64e0f23 100644 --- a/remoting/proto/BUILD.gn +++ b/remoting/proto/BUILD.gn
@@ -18,6 +18,7 @@ "event.proto", "internal.proto", "mux.proto", + "process_stats.proto", "video.proto", "video_stats.proto", ]
diff --git a/remoting/proto/process_stats.proto b/remoting/proto/process_stats.proto new file mode 100644 index 0000000..77d9c8f --- /dev/null +++ b/remoting/proto/process_stats.proto
@@ -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. + +// Protocol for process resource usage. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package remoting.protocol; + +// The resource usage of a single process. +// Next Id: 5 +message ProcessResourceUsage { + // The name or friendly name of the process. + optional string process_name = 1; + + // The processor usage. It should be a consistent value on all platforms in + // range of 0 to (100 * NumCPUCores). + optional double processor_usage = 2; + + // Memory usage of working set. + optional uint64 working_set_size = 3; + + // Memory usage of page file. + optional uint64 pagefile_size = 4; +} + +// The resource usage of several processes. +// Next Id: 6 +message AggregatedProcessResourceUsage { + // A friendly name of the processes current instance aggregated from. + optional string name = 1; + + // The total processor usage. + optional double processor_usage = 2; + + // The total memory usage of working set. + optional uint64 working_set_size = 3; + + // The total memory usage of page file. + optional uint64 pagefile_size = 4; + + // The process resource usage of each individual process. + repeated ProcessResourceUsage usages = 5; +}
diff --git a/remoting/protocol/BUILD.gn b/remoting/protocol/BUILD.gn index 92a4256..f9d4099 100644 --- a/remoting/protocol/BUILD.gn +++ b/remoting/protocol/BUILD.gn
@@ -128,6 +128,7 @@ "port_allocator_factory.h", "port_range.cc", "port_range.h", + "process_stats_stub.h", "pseudotcp_adapter.cc", "pseudotcp_adapter.h", "pseudotcp_channel_factory.cc",
diff --git a/remoting/protocol/process_stats_stub.h b/remoting/protocol/process_stats_stub.h new file mode 100644 index 0000000..b59d7c6 --- /dev/null +++ b/remoting/protocol/process_stats_stub.h
@@ -0,0 +1,26 @@ +// 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 REMOTING_PROTOCOL_PROCESS_STATS_STUB_H_ +#define REMOTING_PROTOCOL_PROCESS_STATS_STUB_H_ + +#include "remoting/proto/process_stats.pb.h" + +namespace remoting { +namespace protocol { + +// An interface to receive process statistic data. +class ProcessStatsStub { + public: + ProcessStatsStub() = default; + virtual ~ProcessStatsStub() = default; + + virtual void OnProcessStats( + const protocol::AggregatedProcessResourceUsage& usage) = 0; +}; + +} // namespace protocol +} // namespace remoting + +#endif // REMOTING_PROTOCOL_PROCESS_STATS_STUB_H_
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc index fbacd2c..7fc239f 100644 --- a/remoting/protocol/webrtc_transport.cc +++ b/remoting/protocol/webrtc_transport.cc
@@ -208,6 +208,9 @@ // See crbug.com/660081. base::ThreadRestrictions::ScopedAllowIO allow_io; peer_connection_->Close(); + peer_connection_ = nullptr; + peer_connection_factory_ = nullptr; + audio_module_ = nullptr; } WebrtcAudioModule* audio_module() {
diff --git a/services/ui/public/interfaces/cursor/cursor.mojom b/services/ui/public/interfaces/cursor/cursor.mojom index 30becc8b..c228539a 100644 --- a/services/ui/public/interfaces/cursor/cursor.mojom +++ b/services/ui/public/interfaces/cursor/cursor.mojom
@@ -5,7 +5,7 @@ module ui.mojom; import "mojo/common/time.mojom"; -import "skia/public/interfaces/bitmap_array.mojom"; +import "skia/public/interfaces/bitmap.mojom"; import "ui/gfx/geometry/mojo/geometry.mojom"; // Standard Cursor numbers. These are the same as Chrome's ui::Cursor and @@ -72,7 +72,7 @@ gfx.mojom.Point hotspot_in_pixels; // The frames of the cursor. - skia.mojom.BitmapArray cursor_frames; + array<skia.mojom.Bitmap?> cursor_frames; // This is the image scale of this cursor. float scale_factor;
diff --git a/services/ui/public/interfaces/cursor/cursor_struct_traits_unittest.cc b/services/ui/public/interfaces/cursor/cursor_struct_traits_unittest.cc index db2c6c4..011b412 100644 --- a/services/ui/public/interfaces/cursor/cursor_struct_traits_unittest.cc +++ b/services/ui/public/interfaces/cursor/cursor_struct_traits_unittest.cc
@@ -99,4 +99,21 @@ } } +// Test that we deal with empty bitmaps. (When a cursor resource isn't loaded +// in the renderer, the renderer will send a kCurstomCursor with an empty +// bitmap.) +TEST_F(CursorStructTraitsTest, TestEmptyCursor) { + const base::TimeDelta kFrameDelay = base::TimeDelta::FromMilliseconds(15); + const gfx::Point kHotspot = gfx::Point(5, 2); + const float kScale = 2.0f; + + ui::CursorData input(kHotspot, {SkBitmap()}, kScale, kFrameDelay); + + ui::CursorData output; + ASSERT_TRUE(EchoCursorData(input, &output)); + + ASSERT_EQ(1u, output.cursor_frames().size()); + EXPECT_TRUE(output.cursor_frames().front().empty()); +} + } // namespace ui
diff --git a/services/ui/public/interfaces/window_manager.mojom b/services/ui/public/interfaces/window_manager.mojom index 2d25904..a0b935cf 100644 --- a/services/ui/public/interfaces/window_manager.mojom +++ b/services/ui/public/interfaces/window_manager.mojom
@@ -298,7 +298,7 @@ WmSetFrameDecorationValues(FrameDecorationValues values); // Sets the cursor that the non-client areas of the window should use. - WmSetNonClientCursor(uint32 window_id, CursorType cursor_id); + WmSetNonClientCursor(uint32 window_id, CursorData cursor); // Response from WmCreateTopLevelWindow() informing the client of the id for // the new window.
diff --git a/services/ui/public/interfaces/window_tree.mojom b/services/ui/public/interfaces/window_tree.mojom index b8c4fabc..47c812c 100644 --- a/services/ui/public/interfaces/window_tree.mojom +++ b/services/ui/public/interfaces/window_tree.mojom
@@ -244,12 +244,10 @@ // Marks the specified window as being able to receive focus. SetCanFocus(uint32 window_id, bool can_focus); - // Sets the cursor when the pointer is inside |window_id| to a system standard - // cursor provided by the window manager. - SetPredefinedCursor(uint32 change_id, uint32 window_id, CursorType cursor_id); + // Sets the cursor when the pointer is inside |window_id|. + SetCursor(uint32 change_id, uint32 window_id, CursorData cursor); - // TODO(erg): Additional cursor methods. Image based cursors, visibility, - // and cursor locking. + // TODO(erg): Additional cursor methods. Visibility, and cursor locking. // Set text input state for the given window. SetWindowTextInputState(uint32 window_id, mojo.TextInputState state); @@ -467,7 +465,7 @@ // initiate the change. OnWindowFocused(uint32 focused_window_id); - OnWindowPredefinedCursorChanged(uint32 window_id, CursorType cursor_id); + OnWindowCursorChanged(uint32 window_id, CursorData cursor); // Invoked when a client window submits a new surface ID. The surface ID and // associated information is propagated to the parent connection. The parent
diff --git a/services/ui/ws/cursor_unittest.cc b/services/ui/ws/cursor_unittest.cc index ee0d8865..1b75b86 100644 --- a/services/ui/ws/cursor_unittest.cc +++ b/services/ui/ws/cursor_unittest.cc
@@ -24,6 +24,7 @@ #include "services/ui/ws/window_tree.h" #include "services/ui/ws/window_tree_binding.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/cursor/cursor.h" #include "ui/events/event.h" #include "ui/gfx/geometry/rect.h" @@ -42,7 +43,9 @@ TestWindowServerDelegate* window_server_delegate() { return ws_test_helper_.window_server_delegate(); } - mojom::CursorType cursor() const { return ws_test_helper_.cursor(); } + ui::CursorType cursor_type() const { + return ws_test_helper_.cursor().cursor_type(); + } protected: // testing::Test: @@ -108,81 +111,86 @@ TEST_F(CursorTest, ChangeByMouseMove) { ServerWindow* win = BuildServerWindow(); - win->SetPredefinedCursor(mojom::CursorType::kIBeam); - win->parent()->SetPredefinedCursor(mojom::CursorType::kCell); - EXPECT_EQ(mojom::CursorType::kIBeam, win->cursor()); - win->SetNonClientCursor(mojom::CursorType::kEastResize); - EXPECT_EQ(mojom::CursorType::kEastResize, win->non_client_cursor()); + win->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + win->parent()->SetCursor(ui::CursorData(ui::CursorType::kCell)); + EXPECT_EQ(ui::CursorType::kIBeam, win->cursor().cursor_type()); + win->SetNonClientCursor(ui::CursorData(ui::CursorType::kEastResize)); + EXPECT_EQ(ui::CursorType::kEastResize, + win->non_client_cursor().cursor_type()); // Non client area MoveCursorTo(gfx::Point(15, 15)); - EXPECT_EQ(mojom::CursorType::kEastResize, cursor()); + EXPECT_EQ(ui::CursorType::kEastResize, cursor_type()); // Client area, which comes from win->parent(). MoveCursorTo(gfx::Point(25, 25)); - EXPECT_EQ(mojom::CursorType::kCell, cursor()); + EXPECT_EQ(ui::CursorType::kCell, cursor_type()); } TEST_F(CursorTest, ChangeByClientAreaChange) { ServerWindow* win = BuildServerWindow(); - win->parent()->SetPredefinedCursor(mojom::CursorType::kCross); - win->SetPredefinedCursor(mojom::CursorType::kIBeam); - EXPECT_EQ(mojom::CursorType::kIBeam, mojom::CursorType(win->cursor())); - win->SetNonClientCursor(mojom::CursorType::kEastResize); - EXPECT_EQ(mojom::CursorType::kEastResize, win->non_client_cursor()); + win->parent()->SetCursor(ui::CursorData(ui::CursorType::kCross)); + win->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + EXPECT_EQ(ui::CursorType::kIBeam, win->cursor().cursor_type()); + win->SetNonClientCursor(ui::CursorData(ui::CursorType::kEastResize)); + EXPECT_EQ(ui::CursorType::kEastResize, + win->non_client_cursor().cursor_type()); // Non client area before we move. MoveCursorTo(gfx::Point(15, 15)); - EXPECT_EQ(mojom::CursorType::kEastResize, cursor()); + EXPECT_EQ(ui::CursorType::kEastResize, cursor_type()); // Changing the client area should cause a change. The cursor for the client // area comes from root ancestor, which is win->parent(). win->SetClientArea(gfx::Insets(1, 1), std::vector<gfx::Rect>()); - EXPECT_EQ(mojom::CursorType::kCross, cursor()); + EXPECT_EQ(ui::CursorType::kCross, cursor_type()); } TEST_F(CursorTest, NonClientCursorChange) { ServerWindow* win = BuildServerWindow(); - win->SetPredefinedCursor(mojom::CursorType::kIBeam); - EXPECT_EQ(mojom::CursorType::kIBeam, win->cursor()); - win->SetNonClientCursor(mojom::CursorType::kEastResize); - EXPECT_EQ(mojom::CursorType::kEastResize, win->non_client_cursor()); + win->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + EXPECT_EQ(ui::CursorType::kIBeam, win->cursor().cursor_type()); + win->SetNonClientCursor(ui::CursorData(ui::CursorType::kEastResize)); + EXPECT_EQ(ui::CursorType::kEastResize, + win->non_client_cursor().cursor_type()); MoveCursorTo(gfx::Point(15, 15)); - EXPECT_EQ(mojom::CursorType::kEastResize, cursor()); + EXPECT_EQ(ui::CursorType::kEastResize, cursor_type()); - win->SetNonClientCursor(mojom::CursorType::kWestResize); - EXPECT_EQ(mojom::CursorType::kWestResize, cursor()); + win->SetNonClientCursor(ui::CursorData(ui::CursorType::kWestResize)); + EXPECT_EQ(ui::CursorType::kWestResize, cursor_type()); } TEST_F(CursorTest, IgnoreClientCursorChangeInNonClientArea) { ServerWindow* win = BuildServerWindow(); - win->SetPredefinedCursor(mojom::CursorType::kIBeam); - EXPECT_EQ(mojom::CursorType::kIBeam, win->cursor()); - win->SetNonClientCursor(mojom::CursorType::kEastResize); - EXPECT_EQ(mojom::CursorType::kEastResize, win->non_client_cursor()); + win->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + EXPECT_EQ(ui::CursorType::kIBeam, win->cursor().cursor_type()); + win->SetNonClientCursor(ui::CursorData(ui::CursorType::kEastResize)); + EXPECT_EQ(ui::CursorType::kEastResize, + win->non_client_cursor().cursor_type()); MoveCursorTo(gfx::Point(15, 15)); - EXPECT_EQ(mojom::CursorType::kEastResize, cursor()); + EXPECT_EQ(ui::CursorType::kEastResize, cursor_type()); - win->SetPredefinedCursor(mojom::CursorType::kHelp); - EXPECT_EQ(mojom::CursorType::kEastResize, cursor()); + win->SetCursor(ui::CursorData(ui::CursorType::kHelp)); + EXPECT_EQ(ui::CursorType::kEastResize, cursor_type()); } TEST_F(CursorTest, NonClientToClientByBoundsChange) { ServerWindow* win = BuildServerWindow(); - win->parent()->SetPredefinedCursor(mojom::CursorType::kCopy); - win->SetPredefinedCursor(mojom::CursorType::kIBeam); - EXPECT_EQ(mojom::CursorType::kIBeam, win->cursor()); - win->SetNonClientCursor(mojom::CursorType::kEastResize); - EXPECT_EQ(mojom::CursorType::kEastResize, win->non_client_cursor()); + win->parent()->SetCursor(ui::CursorData(ui::CursorType::kCopy)); + win->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + EXPECT_EQ(ui::CursorType::kIBeam, win->cursor().cursor_type()); + win->SetNonClientCursor(ui::CursorData(ui::CursorType::kEastResize)); + EXPECT_EQ(ui::CursorType::kEastResize, + win->non_client_cursor().cursor_type()); // Non client area before we move. MoveCursorTo(gfx::Point(15, 15)); - EXPECT_EQ(mojom::CursorType::kEastResize, cursor()); + EXPECT_EQ(ui::CursorType::kEastResize, cursor_type()); win->SetBounds(gfx::Rect(0, 0, 30, 30)); - EXPECT_EQ(mojom::CursorType::kCopy, cursor()); + EXPECT_EQ(ui::CursorType::kCopy, cursor_type()); } } // namespace test
diff --git a/services/ui/ws/display.cc b/services/ui/ws/display.cc index 98c6cfa..becd40ed 100644 --- a/services/ui/ws/display.cc +++ b/services/ui/ws/display.cc
@@ -37,7 +37,8 @@ namespace ws { Display::Display(WindowServer* window_server) - : window_server_(window_server), last_cursor_(mojom::CursorType::kNull) { + : window_server_(window_server), + last_cursor_(ui::CursorData(ui::CursorType::kNull)) { window_server_->window_manager_window_tree_factory_set()->AddObserver(this); window_server_->user_id_tracker()->AddObserver(this); } @@ -197,10 +198,10 @@ NOTREACHED(); } -void Display::UpdateNativeCursor(mojom::CursorType cursor_id) { - if (cursor_id != last_cursor_) { - platform_display_->SetCursorById(cursor_id); - last_cursor_ = cursor_id; +void Display::UpdateNativeCursor(const ui::CursorData& cursor) { + if (!last_cursor_.IsSameAs(cursor)) { + platform_display_->SetCursor(cursor); + last_cursor_ = cursor; } }
diff --git a/services/ui/ws/display.h b/services/ui/ws/display.h index b83ce21..f2d8c732 100644 --- a/services/ui/ws/display.h +++ b/services/ui/ws/display.h
@@ -149,7 +149,7 @@ // |display_root| being destroyed. void RemoveWindowManagerDisplayRoot(WindowManagerDisplayRoot* display_root); - void UpdateNativeCursor(mojom::CursorType cursor_id); + void UpdateNativeCursor(const ui::CursorData& cursor); // mojom::WindowTreeHost: void SetSize(const gfx::Size& size) override; @@ -219,7 +219,7 @@ display::Display display_; // The last cursor set. Used to track whether we need to change the cursor. - mojom::CursorType last_cursor_; + ui::CursorData last_cursor_; ServerWindowTracker activation_parents_;
diff --git a/services/ui/ws/drag_controller.cc b/services/ui/ws/drag_controller.cc index d5bce60..cc3b999 100644 --- a/services/ui/ws/drag_controller.cc +++ b/services/ui/ws/drag_controller.cc
@@ -13,6 +13,7 @@ #include "services/ui/ws/drag_target_connection.h" #include "services/ui/ws/event_dispatcher.h" #include "services/ui/ws/server_window.h" +#include "ui/base/cursor/cursor.h" namespace ui { namespace ws { @@ -52,7 +53,7 @@ cursor_updater_(cursor_updater), drag_operations_(drag_operations), drag_pointer_id_(drag_pointer), - current_cursor_(ui::mojom::CursorType::kNoDrop), + current_cursor_(ui::CursorType::kNoDrop), source_window_(source_window), source_connection_(source_connection), mime_data_(mime_data), @@ -187,11 +188,12 @@ } } -ui::mojom::CursorType DragController::CursorForEffectBitmask( +ui::CursorData DragController::CursorForEffectBitmask( DropEffectBitmask bitmask) { DropEffectBitmask combined = bitmask & drag_operations_; - return combined == ui::mojom::kDropEffectNone ? ui::mojom::CursorType::kNoDrop - : ui::mojom::CursorType::kCopy; + return combined == ui::mojom::kDropEffectNone + ? ui::CursorData(ui::CursorType::kNoDrop) + : ui::CursorData(ui::CursorType::kCopy); } void DragController::SetCurrentTargetWindow(ServerWindow* current_target) { @@ -204,7 +206,7 @@ current_cursor_ = CursorForEffectBitmask(state.bitmask); } else { // Can't drop in empty areas. - current_cursor_ = ui::mojom::CursorType::kNoDrop; + current_cursor_ = ui::CursorData(ui::CursorType::kNoDrop); } cursor_updater_->OnDragCursorUpdated();
diff --git a/services/ui/ws/drag_controller.h b/services/ui/ws/drag_controller.h index de8ea9a..83e6abc 100644 --- a/services/ui/ws/drag_controller.h +++ b/services/ui/ws/drag_controller.h
@@ -53,7 +53,7 @@ DropEffectBitmask drag_operations); ~DragController() override; - ui::mojom::CursorType current_cursor() const { return current_cursor_; } + const ui::CursorData& current_cursor() const { return current_cursor_; } // Cancels the current drag, ie, due to the user pressing Escape. void Cancel(); @@ -89,9 +89,9 @@ // bitmask of the current valid drag operations. void SetWindowDropOperations(ServerWindow* window, DropEffectBitmask bitmask); - // Returns the ui::mojom::Cursor for the window |bitmask|, adjusted for types - // that the drag source allows. - ui::mojom::CursorType CursorForEffectBitmask(DropEffectBitmask bitmask); + // Returns the cursor for the window |bitmask|, adjusted for types that the + // drag source allows. + ui::CursorData CursorForEffectBitmask(DropEffectBitmask bitmask); // Ensure that |window| has an entry in |window_state_| and that we're an // observer. @@ -126,7 +126,7 @@ const int32_t drag_pointer_id_; // The current mouse cursor during the drag. - ui::mojom::CursorType current_cursor_; + ui::CursorData current_cursor_; // Sending OnDragOver() to our |source_| destroys us; there is a period where // we have to continue to exist, but not process any more pointer events.
diff --git a/services/ui/ws/drag_controller_unittest.cc b/services/ui/ws/drag_controller_unittest.cc index 6484f8c..6e10d0f 100644 --- a/services/ui/ws/drag_controller_unittest.cc +++ b/services/ui/ws/drag_controller_unittest.cc
@@ -18,6 +18,7 @@ #include "services/ui/ws/test_server_window_delegate.h" #include "services/ui/ws/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/cursor/cursor.h" #include "ui/events/base_event_utils.h" namespace ui { @@ -162,7 +163,7 @@ // It would be nice if we could just let the observer method fire, but it // fires during the constructor when we haven't assigned the unique_ptr // yet. - cursor_ = ui::mojom::CursorType(drag_operation_->current_cursor()); + cursor_ = drag_operation_->current_cursor().cursor_type(); } void DispatchDrag(DragTestWindow* window, @@ -204,7 +205,7 @@ return drag_completed_value_; } - ui::mojom::CursorType cursor() { return cursor_; } + ui::CursorType cursor_type() const { return cursor_; } private: // Overridden from testing::Test: @@ -232,7 +233,7 @@ // Overridden from DragCursorUpdater: void OnDragCursorUpdated() override { if (drag_operation_) - cursor_ = ui::mojom::CursorType(drag_operation_->current_cursor()); + cursor_ = drag_operation_->current_cursor().cursor_type(); } // Overridden from DragControllerSource: @@ -260,7 +261,7 @@ int window_id_ = 3; - ui::mojom::CursorType cursor_; + ui::CursorType cursor_; std::map<WindowId, ServerWindow*> server_window_by_id_; std::map<ServerWindow*, DragTargetConnection*> connection_by_window_; @@ -282,14 +283,14 @@ std::unique_ptr<DragTestWindow> window = BuildWindow(); StartDragOperation(window.get(), ui::mojom::kDropEffectMove); - EXPECT_EQ(ui::mojom::CursorType::kNoDrop, cursor()); + EXPECT_EQ(ui::CursorType::kNoDrop, cursor_type()); DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); window->Respond(true); // (Even though we're doing a move, the cursor name is COPY.) - EXPECT_EQ(ui::mojom::CursorType::kCopy, cursor()); + EXPECT_EQ(ui::CursorType::kCopy, cursor_type()); DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); EXPECT_EQ(QueuedType::OVER, window->queue_response_type()); @@ -538,7 +539,7 @@ std::unique_ptr<DragTestWindow> window1 = BuildWindow(); std::unique_ptr<DragTestWindow> window2 = BuildWindow(); StartDragOperation(window1.get(), ui::mojom::kDropEffectMove); - EXPECT_EQ(ui::mojom::CursorType::kNoDrop, cursor()); + EXPECT_EQ(ui::CursorType::kNoDrop, cursor_type()); // Send some events to |window|. DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, @@ -548,13 +549,13 @@ DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); window2->Respond(true); - EXPECT_EQ(ui::mojom::CursorType::kCopy, cursor()); + EXPECT_EQ(ui::CursorType::kCopy, cursor_type()); // Force the destruction of |window.window|. window2.reset(); // The cursor no loner indicates that it can drop on |window2|. - EXPECT_EQ(ui::mojom::CursorType::kNoDrop, cursor()); + EXPECT_EQ(ui::CursorType::kNoDrop, cursor_type()); } TEST_F(DragControllerTest, SourceWindowClosedWhileDrag) { @@ -640,20 +641,20 @@ std::unique_ptr<DragTestWindow> window = BuildWindow(); StartDragOperation(window.get(), ui::mojom::kDropEffectMove); - EXPECT_EQ(ui::mojom::CursorType::kNoDrop, cursor()); + EXPECT_EQ(ui::CursorType::kNoDrop, cursor_type()); DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); EXPECT_EQ(QueuedType::ENTER, window->queue_response_type()); window->Respond(true); - EXPECT_EQ(ui::mojom::CursorType::kCopy, cursor()); + EXPECT_EQ(ui::CursorType::kCopy, cursor_type()); DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2)); EXPECT_EQ(QueuedType::OVER, window->queue_response_type()); // At this point, we respond with no available drag actions at this pixel. window->Respond(false); - EXPECT_EQ(ui::mojom::CursorType::kNoDrop, cursor()); + EXPECT_EQ(ui::CursorType::kNoDrop, cursor_type()); } TEST_F(DragControllerTest, ResopnseFromOtherWindowDoesntChangeCursor) { @@ -668,7 +669,7 @@ DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1)); - EXPECT_EQ(ui::mojom::CursorType::kNoDrop, cursor()); + EXPECT_EQ(ui::CursorType::kNoDrop, cursor_type()); // Now enter |window1|, and respond. DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON, @@ -676,13 +677,13 @@ EXPECT_EQ(QueuedType::ENTER, window1->queue_response_type()); window1->Respond(true); - EXPECT_EQ(ui::mojom::CursorType::kCopy, cursor()); + EXPECT_EQ(ui::CursorType::kCopy, cursor_type()); // Window 2 responding negatively to its queued messages shouldn't change the // cursor. window2->Respond(false); - EXPECT_EQ(ui::mojom::CursorType::kCopy, cursor()); + EXPECT_EQ(ui::CursorType::kCopy, cursor_type()); } } // namespace ws
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc index 9edd3bc9..83e8b37 100644 --- a/services/ui/ws/event_dispatcher.cc +++ b/services/ui/ws/event_dispatcher.cc
@@ -16,6 +16,7 @@ #include "services/ui/ws/server_window_delegate.h" #include "services/ui/ws/window_coordinate_conversions.h" #include "services/ui/ws/window_finder.h" +#include "ui/base/cursor/cursor.h" #include "ui/events/event_utils.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_conversions.h" @@ -86,18 +87,18 @@ delegate_->OnMouseCursorLocationChanged(screen_location); } -ui::mojom::CursorType EventDispatcher::GetCurrentMouseCursor() const { +ui::CursorData EventDispatcher::GetCurrentMouseCursor() const { if (drag_controller_) return drag_controller_->current_cursor(); if (!mouse_cursor_source_window_) - return ui::mojom::CursorType::kPointer; + return ui::CursorData(ui::CursorType::kPointer); if (mouse_cursor_in_non_client_area_) return mouse_cursor_source_window_->non_client_cursor(); const ServerWindow* window = GetWindowForMouseCursor(); - return window ? window->cursor() : ui::mojom::CursorType::kPointer; + return window ? window->cursor() : ui::CursorData(ui::CursorType::kPointer); } bool EventDispatcher::SetCaptureWindow(ServerWindow* window,
diff --git a/services/ui/ws/event_dispatcher.h b/services/ui/ws/event_dispatcher.h index 5d9c786..8b084d7 100644 --- a/services/ui/ws/event_dispatcher.h +++ b/services/ui/ws/event_dispatcher.h
@@ -66,7 +66,7 @@ // Returns the cursor for the current target, or POINTER if the mouse is not // over a valid target. - ui::mojom::CursorType GetCurrentMouseCursor() const; + ui::CursorData GetCurrentMouseCursor() const; // |capture_window_| will receive all input. See window_tree.mojom for // details.
diff --git a/services/ui/ws/platform_display.h b/services/ui/ws/platform_display.h index 7f82a61..bdfb5b4 100644 --- a/services/ui/ws/platform_display.h +++ b/services/ui/ws/platform_display.h
@@ -46,7 +46,7 @@ virtual void ReleaseCapture() = 0; - virtual void SetCursorById(mojom::CursorType cursor) = 0; + virtual void SetCursor(const ui::CursorData& cursor) = 0; virtual void UpdateTextInputState(const ui::TextInputState& state) = 0; virtual void SetImeVisibility(bool visible) = 0;
diff --git a/services/ui/ws/platform_display_default.cc b/services/ui/ws/platform_display_default.cc index 93611c8..b879e335 100644 --- a/services/ui/ws/platform_display_default.cc +++ b/services/ui/ws/platform_display_default.cc
@@ -26,6 +26,7 @@ #elif defined(OS_ANDROID) #include "ui/platform_window/android/platform_window_android.h" #elif defined(USE_OZONE) +#include "ui/ozone/public/cursor_factory_ozone.h" #include "ui/ozone/public/ozone_platform.h" #endif @@ -100,22 +101,43 @@ platform_window_->ReleaseCapture(); } -void PlatformDisplayDefault::SetCursorById(mojom::CursorType cursor_id) { +void PlatformDisplayDefault::SetCursor(const ui::CursorData& cursor_data) { if (!image_cursors_) return; - // TODO(erg): This still isn't sufficient, and will only use native cursors - // that chrome would use, not custom image cursors. For that, we should - // delegate to the window manager to load images from resource packs. - // - // We probably also need to deal with different DPIs. - ui::CursorType type; - if (mojo::EnumTraits<ui::mojom::CursorType, ui::CursorType>::FromMojom( - cursor_id, &type)) { - ui::Cursor cursor(type); - image_cursors_->SetPlatformCursor(&cursor); - platform_window_->SetCursor(cursor.platform()); + ui::Cursor native_cursor(cursor_data.cursor_type()); + +#if defined(USE_OZONE) + if (cursor_data.cursor_type() != ui::CursorType::kCustom) { + image_cursors_->SetPlatformCursor(&native_cursor); + } else { + // In Ozone builds, we have an interface available which turns bitmap data + // into platform cursors. + ui::CursorFactoryOzone* cursor_factory = + delegate_->GetOzonePlatform()->GetCursorFactoryOzone(); + native_cursor.SetPlatformCursor(cursor_factory->CreateAnimatedCursor( + cursor_data.cursor_frames(), cursor_data.hotspot_in_pixels(), + cursor_data.frame_delay().InMilliseconds(), + cursor_data.scale_factor())); } +#else + // Outside of ozone builds, there isn't a single interface for creating + // PlatformCursors. The closest thing to one is in //content/ instead of + // //ui/ which means we can't use it from here. For now, just don't handle + // custom image cursors. + // + // TODO(erg): Once blink speaks directly to mus, make blink perform its own + // cursor management on its own mus windows so we can remove Webcursor from + // //content/ and do this in way that's safe cross-platform, instead of as an + // ozone-specific hack. + if (cursor_data.cursor_type() == ui::CursorType::kCustom) { + NOTIMPLEMENTED() << "No custom cursor support on non-ozone yet."; + native_cursor = ui::Cursor(ui::CursorType::kPointer); + } + image_cursors_->SetPlatformCursor(&native_cursor); +#endif + + platform_window_->SetCursor(native_cursor.platform()); } void PlatformDisplayDefault::UpdateTextInputState(
diff --git a/services/ui/ws/platform_display_default.h b/services/ui/ws/platform_display_default.h index 3c7d590..5ca1ba6 100644 --- a/services/ui/ws/platform_display_default.h +++ b/services/ui/ws/platform_display_default.h
@@ -44,7 +44,7 @@ void SetTitle(const base::string16& title) override; void SetCapture() override; void ReleaseCapture() override; - void SetCursorById(mojom::CursorType cursor) override; + void SetCursor(const ui::CursorData& cursor) override; void UpdateTextInputState(const ui::TextInputState& state) override; void SetImeVisibility(bool visible) override; void UpdateViewportMetrics(const display::ViewportMetrics& metrics) override;
diff --git a/services/ui/ws/server_window.cc b/services/ui/ws/server_window.cc index 2f59aac1..c3760afd 100644 --- a/services/ui/ws/server_window.cc +++ b/services/ui/ws/server_window.cc
@@ -14,6 +14,7 @@ #include "services/ui/ws/server_window_compositor_frame_sink_manager.h" #include "services/ui/ws/server_window_delegate.h" #include "services/ui/ws/server_window_observer.h" +#include "ui/base/cursor/cursor.h" namespace ui { namespace ws { @@ -34,8 +35,8 @@ visible_(false), // Default to kPointer as kNull doesn't change the cursor, it leaves // the last non-null cursor. - cursor_id_(mojom::CursorType::kPointer), - non_client_cursor_id_(mojom::CursorType::kPointer), + cursor_(ui::CursorType::kPointer), + non_client_cursor_(ui::CursorType::kPointer), opacity_(1), can_focus_(true), properties_(properties), @@ -299,20 +300,20 @@ observer.OnWindowOpacityChanged(this, old_opacity, opacity_); } -void ServerWindow::SetPredefinedCursor(ui::mojom::CursorType value) { - if (value == cursor_id_) +void ServerWindow::SetCursor(ui::CursorData value) { + if (cursor_.IsSameAs(value)) return; - cursor_id_ = value; + cursor_ = std::move(value); for (auto& observer : observers_) - observer.OnWindowPredefinedCursorChanged(this, value); + observer.OnWindowCursorChanged(this, cursor_); } -void ServerWindow::SetNonClientCursor(ui::mojom::CursorType value) { - if (value == non_client_cursor_id_) +void ServerWindow::SetNonClientCursor(ui::CursorData value) { + if (non_client_cursor_.IsSameAs(value)) return; - non_client_cursor_id_ = value; + non_client_cursor_ = std::move(value); for (auto& observer : observers_) - observer.OnWindowNonClientCursorChanged(this, value); + observer.OnWindowNonClientCursorChanged(this, non_client_cursor_); } void ServerWindow::SetTransform(const gfx::Transform& transform) {
diff --git a/services/ui/ws/server_window.h b/services/ui/ws/server_window.h index 3a7fa5a..cc8fce16 100644 --- a/services/ui/ws/server_window.h +++ b/services/ui/ws/server_window.h
@@ -105,10 +105,8 @@ bool can_accept_drops() const { return accepts_drops_; } void SetCanAcceptDrops(bool accepts_drags); - ui::mojom::CursorType cursor() const { return cursor_id_; } - ui::mojom::CursorType non_client_cursor() const { - return non_client_cursor_id_; - } + const ui::CursorData& cursor() const { return cursor_; } + const ui::CursorData& non_client_cursor() const { return non_client_cursor_; } const ServerWindow* parent() const { return parent_; } ServerWindow* parent() { return parent_; } @@ -151,8 +149,8 @@ float opacity() const { return opacity_; } void SetOpacity(float value); - void SetPredefinedCursor(ui::mojom::CursorType cursor_id); - void SetNonClientCursor(ui::mojom::CursorType cursor_id); + void SetCursor(ui::CursorData cursor); + void SetNonClientCursor(ui::CursorData cursor); const gfx::Transform& transform() const { return transform_; } void SetTransform(const gfx::Transform& transform); @@ -252,8 +250,8 @@ std::vector<gfx::Rect> additional_client_areas_; std::unique_ptr<ServerWindowCompositorFrameSinkManager> compositor_frame_sink_manager_; - mojom::CursorType cursor_id_; - mojom::CursorType non_client_cursor_id_; + ui::CursorData cursor_; + ui::CursorData non_client_cursor_; float opacity_; bool can_focus_; mojom::EventTargetingPolicy event_targeting_policy_ =
diff --git a/services/ui/ws/server_window_observer.h b/services/ui/ws/server_window_observer.h index 265c408..400c087 100644 --- a/services/ui/ws/server_window_observer.h +++ b/services/ui/ws/server_window_observer.h
@@ -66,10 +66,11 @@ float old_opacity, float new_opacity) {} - virtual void OnWindowPredefinedCursorChanged(ServerWindow* window, - mojom::CursorType cursor_id) {} - virtual void OnWindowNonClientCursorChanged(ServerWindow* window, - mojom::CursorType cursor_id) {} + virtual void OnWindowCursorChanged(ServerWindow* window, + const ui::CursorData& cursor_data) {} + virtual void OnWindowNonClientCursorChanged( + ServerWindow* window, + const ui::CursorData& cursor_data) {} virtual void OnWindowTextInputStateChanged(ServerWindow* window, const ui::TextInputState& state) {}
diff --git a/services/ui/ws/test_change_tracker.cc b/services/ui/ws/test_change_tracker.cc index b27d565..104cc614 100644 --- a/services/ui/ws/test_change_tracker.cc +++ b/services/ui/ws/test_change_tracker.cc
@@ -10,6 +10,7 @@ #include "base/strings/stringprintf.h" #include "mojo/public/cpp/bindings/map.h" #include "services/ui/common/util.h" +#include "ui/base/cursor/cursor.h" namespace ui { @@ -131,9 +132,9 @@ WindowIdToString(change.window_id).c_str()); case CHANGE_TYPE_CURSOR_CHANGED: - return base::StringPrintf("CursorChanged id=%s cursor_id=%d", + return base::StringPrintf("CursorChanged id=%s cursor_type=%d", WindowIdToString(change.window_id).c_str(), - change.cursor_id); + static_cast<int>(change.cursor_type)); case CHANGE_TYPE_ON_CHANGE_COMPLETED: return base::StringPrintf("ChangeCompleted id=%d sucess=%s", change.change_id, @@ -230,7 +231,7 @@ direction(mojom::OrderDirection::ABOVE), bool_value(false), float_value(0.f), - cursor_id(0), + cursor_type(ui::CursorType::kNull), change_id(0u) {} Change::Change(const Change& other) = default; @@ -420,13 +421,12 @@ AddChange(change); } -void TestChangeTracker::OnWindowPredefinedCursorChanged( - Id window_id, - mojom::CursorType cursor_id) { +void TestChangeTracker::OnWindowCursorChanged(Id window_id, + const ui::CursorData& cursor) { Change change; change.type = CHANGE_TYPE_CURSOR_CHANGED; change.window_id = window_id; - change.cursor_id = static_cast<int32_t>(cursor_id); + change.cursor_type = cursor.cursor_type(); AddChange(change); }
diff --git a/services/ui/ws/test_change_tracker.h b/services/ui/ws/test_change_tracker.h index 98f259f..c4162ad 100644 --- a/services/ui/ws/test_change_tracker.h +++ b/services/ui/ws/test_change_tracker.h
@@ -89,7 +89,7 @@ float float_value; std::string property_key; std::string property_value; - int32_t cursor_id; + ui::CursorType cursor_type; uint32_t change_id; cc::SurfaceId surface_id; gfx::Size frame_size; @@ -179,8 +179,7 @@ const std::string& name, const base::Optional<std::vector<uint8_t>>& data); void OnWindowFocused(Id window_id); - void OnWindowPredefinedCursorChanged(Id window_id, - mojom::CursorType cursor_id); + void OnWindowCursorChanged(Id window_id, const ui::CursorData& cursor); void OnChangeCompleted(uint32_t change_id, bool success); void OnTopLevelCreated(uint32_t change_id, mojom::WindowDataPtr window_data,
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc index fe0428c..e926d366 100644 --- a/services/ui/ws/test_utils.cc +++ b/services/ui/ws/test_utils.cc
@@ -16,6 +16,7 @@ #include "services/ui/ws/window_manager_access_policy.h" #include "services/ui/ws/window_manager_window_tree_factory.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/cursor/cursor.h" #include "ui/gfx/geometry/dip_util.h" namespace ui { @@ -28,7 +29,7 @@ class TestPlatformDisplay : public PlatformDisplay { public: explicit TestPlatformDisplay(const display::ViewportMetrics& metrics, - mojom::CursorType* cursor_storage) + ui::CursorData* cursor_storage) : metrics_(metrics), cursor_storage_(cursor_storage) {} ~TestPlatformDisplay() override {} @@ -40,7 +41,7 @@ void SetTitle(const base::string16& title) override {} void SetCapture() override {} void ReleaseCapture() override {} - void SetCursorById(mojom::CursorType cursor) override { + void SetCursor(const ui::CursorData& cursor) override { *cursor_storage_ = cursor; } void UpdateTextInputState(const ui::TextInputState& state) override {} @@ -56,7 +57,7 @@ private: display::ViewportMetrics metrics_; - mojom::CursorType* cursor_storage_; + ui::CursorData* cursor_storage_; DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplay); }; @@ -149,7 +150,7 @@ // TestPlatformDisplayFactory ------------------------------------------------- TestPlatformDisplayFactory::TestPlatformDisplayFactory( - mojom::CursorType* cursor_storage) + ui::CursorData* cursor_storage) : cursor_storage_(cursor_storage) {} TestPlatformDisplayFactory::~TestPlatformDisplayFactory() {} @@ -423,10 +424,9 @@ tracker_.OnWindowFocused(focused_window_id); } -void TestWindowTreeClient::OnWindowPredefinedCursorChanged( - uint32_t window_id, - mojom::CursorType cursor_id) { - tracker_.OnWindowPredefinedCursorChanged(window_id, cursor_id); +void TestWindowTreeClient::OnWindowCursorChanged(uint32_t window_id, + ui::CursorData cursor) { + tracker_.OnWindowCursorChanged(window_id, cursor); } void TestWindowTreeClient::OnWindowSurfaceChanged( @@ -530,8 +530,7 @@ // WindowServerTestHelper --------------------------------------------------- WindowServerTestHelper::WindowServerTestHelper() - : cursor_id_(mojom::CursorType::kNull), - platform_display_factory_(&cursor_id_) { + : cursor_(ui::CursorType::kNull), platform_display_factory_(&cursor_) { // Some tests create their own message loop, for example to add a task runner. if (!base::MessageLoop::current()) message_loop_ = base::MakeUnique<base::MessageLoop>();
diff --git a/services/ui/ws/test_utils.h b/services/ui/ws/test_utils.h index f5e0bb08..5be2f294 100644 --- a/services/ui/ws/test_utils.h +++ b/services/ui/ws/test_utils.h
@@ -151,7 +151,7 @@ void OnEvent(ui::Event* event) { display_->OnEventFromSource(event); } - mojom::CursorType last_cursor() const { return display_->last_cursor_; } + const ui::CursorData& last_cursor() const { return display_->last_cursor_; } private: Display* display_; @@ -300,7 +300,7 @@ // Factory that dispenses TestPlatformDisplays. class TestPlatformDisplayFactory : public PlatformDisplayFactory { public: - explicit TestPlatformDisplayFactory(mojom::CursorType* cursor_storage); + explicit TestPlatformDisplayFactory(ui::CursorData* cursor_storage); ~TestPlatformDisplayFactory(); // PlatformDisplayFactory: @@ -309,7 +309,7 @@ const display::ViewportMetrics& metrics) override; private: - mojom::CursorType* cursor_storage_; + ui::CursorData* cursor_storage_; DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplayFactory); }; @@ -490,8 +490,8 @@ uint32_t window_id, int64_t display_id) override; void OnWindowFocused(uint32_t focused_window_id) override; - void OnWindowPredefinedCursorChanged(uint32_t window_id, - mojom::CursorType cursor_id) override; + void OnWindowCursorChanged(uint32_t window_id, + ui::CursorData cursor) override; void OnWindowSurfaceChanged(Id window_id, const cc::SurfaceInfo& surface_info) override; void OnDragDropStart( @@ -622,14 +622,14 @@ ~WindowServerTestHelper(); WindowServer* window_server() { return window_server_.get(); } - mojom::CursorType cursor() const { return cursor_id_; } + ui::CursorData cursor() const { return cursor_; } TestWindowServerDelegate* window_server_delegate() { return &window_server_delegate_; } private: - mojom::CursorType cursor_id_; + ui::CursorData cursor_; TestPlatformDisplayFactory platform_display_factory_; TestWindowServerDelegate window_server_delegate_; std::unique_ptr<WindowServer> window_server_; @@ -665,7 +665,9 @@ // Sets the task runner for |message_loop_| void SetTaskRunner(scoped_refptr<base::SingleThreadTaskRunner> task_runner); - mojom::CursorType cursor() const { return ws_test_helper_.cursor(); } + ui::CursorType cursor_type() const { + return ws_test_helper_.cursor().cursor_type(); + } Display* display() { return display_; } TestWindowTreeBinding* last_binding() { return ws_test_helper_.window_server_delegate()->last_binding();
diff --git a/services/ui/ws/window_manager_state.cc b/services/ui/ws/window_manager_state.cc index 35ff9b97..295eb4d 100644 --- a/services/ui/ws/window_manager_state.cc +++ b/services/ui/ws/window_manager_state.cc
@@ -588,10 +588,9 @@ } void WindowManagerState::UpdateNativeCursorFromDispatcher() { - const ui::mojom::CursorType cursor_id = - event_dispatcher_.GetCurrentMouseCursor(); + const ui::CursorData cursor = event_dispatcher_.GetCurrentMouseCursor(); for (Display* display : display_manager()->displays()) - display->UpdateNativeCursor(cursor_id); + display->UpdateNativeCursor(cursor); } void WindowManagerState::OnCaptureChanged(ServerWindow* new_capture,
diff --git a/services/ui/ws/window_manager_state_unittest.cc b/services/ui/ws/window_manager_state_unittest.cc index ce0c8ce3c..2fee93d3 100644 --- a/services/ui/ws/window_manager_state_unittest.cc +++ b/services/ui/ws/window_manager_state_unittest.cc
@@ -26,6 +26,7 @@ #include "services/ui/ws/window_server.h" #include "services/ui/ws/window_tree.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/cursor/cursor.h" #include "ui/events/event.h" namespace ui { @@ -649,8 +650,9 @@ window_tree()->AddWindow(FirstRootId(window_tree()), child_window_id); child_window->SetVisible(true); child_window->SetBounds(gfx::Rect(0, 0, 20, 20)); - child_window->parent()->SetPredefinedCursor(ui::mojom::CursorType::kCopy); - EXPECT_EQ(ui::mojom::CursorType::kCopy, display_test_api.last_cursor()); + child_window->parent()->SetCursor(ui::CursorData(ui::CursorType::kCopy)); + EXPECT_EQ(ui::CursorType::kCopy, + display_test_api.last_cursor().cursor_type()); // Move the mouse outside the bounds of the child, so that the mouse is not // over any valid windows. Cursor should change to POINTER. ui::PointerEvent move( @@ -660,7 +662,8 @@ window_manager_state()->ProcessEvent(move, 0); // The event isn't over a valid target, which should trigger resetting the // cursor to POINTER. - EXPECT_EQ(ui::mojom::CursorType::kPointer, display_test_api.last_cursor()); + EXPECT_EQ(ui::CursorType::kPointer, + display_test_api.last_cursor().cursor_type()); } } // namespace test
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc index d012b886..f48149ee5 100644 --- a/services/ui/ws/window_server.cc +++ b/services/ui/ws/window_server.cc
@@ -417,11 +417,10 @@ pair.second->ProcessWindowDeleted(window, IsOperationSource(pair.first)); } -void WindowServer::ProcessWillChangeWindowPredefinedCursor( - ServerWindow* window, - mojom::CursorType cursor_id) { +void WindowServer::ProcessWillChangeWindowCursor(ServerWindow* window, + const ui::CursorData& cursor) { for (auto& pair : tree_map_) { - pair.second->ProcessCursorChanged(window, cursor_id, + pair.second->ProcessCursorChanged(window, cursor, IsOperationSource(pair.first)); } } @@ -750,19 +749,19 @@ window); } -void WindowServer::OnWindowPredefinedCursorChanged( - ServerWindow* window, - mojom::CursorType cursor_id) { +void WindowServer::OnWindowCursorChanged(ServerWindow* window, + const ui::CursorData& cursor) { if (in_destructor_) return; - ProcessWillChangeWindowPredefinedCursor(window, cursor_id); + ProcessWillChangeWindowCursor(window, cursor); UpdateNativeCursorIfOver(window); } -void WindowServer::OnWindowNonClientCursorChanged(ServerWindow* window, - mojom::CursorType cursor_id) { +void WindowServer::OnWindowNonClientCursorChanged( + ServerWindow* window, + const ui::CursorData& cursor) { if (in_destructor_) return;
diff --git a/services/ui/ws/window_server.h b/services/ui/ws/window_server.h index d01c2e0..f79cf96 100644 --- a/services/ui/ws/window_server.h +++ b/services/ui/ws/window_server.h
@@ -188,8 +188,8 @@ const ServerWindow* relative_window, const mojom::OrderDirection direction); void ProcessWindowDeleted(ServerWindow* window); - void ProcessWillChangeWindowPredefinedCursor(ServerWindow* window, - mojom::CursorType cursor_id); + void ProcessWillChangeWindowCursor(ServerWindow* window, + const ui::CursorData& cursor); // Sends an |event| to all WindowTrees belonging to |user_id| that might be // observing events. Skips |ignore_tree| if it is non-null. |target_window| is @@ -322,10 +322,10 @@ ServerWindow* window, const std::string& name, const std::vector<uint8_t>* new_data) override; - void OnWindowPredefinedCursorChanged(ServerWindow* window, - mojom::CursorType cursor_id) override; + void OnWindowCursorChanged(ServerWindow* window, + const ui::CursorData& cursor) override; void OnWindowNonClientCursorChanged(ServerWindow* window, - mojom::CursorType cursor_id) override; + const ui::CursorData& cursor) override; void OnWindowTextInputStateChanged(ServerWindow* window, const ui::TextInputState& state) override; void OnTransientWindowAdded(ServerWindow* window,
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc index 76cca865..086fd81 100644 --- a/services/ui/ws/window_tree.cc +++ b/services/ui/ws/window_tree.cc
@@ -30,6 +30,7 @@ #include "services/ui/ws/window_manager_state.h" #include "services/ui/ws/window_server.h" #include "services/ui/ws/window_tree_binding.h" +#include "ui/base/cursor/cursor.h" #include "ui/display/display.h" #include "ui/display/display_list.h" #include "ui/display/screen_base.h" @@ -898,7 +899,7 @@ } void WindowTree::ProcessCursorChanged(const ServerWindow* window, - mojom::CursorType cursor_id, + const ui::CursorData& cursor, bool originated_change) { if (originated_change) return; @@ -906,7 +907,7 @@ if (!IsWindowKnown(window, &client_window_id)) return; - client()->OnWindowPredefinedCursorChanged(client_window_id.id, cursor_id); + client()->OnWindowCursorChanged(client_window_id.id, cursor); } void WindowTree::ProcessFocusChanged(const ServerWindow* old_focused_window, @@ -1773,19 +1774,45 @@ window->set_event_targeting_policy(policy); } -void WindowTree::SetPredefinedCursor(uint32_t change_id, - Id transport_window_id, - ui::mojom::CursorType cursor_id) { +void WindowTree::SetCursor(uint32_t change_id, + Id transport_window_id, + ui::CursorData cursor) { ServerWindow* window = GetWindowByClientId(ClientWindowId(transport_window_id)); + if (!window) { + DVLOG(1) << "SetCursor failed (invalid id)"; + client()->OnChangeCompleted(change_id, false); + return; + } // Only the owner of the window can change the bounds. - bool success = window && access_policy_->CanSetCursorProperties(window); - if (success) { - Operation op(this, window_server_, - OperationType::SET_WINDOW_PREDEFINED_CURSOR); - window->SetPredefinedCursor(cursor_id); + bool success = access_policy_->CanSetCursorProperties(window); + if (!success) { + DVLOG(1) << "SetCursor failed (access denied)"; + client()->OnChangeCompleted(change_id, false); + return; } + + // If the cursor is custom, it must have valid frames. + if (cursor.cursor_type() == ui::CursorType::kCustom) { + if (cursor.cursor_frames().empty()) { + DVLOG(1) << "SetCursor failed (no frames with custom cursor)"; + client()->OnChangeCompleted(change_id, false); + return; + } + + for (const SkBitmap& bitmap : cursor.cursor_frames()) { + if (bitmap.drawsNothing()) { + DVLOG(1) << "SetCursor failed (cursor frame draws nothing)"; + client()->OnChangeCompleted(change_id, false); + return; + } + } + } + + Operation op(this, window_server_, + OperationType::SET_WINDOW_PREDEFINED_CURSOR); + window->SetCursor(std::move(cursor)); client()->OnChangeCompleted(change_id, success); } @@ -2232,11 +2259,11 @@ } void WindowTree::WmSetNonClientCursor(uint32_t window_id, - mojom::CursorType cursor_id) { + ui::CursorData cursor) { DCHECK(window_manager_state_); ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id)); if (window) { - window->SetNonClientCursor(cursor_id); + window->SetNonClientCursor(std::move(cursor)); } else { DVLOG(1) << "trying to update non-client cursor of invalid window"; }
diff --git a/services/ui/ws/window_tree.h b/services/ui/ws/window_tree.h index 3a2a779..0721fff 100644 --- a/services/ui/ws/window_tree.h +++ b/services/ui/ws/window_tree.h
@@ -261,7 +261,7 @@ float new_opacity, bool originated_change); void ProcessCursorChanged(const ServerWindow* window, - mojom::CursorType cursor_id, + const ui::CursorData& cursor, bool originated_change); void ProcessFocusChanged(const ServerWindow* old_focused_window, const ServerWindow* new_focused_window); @@ -462,9 +462,9 @@ void SetCanFocus(Id transport_window_id, bool can_focus) override; void SetEventTargetingPolicy(Id transport_window_id, mojom::EventTargetingPolicy policy) override; - void SetPredefinedCursor(uint32_t change_id, - Id transport_window_id, - ui::mojom::CursorType cursor_id) override; + void SetCursor(uint32_t change_id, + Id transport_window_id, + ui::CursorData cursor) override; void SetWindowTextInputState(Id transport_window_id, mojo::TextInputStatePtr state) override; void SetImeVisibility(Id transport_window_id, @@ -521,8 +521,7 @@ void WmRequestClose(Id transport_window_id) override; void WmSetFrameDecorationValues( mojom::FrameDecorationValuesPtr values) override; - void WmSetNonClientCursor(uint32_t window_id, - mojom::CursorType cursor_id) override; + void WmSetNonClientCursor(uint32_t window_id, ui::CursorData cursor) override; void OnWmCreatedTopLevelWindow(uint32_t change_id, Id transport_window_id) override; void OnAcceleratorAck(
diff --git a/services/ui/ws/window_tree_client_unittest.cc b/services/ui/ws/window_tree_client_unittest.cc index 602b3b9..d18cb29 100644 --- a/services/ui/ws/window_tree_client_unittest.cc +++ b/services/ui/ws/window_tree_client_unittest.cc
@@ -23,6 +23,7 @@ #include "services/ui/ws/ids.h" #include "services/ui/ws/test_change_tracker.h" #include "services/ui/ws/window_server_service_test_base.h" +#include "ui/base/cursor/cursor.h" using mojo::InterfaceRequest; using service_manager::Service; @@ -236,9 +237,9 @@ return WaitForChangeCompleted(change_id); } - bool SetPredefinedCursor(Id window_id, mojom::CursorType cursor) { + bool SetCursor(Id window_id, const ui::CursorData& cursor) { const uint32_t change_id = GetAndAdvanceChangeId(); - tree()->SetPredefinedCursor(change_id, window_id, cursor); + tree()->SetCursor(change_id, window_id, cursor); return WaitForChangeCompleted(change_id); } @@ -385,9 +386,9 @@ } // TODO(sky): add testing coverage. void OnWindowFocused(uint32_t focused_window_id) override {} - void OnWindowPredefinedCursorChanged(uint32_t window_id, - mojom::CursorType cursor_id) override { - tracker_.OnWindowPredefinedCursorChanged(window_id, cursor_id); + void OnWindowCursorChanged(uint32_t window_id, + ui::CursorData cursor) override { + tracker_.OnWindowCursorChanged(window_id, cursor); } void OnDragDropStart( @@ -1638,11 +1639,11 @@ Id window_1_1 = BuildWindowId(client_id_1(), 1); changes2()->clear(); - ASSERT_TRUE( - wt_client1()->SetPredefinedCursor(window_1_1, mojom::CursorType::kIBeam)); + ASSERT_TRUE(wt_client1()->SetCursor(window_1_1, + ui::CursorData(ui::CursorType::kIBeam))); wt_client2_->WaitForChangeCount(1u); - EXPECT_EQ("CursorChanged id=" + IdToString(window_1_1) + " cursor_id=4", + EXPECT_EQ("CursorChanged id=" + IdToString(window_1_1) + " cursor_type=4", SingleChangeToDescription(*changes2())); }
diff --git a/services/ui/ws/window_tree_unittest.cc b/services/ui/ws/window_tree_unittest.cc index 1d64d28..15a844a 100644 --- a/services/ui/ws/window_tree_unittest.cc +++ b/services/ui/ws/window_tree_unittest.cc
@@ -31,6 +31,7 @@ #include "services/ui/ws/window_server_delegate.h" #include "services/ui/ws/window_tree_binding.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/cursor/cursor.h" #include "ui/events/event.h" #include "ui/events/event_utils.h" #include "ui/gfx/geometry/rect.h" @@ -129,8 +130,8 @@ WindowTreeTest() {} ~WindowTreeTest() override {} - ui::mojom::CursorType cursor_id() { - return window_event_targeting_helper_.cursor(); + ui::CursorType cursor_type() { + return window_event_targeting_helper_.cursor_type(); } Display* display() { return window_event_targeting_helper_.display(); } TestWindowTreeClient* last_window_tree_client() { @@ -475,11 +476,11 @@ DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22)); // Set the cursor on the parent as that is where the cursor is picked up from. - window->parent()->SetPredefinedCursor(mojom::CursorType::kIBeam); + window->parent()->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); // Because the cursor is over the window when SetCursor was called, we should // have immediately changed the cursor. - EXPECT_EQ(mojom::CursorType::kIBeam, cursor_id()); + EXPECT_EQ(ui::CursorType::kIBeam, cursor_type()); } TEST_F(WindowTreeTest, CursorChangesWhenEnteringWindowWithDifferentCursor) { @@ -492,11 +493,11 @@ // inside. DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); // Set the cursor on the parent as that is where the cursor is picked up from. - window->parent()->SetPredefinedCursor(mojom::CursorType::kIBeam); - EXPECT_EQ(mojom::CursorType::kPointer, cursor_id()); + window->parent()->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + EXPECT_EQ(ui::CursorType::kPointer, cursor_type()); DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22)); - EXPECT_EQ(mojom::CursorType::kIBeam, cursor_id()); + EXPECT_EQ(ui::CursorType::kIBeam, cursor_type()); } TEST_F(WindowTreeTest, TouchesDontChangeCursor) { @@ -508,12 +509,12 @@ // Let's create a pointer event outside the window and then move the pointer // inside. DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); - window->SetPredefinedCursor(mojom::CursorType::kIBeam); - EXPECT_EQ(mojom::CursorType::kPointer, cursor_id()); + window->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + EXPECT_EQ(ui::CursorType::kPointer, cursor_type()); // With a touch event, we shouldn't update the cursor. DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22)); - EXPECT_EQ(mojom::CursorType::kPointer, cursor_id()); + EXPECT_EQ(ui::CursorType::kPointer, cursor_type()); } TEST_F(WindowTreeTest, DragOutsideWindow) { @@ -526,25 +527,25 @@ // change the cursor. DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); // Set the cursor on the parent as that is where the cursor is picked up from. - window->parent()->SetPredefinedCursor(mojom::CursorType::kIBeam); - EXPECT_EQ(mojom::CursorType::kPointer, cursor_id()); + window->parent()->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + EXPECT_EQ(ui::CursorType::kPointer, cursor_type()); // Move the pointer to the inside of the window DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22)); - EXPECT_EQ(mojom::CursorType::kIBeam, cursor_id()); + EXPECT_EQ(ui::CursorType::kIBeam, cursor_type()); // Start the drag. DispatchEventAndAckImmediately(CreateMouseDownEvent(21, 22)); - EXPECT_EQ(mojom::CursorType::kIBeam, cursor_id()); + EXPECT_EQ(ui::CursorType::kIBeam, cursor_type()); // Move the cursor (mouse is still down) outside the window. DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); - EXPECT_EQ(mojom::CursorType::kIBeam, cursor_id()); + EXPECT_EQ(ui::CursorType::kIBeam, cursor_type()); // Release the cursor. We should now adapt the cursor of the window // underneath the pointer. DispatchEventAndAckImmediately(CreateMouseUpEvent(5, 5)); - EXPECT_EQ(mojom::CursorType::kPointer, cursor_id()); + EXPECT_EQ(ui::CursorType::kPointer, cursor_type()); } TEST_F(WindowTreeTest, ChangingWindowBoundsChangesCursor) { @@ -556,17 +557,17 @@ // Put the cursor just outside the bounds of the window. DispatchEventAndAckImmediately(CreateMouseMoveEvent(41, 41)); // Sets the cursor on the root as that is where the cursor is picked up from. - window->parent()->SetPredefinedCursor(mojom::CursorType::kIBeam); - EXPECT_EQ(mojom::CursorType::kPointer, cursor_id()); + window->parent()->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + EXPECT_EQ(ui::CursorType::kPointer, cursor_type()); // Expand the bounds of the window so they now include where the cursor now // is. window->SetBounds(gfx::Rect(20, 20, 25, 25)); - EXPECT_EQ(mojom::CursorType::kIBeam, cursor_id()); + EXPECT_EQ(ui::CursorType::kIBeam, cursor_type()); // Contract the bounds again. window->SetBounds(gfx::Rect(20, 20, 20, 20)); - EXPECT_EQ(mojom::CursorType::kPointer, cursor_id()); + EXPECT_EQ(ui::CursorType::kPointer, cursor_type()); } TEST_F(WindowTreeTest, WindowReorderingChangesCursor) { @@ -583,14 +584,14 @@ mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); embed_window2->set_event_targeting_policy( mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); - embed_window1->SetPredefinedCursor(mojom::CursorType::kIBeam); - embed_window2->SetPredefinedCursor(mojom::CursorType::kCross); + embed_window1->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + embed_window2->SetCursor(ui::CursorData(ui::CursorType::kCross)); DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); // Cursor should match that of top-most window, which is |embed_window2|. - EXPECT_EQ(mojom::CursorType::kCross, cursor_id()); + EXPECT_EQ(ui::CursorType::kCross, cursor_type()); // Move |embed_window1| on top, cursor should now match it. embed_window1->parent()->StackChildAtTop(embed_window1); - EXPECT_EQ(mojom::CursorType::kIBeam, cursor_id()); + EXPECT_EQ(ui::CursorType::kIBeam, cursor_type()); } // Assertions around moving cursor between trees with roots. @@ -608,9 +609,9 @@ mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); embed_window2->parent()->set_event_targeting_policy( mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); - embed_window1->SetPredefinedCursor(mojom::CursorType::kIBeam); - embed_window2->SetPredefinedCursor(mojom::CursorType::kCross); - embed_window1->parent()->SetPredefinedCursor(mojom::CursorType::kCopy); + embed_window1->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + embed_window2->SetCursor(ui::CursorData(ui::CursorType::kCross)); + embed_window1->parent()->SetCursor(ui::CursorData(ui::CursorType::kCopy)); // Create a child of |embed_window1|. ServerWindow* embed_window1_child = NewWindowInTreeWithParent( @@ -621,15 +622,15 @@ // Move mouse into |embed_window1|. DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5)); - EXPECT_EQ(mojom::CursorType::kIBeam, cursor_id()); + EXPECT_EQ(ui::CursorType::kIBeam, cursor_type()); // Move mouse into |embed_window2|. DispatchEventAndAckImmediately(CreateMouseMoveEvent(25, 25)); - EXPECT_EQ(mojom::CursorType::kCross, cursor_id()); + EXPECT_EQ(ui::CursorType::kCross, cursor_type()); // Move mouse into area between, which should use cursor set on parent. DispatchEventAndAckImmediately(CreateMouseMoveEvent(15, 15)); - EXPECT_EQ(mojom::CursorType::kCopy, cursor_id()); + EXPECT_EQ(ui::CursorType::kCopy, cursor_type()); } TEST_F(WindowTreeTest, EventAck) {
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 8fd5e78..b9dd2c71 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -273,20 +273,11 @@ # LayoutNG - is a new layout system for Blink. ### external/wpt/css/CSS2/floats-clear -#### Passed: 50 26% -#### Skipped: 141 +#### Passed: 52 29% +#### Skipped: 139 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/adjacent-floats-001.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-007.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-008.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-009.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-non-replaced-height-001.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-height-004.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-height-007.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-003.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-123.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-002.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-005.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-applies-to-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-applies-to-002.xht [ Skip ] @@ -300,12 +291,14 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-applies-to-012.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-applies-to-013.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-applies-to-015.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-004.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-005.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-006.xht [ Skip ] +crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-007.xht [ Skip ] +crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-008.xht [ Skip ] +crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/clear-float-009.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-006.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-applies-to-001.xht [ Skip ] @@ -324,6 +317,7 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-applies-to-013.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-applies-to-014.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-applies-to-015.xht [ Skip ] +crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-non-replaced-height-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-non-replaced-width-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-non-replaced-width-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-non-replaced-width-003.xht [ Skip ] @@ -336,7 +330,9 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-height-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-height-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-height-003.xht [ Skip ] +crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-height-004.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-height-006.xht [ Skip ] +crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-height-007.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-width-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-width-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-width-003.xht [ Skip ] @@ -350,6 +346,7 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floating-replaced-height-008.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-002.xht [ Skip ] +crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-004.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-005.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-006.xht [ Skip ] @@ -376,6 +373,7 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-113.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-117.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-120.xht [ Skip ] +crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-123.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-126.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-127.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-128.xht [ Skip ] @@ -418,8 +416,8 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-clear-015.xht [ Skip ] ### external/wpt/css/CSS2/floats -#### Passed: 17 40% -#### Skipped: 25 +#### Passed: 19 48% +#### Skipped: 23 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-placement-vertical-001a.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-placement-vertical-001b.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-placement-vertical-001c.xht [ Skip ] @@ -435,8 +433,6 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-bfc-007.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-001l.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-001r.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-002l.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-002r.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-003l.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-003r.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-inline-001l.xht [ Skip ] @@ -447,8 +443,8 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-inline-003r.xht [ Skip ] ### external/wpt/css/CSS2/positioning -#### Passed: 263 50% -#### Skipped: 260 +#### Passed: 278 53% +#### Skipped: 245 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-non-replaced-height-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-non-replaced-height-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/absolute-non-replaced-height-004.xht [ Skip ] @@ -561,14 +557,10 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/bottom-applies-to-013.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/bottom-applies-to-014.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/bottom-applies-to-015.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/bottom-offset-001.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/bottom-offset-002.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/bottom-offset-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/bottom-offset-percentage-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/left-applies-to-009.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/left-applies-to-012.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/left-offset-001.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/left-offset-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/left-offset-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/left-offset-percentage-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-004.xht [ Skip ] @@ -592,15 +584,9 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-fixed-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-fixed-004.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-fixed-005.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-fixed-007.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-003.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-004.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-014.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-015.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-016.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-017.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-019.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-020.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-021.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-022.xht [ Skip ] @@ -682,8 +668,6 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/right-applies-to-013.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/right-applies-to-014.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/right-applies-to-015.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/right-offset-001.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/right-offset-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/right-offset-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/right-offset-percentage-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-007.xht [ Skip ] @@ -705,9 +689,6 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-103.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-104.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-113.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-offset-001.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-offset-002.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-offset-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-offset-percentage-001.xht [ Skip ] #### external/wpt/css/CSS2/abspos @@ -718,8 +699,8 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/abspos/abspos-containing-block-initial-009a.xht [ Skip ] #### external/wpt/css/CSS2/normal-flow -#### Passed: 430 61% -#### Skipped: 278 +#### Passed: 492 70% +#### Skipped: 216 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-formatting-context-height-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-formatting-context-height-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-formatting-contexts-008.xht [ Skip ] @@ -797,32 +778,24 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-004.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-005.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-non-replaced-height-002.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-height-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-height-006.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-height-008.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-height-009.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-width-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-width-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-width-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-width-006.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-width-007.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-width-008.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-valign-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-zorder-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-non-replaced-height-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-non-replaced-height-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-non-replaced-width-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-non-replaced-width-002.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-height-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-height-006.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-height-008.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-height-009.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-003.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-006.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-008.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-009.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-011.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-012.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-013.xht [ Skip ] @@ -877,26 +850,8 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-height-applies-to-012.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-height-percentage-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-height-percentage-003.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-006.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-007.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-017.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-018.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-028.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-029.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-039.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-040.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-050.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-051.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-061.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-062.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-072.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-073.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-083.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-084.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-094.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-095.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-106.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-110.xht [ Skip ] +crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-110.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-applies-to-005.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-applies-to-006.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-width-applies-to-008.xht [ Skip ] @@ -950,24 +905,6 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-height-104.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-height-106.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-height-applies-to-012.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-006.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-007.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-017.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-018.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-028.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-029.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-039.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-040.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-050.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-051.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-061.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-062.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-072.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-073.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-083.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-084.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-094.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-095.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-applies-to-005.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-applies-to-006.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/min-width-applies-to-008.xht [ Skip ] @@ -977,24 +914,6 @@ crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/replaced-intrinsic-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/replaced-intrinsic-002.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/root-box-001.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-006.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-007.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-017.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-018.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-028.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-029.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-039.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-040.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-050.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-051.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-061.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-062.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-072.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-073.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-083.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-084.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-094.xht [ Skip ] -crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-095.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-applies-to-012.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-inherit-001.xht [ Skip ] crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-percentage-001.xht [ Skip ] @@ -2415,9 +2334,18 @@ # This test fails with the stable release mode. crbug.com/694958 virtual/stable/http/tests/navigation/same-and-different-back.html [ Skip ] -# These tests have console error messages whose order is not deterministic. -crbug.com/679742 external/wpt/html/semantics/scripting-1/the-script-element/module/crossorigin.html [ Pass Failure ] -crbug.com/679742 external/wpt/html/semantics/scripting-1/the-script-element/module/errorhandling.html [ Pass Failure ] +# Failing because of module-related implementation/test issues and +# lack of inline module script support. +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/crossorigin.html [ Failure ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/errorhandling.html [ Failure ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/imports.html [ Failure Crash ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/execorder.html [ Failure Timeout ] +crbug.com/594639 external/wpt/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html [ Failure Crash ] + +# Inline module scripts are not yet supported. +crbug.com/715369 external/wpt/html/semantics/scripting-1/the-script-element/nomodule-set-on-inline-module-script.html [ Failure ] +crbug.com/715369 fast/dom/HTMLScriptElement/module-script.html [ Failure ] +crbug.com/715369 virtual/sharedarraybuffer/fast/dom/HTMLScriptElement/module-script.html [ Failure ] # This test has a failure console message with specific performance # numbers so a consistent baseline cannot be added. This test could be @@ -2709,7 +2637,6 @@ crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_with_class_object_specific_selector.html [ Failure ] crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/default_styles/inherit_as_default_value_inherits_values_from_media_element.html [ Failure ] crbug.com/626703 external/wpt/pointerevents/pointerevent_click_during_capture-manual.html [ Timeout ] -crbug.com/626703 [ Linux ] external/wpt/html/semantics/scripting-1/the-script-element/module/execorder.html [ Timeout ] crbug.com/626703 external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/allow-crossorigin.html [ Timeout ] crbug.com/626703 external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html [ Timeout ] crbug.com/626703 external/wpt/html/webappapis/idle-callbacks/cancel-invoked.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/execorder-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/execorder-expected.txt deleted file mode 100644 index 486dfeb..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/execorder-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -This is a testharness.js-based test. -PASS Unordered module script execution (parsed, unordered #1) -PASS Unordered module script execution (parsed, unordered #2) -PASS Unordered module script execution (dynamic, unordered #1) -PASS Unordered module script execution (dynamic, unordered #2) -FAIL Interlaced module/non-module script execution (parsed, async-ordered) assert_equals: Inline module-typed script element should have fired third expected 3 but got 1 -PASS Interlaced module/non-module script execution (dynamic, async-ordered) -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/imports-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/imports-expected.txt deleted file mode 100644 index 871ee18..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/imports-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL html-script-module-imports Uncaught SyntaxError: Unexpected token import -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/nomodule-set-on-external-module-script-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/nomodule-set-on-external-module-script-expected.txt deleted file mode 100644 index d7a598e..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/nomodule-set-on-external-module-script-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL An external module script with nomodule must run Uncaught SyntaxError: Unexpected token import -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/nomodule-set-on-inline-module-script-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/nomodule-set-on-inline-module-script-expected.txt deleted file mode 100644 index 5629f50..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/nomodule-set-on-inline-module-script-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL An inline module script with nomodule must run Uncaught SyntaxError: Unexpected token import -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https-expected.txt index 3f3e688..9eed3f6 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/interfaces.https-expected.txt
@@ -7,7 +7,7 @@ PASS PaymentRequest interface: operation show() PASS PaymentRequest interface: operation abort() PASS PaymentRequest interface: operation canMakePayment() -FAIL PaymentRequest interface: attribute id assert_true: The prototype object must have a property "id" expected true got false +PASS PaymentRequest interface: attribute id PASS PaymentRequest interface: attribute shippingAddress PASS PaymentRequest interface: attribute shippingOption PASS PaymentRequest interface: attribute shippingType @@ -18,7 +18,7 @@ PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "show" with the proper type (0) PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "abort" with the proper type (1) PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "canMakePayment" with the proper type (2) -FAIL PaymentRequest interface: new PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "id" with the proper type (3) assert_inherits: property "id" not found in prototype chain +PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "id" with the proper type (3) PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "shippingAddress" with the proper type (4) PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "shippingOption" with the proper type (5) PASS PaymentRequest interface: new PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'bar', amount: {currency: 'BAZ', value: '0'}}}) must inherit property "shippingType" with the proper type (6) @@ -45,7 +45,7 @@ PASS PaymentResponse interface object name FAIL PaymentResponse interface: existence and properties of interface prototype object assert_equals: class string of PaymentResponse.prototype expected "[object PaymentResponsePrototype]" but got "[object PaymentResponse]" PASS PaymentResponse interface: existence and properties of interface prototype object's "constructor" property -FAIL PaymentResponse interface: attribute requestId assert_true: The prototype object must have a property "requestId" expected true got false +PASS PaymentResponse interface: attribute requestId PASS PaymentResponse interface: attribute methodName PASS PaymentResponse interface: attribute details PASS PaymentResponse interface: attribute shippingAddress
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id.https.html new file mode 100644 index 0000000..8e3c3446 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-id.https.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<!-- Copyright © 2017 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). --> +<meta charset="utf-8"> +<title>Test for PaymentRequest identifier usage</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<iframe id="iframe" allowpaymentrequest></iframe> +<script> +async_test((t) => { + onload = t.step_func_done(() => { + var request = new window[0].PaymentRequest([{supportedMethods: ['foo']}], {id: 'my_payment_id', total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}); + assert_equals(request.id, 'my_payment_id', 'Payment identifier is not reflected correctly in PaymentRequest.id'); + + request = new window[0].PaymentRequest([{supportedMethods: ['foo']}], {total: {label: 'label', amount: {currency: 'USD', value: '5.00'}}}); + assert_equals(request.id.length, 36, 'Generated payment identifier is not of correct length.'); + }); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-response-id.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-response-id.html new file mode 100644 index 0000000..3fd6bd1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-response-id.html
@@ -0,0 +1,140 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>PaymentRequest identifier manual test</title> +</head> +<body> + <div id="contents"> + <h1>PaymentRequest identifier manual test</h1> + <p>Perform the following steps:</p> + <ul> + <li>Press 'Buy'</li> + <li>In the payment dialog make sure a payment app is selected</li> + <li>In the payment dialog press 'Pay'</li> + <li>In the launched payment app perform steps to do the payment</li> + <li>The response will be processed and below should display 'my_payment_id'</li> + </ul> + <p>No payment will be processed.</p> + <p>Price: USD <strong>$55.00</strong></p> + <p><button onclick="onBuyClicked()">Buy</button></p> + </div> + <pre id="msg"></pre> + <script> + /** + * Initializes the payment request object. + * @return {PaymentRequest} The payment request object. + */ + function buildPaymentRequest() { + if (!window.PaymentRequest) { + return null; + } + + const supportedInstruments = [{ + supportedMethods: ['https://android.com/pay'], + data: { + merchantName: 'Rouslan Solomakhin', + merchantId: '00184145120947117657', + allowedCardNetworks: ['AMEX', 'MASTERCARD', 'VISA', 'DISCOVER'], + paymentMethodTokenizationParameters: { + tokenizationType: 'GATEWAY_TOKEN', + parameters: { + 'gateway': 'stripe', + 'stripe:publishableKey': 'pk_live_lNk21zqKM2BENZENh3rzCUgo', + 'stripe:version': '2016-07-06', + }, + }, + }, + }, { + supportedMethods: ['basic-card'], + data: { + supportedNetworks: ['unionpay', 'visa', 'mastercard', 'amex', 'discover', + 'diners', 'jcb', 'mir', + ], + supportedTypes: ['prepaid', 'debit', 'credit'], + }, + }]; + + const details = { + id: 'my_payment_id', + total: { + label: 'Donation', + amount: { + currency: 'USD', + value: '55.00', + }, + }, + displayItems: [{ + label: 'Original donation amount', + amount: { + currency: 'USD', + value: '65.00', + }, + }, { + label: 'Friends and family discount', + amount: { + currency: 'USD', + value: '-10.00', + }, + }], + }; + + let request = null; + + try { + request = new PaymentRequest(supportedInstruments, details); + if (request.canMakePayment) { + request.canMakePayment().then(function(result) { + console.log(result ? 'Can make payment' : 'Cannot make payment'); + }).catch(function(err) { + console.log(err); + }); + } + } catch (e) { + console.log('Developer mistake: \'' + e + '\''); + } + + return request; + } + + let request = buildPaymentRequest(); + + /** + * Launches payment request that does not require shipping. + */ + function onBuyClicked() { // eslint-disable-line no-unused-vars + if (!window.PaymentRequest || !request) { + console.log('PaymentRequest API is not supported.'); + return; + } + + try { + request.show() + .then(function(instrumentResponse) { + window.setTimeout(function() { + instrumentResponse.complete('success') + .then(function() { + let element = document.createElement('pre'); + element.innerHTML = instrumentResponse.requestId; + document.getElementById('msg').appendChild(element); + }) + .catch(function(err) { + console.log(err); + request = buildPaymentRequest(); + }); + }, 2000); + }) + .catch(function(err) { + console.log(err); + request = buildPaymentRequest(); + }); + } catch (e) { + console.log('Developer mistake: \'' + e + '\''); + request = buildPaymentRequest(); + } + } + </script> +</body> +</html> +
diff --git a/third_party/WebKit/LayoutTests/inspector/components/parsed-url-expected.txt b/third_party/WebKit/LayoutTests/inspector/components/parsed-url-expected.txt index 5d02f96d..076f2cc 100644 --- a/third_party/WebKit/LayoutTests/inspector/components/parsed-url-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/components/parsed-url-expected.txt
@@ -150,4 +150,32 @@ fragment: undefined folderPathComponents: /foo/bar//// lastPathComponent: baz.html +Splitting url: http://www.chromium.org + URL: http://www.chromium.org + Line: undefined + Column: undefined +Splitting url: http://www.chromium.org:8000 + URL: http://www.chromium.org:8000 + Line: undefined + Column: undefined +Splitting url: http://www.chromium.org:8000/ + URL: http://www.chromium.org:8000/ + Line: undefined + Column: undefined +Splitting url: http://www.chromium.org:8000/foo.js:10 + URL: http://www.chromium.org:8000/foo.js + Line: 9 + Column: undefined +Splitting url: http://www.chromium.org:8000/foo.js:10:20 + URL: http://www.chromium.org:8000/foo.js + Line: 9 + Column: 19 +Splitting url: http://www.chromium.org/foo.js:10 + URL: http://www.chromium.org/foo.js + Line: 9 + Column: undefined +Splitting url: http://www.chromium.org/foo.js:10:20 + URL: http://www.chromium.org/foo.js + Line: 9 + Column: 19
diff --git a/third_party/WebKit/LayoutTests/inspector/components/parsed-url.html b/third_party/WebKit/LayoutTests/inspector/components/parsed-url.html index 57098bd..d539d41 100644 --- a/third_party/WebKit/LayoutTests/inspector/components/parsed-url.html +++ b/third_party/WebKit/LayoutTests/inspector/components/parsed-url.html
@@ -39,6 +39,23 @@ parseAndDumpURL("http://example.com/foo////bar/baz.html"); parseAndDumpURL("http://example.com/foo/bar/////baz.html"); + function testSplitLineColumn(url) { + var result = Common.ParsedURL.splitLineAndColumn(url); + + InspectorTest.addResult("Splitting url: " + url); + InspectorTest.addResult(" URL: " + result.url); + InspectorTest.addResult(" Line: " + result.lineNumber); + InspectorTest.addResult(" Column: " + result.columnNumber); + } + + testSplitLineColumn("http://www.chromium.org"); + testSplitLineColumn("http://www.chromium.org:8000"); + testSplitLineColumn("http://www.chromium.org:8000/"); + testSplitLineColumn("http://www.chromium.org:8000/foo.js:10"); + testSplitLineColumn("http://www.chromium.org:8000/foo.js:10:20"); + testSplitLineColumn("http://www.chromium.org/foo.js:10"); + testSplitLineColumn("http://www.chromium.org/foo.js:10:20"); + InspectorTest.completeTest(); }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2-expected.png b/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2-expected.png index c781870..a7fe526 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2-expected.png +++ b/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2.html b/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2.html index aa972a0a..51020a7 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/border-radius-repaint-2.html
@@ -3,13 +3,11 @@ <head> <title>Repaint test for crbug.com/222851</title> <script src="resources/text-based-repaint.js" type="text/javascript"></script> +<style> +/* Avoid the noise caused by change of scrollbar existence. */ +html { overflow: hidden; } +</style> <script> -if (window.internals) { - // Avoid the noise caused by change of scrollbar existence. - internals.settings.setOverlayScrollbarsEnabled(true); - internals.settings.setMockScrollbarsEnabled(true); -} - function repaintTest() { document.getElementById('target').style.height = '2px'; } @@ -17,12 +15,12 @@ </head> <body style="background-color: #3F3F3F;" onload="runRepaintAndPixelTest()"> <div style="border-radius: 150px; background-color: #EFEFEF; width: 90%; padding: 5em; margin: 0 auto;"> - <div style="border-radius: 5px; border: solid 3px #367CAF; width: 85%; margin: 0 auto;"> - <div class="notARealClass" style="background-color: #367CAF; height: 3em; cursor: pointer;"> - </div> - <div id="target" style="width: 100%; height: 550px;"> - </div> - </div> + <div style="border-radius: 5px; border: solid 3px #367CAF; width: 85%; margin: 0 auto;"> + <div class="notARealClass" style="background-color: #367CAF; height: 3em; cursor: pointer;"> + </div> + <div id="target" style="width: 100%; height: 550px;"> + </div> + </div> </div> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change1-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change1-expected.html index 9c01bec..847bad9 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change1-expected.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change1-expected.html
@@ -1,9 +1,6 @@ <!DOCTYPE html> -<script> -if (window.internals) { - internals.settings.setOverlayScrollbarsEnabled(true); - internals.settings.setMockScrollbarsEnabled(true); -} -</script> +<style> + html { overflow: hidden; } +</style> <div style="width: 2000px; height: 2000px; background-color: blue"> </div>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change1.html b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change1.html index 3fd9ae72..fb0dac1 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change1.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change1.html
@@ -1,10 +1,7 @@ <!DOCTYPE html> <script src="resources/window-resize-repaint.js"></script> -<script> -if (window.internals) { - internals.settings.setOverlayScrollbarsEnabled(true); - internals.settings.setMockScrollbarsEnabled(true); -} -</script> +<style> + html { overflow: hidden; } +</style> <div style="width: 2000px; height: 2000px; background-color: blue"> </div>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change2-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change2-expected.html index f8b1995..ba4be0f 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change2-expected.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change2-expected.html
@@ -1,10 +1,7 @@ <!DOCTYPE html> -<script> -if (window.internals) { - internals.settings.setOverlayScrollbarsEnabled(true); - internals.settings.setMockScrollbarsEnabled(true); -} -</script> +<style> + html { overflow: hidden; } +</style> <div style="position: absolute; width: 2000px; height: 2000px; background-color: blue"> <div style="width: 20%; height: 20%; background-color: yellow"> </div>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change2.html b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change2.html index f8ae3a8..76c2a2ed 100644 --- a/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change2.html +++ b/third_party/WebKit/LayoutTests/paint/invalidation/window-resize-no-layout-change2.html
@@ -1,11 +1,8 @@ <!DOCTYPE html> <script src="resources/window-resize-repaint.js"></script> -<script> -if (window.internals) { - internals.settings.setOverlayScrollbarsEnabled(true); - internals.settings.setMockScrollbarsEnabled(true); -} -</script> +<style> + html { overflow: hidden; } +</style> <div style="position: absolute; width: 2000px; height: 2000px; background-color: blue"> <div style="width: 20%; height: 20%; background-color: yellow"> </div>
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt index 0e745ff..d9e555b 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -4716,6 +4716,7 @@ method setManifest interface PaymentRequest : EventTarget attribute @@toStringTag + getter id getter onshippingaddresschange getter onshippingoptionchange getter shippingAddress @@ -4738,6 +4739,7 @@ getter payerEmail getter payerName getter payerPhone + getter requestId getter shippingAddress getter shippingOption method complete
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index 7b8356f..9865784 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4723,6 +4723,7 @@ method setManifest interface PaymentRequest : EventTarget attribute @@toStringTag + getter id getter onshippingaddresschange getter onshippingoptionchange getter shippingAddress @@ -4745,6 +4746,7 @@ getter payerEmail getter payerName getter payerPhone + getter requestId getter shippingAddress getter shippingOption method complete
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 index e32263e0..68e408a 100644 --- a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 +++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -40,7 +40,6 @@ "table-footer-group", "table-row", "table-column-group", "table-column", "table-cell", "table-caption", "-webkit-box", "-webkit-inline-box", "flex", "inline-flex", "grid", "inline-grid", "contents", "flow-root", "none", ], - has_custom_compare_and_copy: true, }, { name: "InsideLink", @@ -154,15 +153,14 @@ has_custom_compare_and_copy: true, }, // TODO(shend): vertical align is actually a CSS property, but since we don't support union fields - // which can be either a keyword or Length, this is generated as a nonproperty for now. Remove this - // once we can support union fields and groups. + // which can be either a keyword or Length, this is specified in this file for now. Remove this + // once we can support union fields. { name: "VerticalAlign", field_template: "storage_only", field_size: 4, default_value: "EVerticalAlign::kBaseline", type_name: "EVerticalAlign", - has_custom_compare_and_copy: true, }, { name: "border",
diff --git a/third_party/WebKit/Source/core/dom/ModuleMapTest.cpp b/third_party/WebKit/Source/core/dom/ModuleMapTest.cpp index eb3f00f3..b29ebec4 100644 --- a/third_party/WebKit/Source/core/dom/ModuleMapTest.cpp +++ b/third_party/WebKit/Source/core/dom/ModuleMapTest.cpp
@@ -131,7 +131,7 @@ void ModuleMapTestModulator::ResolveFetches() { for (const auto& test_request : test_requests_) { - ModuleScript* module_script = ModuleScript::Create( + ModuleScript* module_script = ModuleScript::CreateForTest( this, ScriptModule(), test_request->url, test_request->nonce, kParserInserted, WebURLRequest::kFetchCredentialsModeOmit); TaskRunner()->PostTask(
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.cpp b/third_party/WebKit/Source/core/dom/ModuleScript.cpp index a0f6a396..6ad54434 100644 --- a/third_party/WebKit/Source/core/dom/ModuleScript.cpp +++ b/third_party/WebKit/Source/core/dom/ModuleScript.cpp
@@ -10,6 +10,37 @@ namespace blink { +ModuleScript* ModuleScript::Create( + const String& source_text, + Modulator* modulator, + const KURL& base_url, + const String& nonce, + ParserDisposition parser_state, + WebURLRequest::FetchCredentialsMode credentials_mode, + AccessControlStatus access_control_status) { + // Step 1. Let script be a new module script that this algorithm will + // subsequently initialize. + // Step 2. Set script's settings object to the environment settings object + // provided. + // Note: "script's settings object" will be "modulator". + + // Delegate to Modulator::compileModule to process Steps 3-6. + ScriptModule result = modulator->CompileModule( + source_text, base_url.GetString(), access_control_status); + // Step 6: "...return null, and abort these steps." + if (result.IsNull()) + return nullptr; + // Step 7. Set script's module record to result. + // Step 8. Set script's base URL to the script base URL provided. + // Step 9. Set script's cryptographic nonce to the cryptographic nonce + // provided. + // Step 10. Set script's parser state to the parser state. + // Step 11. Set script's credentials mode to the credentials mode provided. + // Step 12. Return script. + return new ModuleScript(modulator, result, base_url, nonce, parser_state, + credentials_mode); +} + void ModuleScript::SetInstantiationErrorAndClearRecord(ScriptValue error) { // Implements Step 7.1 of: // https://html.spec.whatwg.org/multipage/webappapis.html#internal-module-script-graph-fetching-procedure
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.h b/third_party/WebKit/Source/core/dom/ModuleScript.h index df85c45..5ac8f9f 100644 --- a/third_party/WebKit/Source/core/dom/ModuleScript.h +++ b/third_party/WebKit/Source/core/dom/ModuleScript.h
@@ -30,7 +30,16 @@ // https://html.spec.whatwg.org/multipage/webappapis.html#module-script class CORE_EXPORT ModuleScript final : public Script, public TraceWrapperBase { public: - static ModuleScript* Create( + // https://html.spec.whatwg.org/#creating-a-module-script + static ModuleScript* Create(const String& source_text, + Modulator*, + const KURL& base_url, + const String& nonce, + ParserDisposition, + WebURLRequest::FetchCredentialsMode, + AccessControlStatus); + + static ModuleScript* CreateForTest( Modulator* settings_object, ScriptModule record, const KURL& base_url,
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp index fb70a86..31c1d93 100644 --- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -26,6 +26,7 @@ #include "bindings/core/v8/ScriptController.h" #include "bindings/core/v8/ScriptSourceCode.h" +#include "bindings/core/v8/V8BindingForCore.h" #include "core/HTMLNames.h" #include "core/SVGNames.h" #include "core/dom/ClassicPendingScript.h" @@ -34,6 +35,8 @@ #include "core/dom/DocumentParserTiming.h" #include "core/dom/DocumentWriteIntervention.h" #include "core/dom/IgnoreDestructiveWriteCountIncrementer.h" +#include "core/dom/Modulator.h" +#include "core/dom/ModulePendingScript.h" #include "core/dom/Script.h" #include "core/dom/ScriptElementBase.h" #include "core/dom/ScriptRunner.h" @@ -45,6 +48,8 @@ #include "core/frame/csp/ContentSecurityPolicy.h" #include "core/html/imports/HTMLImport.h" #include "core/html/parser/HTMLParserIdioms.h" +#include "core/inspector/ConsoleMessage.h" +#include "core/loader/modulescript/ModuleScriptFetchRequest.h" #include "core/loader/resource/ScriptResource.h" #include "platform/WebFrameScheduler.h" #include "platform/loader/fetch/AccessControlStatus.h" @@ -107,6 +112,7 @@ visitor->Trace(element_); visitor->Trace(resource_); visitor->Trace(pending_script_); + visitor->Trace(module_tree_client_); PendingScriptClient::Trace(visitor); } @@ -315,7 +321,7 @@ CrossOriginAttributeValue cross_origin = GetCrossOriginAttributeValue(element_->CrossOriginAttributeValue()); - // 16. will be handled below once module script support is implemented. + // 16. is handled below. // 17. "If the script element has a nonce attribute, // then let cryptographic nonce be that attribute's value. @@ -364,51 +370,82 @@ } DCHECK(!resource_); + DCHECK(!module_tree_client_); // 21.6. "Switch on the script's type:" - // - "classic": + if (GetScriptType() == ScriptType::kClassic) { + // - "classic": - // 14. "If the script element has a charset attribute, - // then let encoding be the result of - // getting an encoding from the value of the charset attribute." - // "If the script element does not have a charset attribute, - // or if getting an encoding failed, let encoding - // be the same as the encoding of the script element's node - // document." - // TODO(hiroshige): Should we handle failure in getting an encoding? - String encoding; - if (!element_->CharsetAttributeValue().IsEmpty()) - encoding = element_->CharsetAttributeValue(); - else - encoding = element_document.characterSet(); + // 14. "If the script element has a charset attribute, + // then let encoding be the result of + // getting an encoding from the value of the charset attribute." + // "If the script element does not have a charset attribute, + // or if getting an encoding failed, let encoding + // be the same as the encoding of the script element's node + // document." + // TODO(hiroshige): Should we handle failure in getting an encoding? + String encoding; + if (!element_->CharsetAttributeValue().IsEmpty()) + encoding = element_->CharsetAttributeValue(); + else + encoding = element_document.characterSet(); - // Step 16 is skipped because "module script credentials" is not used - // for classic scripts. + // Step 16 is skipped because "module script credentials" is not used + // for classic scripts. - // 18. "If the script element has an integrity attribute, - // then let integrity metadata be that attribute's value. - // Otherwise, let integrity metadata be the empty string." - String integrity_attr = element_->IntegrityAttributeValue(); - IntegrityMetadataSet integrity_metadata; - if (!integrity_attr.IsEmpty()) { - SubresourceIntegrity::ParseIntegrityAttribute( - integrity_attr, integrity_metadata, &element_document); + // 18. "If the script element has an integrity attribute, + // then let integrity metadata be that attribute's value. + // Otherwise, let integrity metadata be the empty string." + String integrity_attr = element_->IntegrityAttributeValue(); + IntegrityMetadataSet integrity_metadata; + if (!integrity_attr.IsEmpty()) { + SubresourceIntegrity::ParseIntegrityAttribute( + integrity_attr, integrity_metadata, &element_document); + } + + if (!FetchClassicScript(url, element_document.Fetcher(), nonce, + integrity_metadata, parser_state, cross_origin, + element_document.GetSecurityOrigin(), encoding)) { + // TODO(hiroshige): Make this asynchronous. Currently we fire the error + // event synchronously to keep the existing behavior. + DispatchErrorEvent(); + return false; + } + + DCHECK(resource_); + DCHECK(!module_tree_client_); + } else { + // - "module": + + // Steps 14 and 18 are skipped because they are not used in module + // scripts. + + // 16. "Let module script credentials mode be determined by switching + // on CORS setting:" + WebURLRequest::FetchCredentialsMode credentials_mode = + WebURLRequest::kFetchCredentialsModeOmit; + switch (cross_origin) { + case kCrossOriginAttributeNotSet: + credentials_mode = WebURLRequest::kFetchCredentialsModeOmit; + break; + case kCrossOriginAttributeAnonymous: + credentials_mode = WebURLRequest::kFetchCredentialsModeSameOrigin; + break; + case kCrossOriginAttributeUseCredentials: + credentials_mode = WebURLRequest::kFetchCredentialsModeInclude; + break; + } + + DCHECK(RuntimeEnabledFeatures::moduleScriptsEnabled()); + Modulator* modulator = Modulator::From( + ToScriptStateForMainWorld(element_document.GetFrame())); + FetchModuleScriptTree(url, modulator, nonce, parser_state, + credentials_mode); + + DCHECK(!resource_); + DCHECK(module_tree_client_); } - if (!FetchClassicScript(url, element_document.Fetcher(), nonce, - integrity_metadata, parser_state, cross_origin, - element_document.GetSecurityOrigin(), encoding)) { - // TODO(hiroshige): Make this asynchronous. Currently we fire the error - // event synchronously to keep the existing behavior. - DispatchErrorEvent(); - return false; - } - - DCHECK(resource_); - - // - "module": - // TODO(hiroshige): Implement this. - // "When the chosen algorithm asynchronously completes, set // the script's script to the result. At that time, the script is ready." // When the script is ready, PendingScriptClient::pendingScriptFinished() @@ -421,32 +458,50 @@ // 22. "If the element does not have a src content attribute, // run these substeps:" + if (!element_->HasSourceAttribute()) { + // 22.1. "Let source text be the value of the text IDL attribute." + // This step is done later: + // - in ScriptLoader::pendingScript() (Step 23, 6th Clause), + // as Element::textFromChildren() in ScriptLoader::scriptContent(), + // - in HTMLParserScriptRunner::processScriptElementInternal() + // (Duplicated code of Step 23, 6th Clause), + // as Element::textContent(), + // - in XMLDocumentParser::endElementNs() (Step 23, 5th Clause), + // as Element::textFromChildren() in ScriptLoader::scriptContent(), + // - PendingScript::getSource() (Indirectly used via + // HTMLParserScriptRunner::processScriptElementInternal(), + // Step 23, 5th Clause), + // as Element::textContent(). + // TODO(hiroshige): Make them merged or consistent. - // 22.1. "Let source text be the value of the text IDL attribute." - // This step is done later: - // - in ScriptLoader::pendingScript() (Step 23, 6th Clause), - // as Element::textFromChildren() in ScriptLoader::scriptContent(), - // - in HTMLParserScriptRunner::processScriptElementInternal() - // (Duplicated code of Step 23, 6th Clause), - // as Element::textContent(), - // - in XMLDocumentParser::endElementNs() (Step 23, 5th Clause), - // as Element::textFromChildren() in ScriptLoader::scriptContent(), - // - PendingScript::getSource() (Indirectly used via - // HTMLParserScriptRunner::processScriptElementInternal(), - // Step 23, 5th Clause), - // as Element::textContent(). - // TODO(hiroshige): Make them merged or consistent. + // 22.2. "Switch on the script's type:" + switch (GetScriptType()) { + // - "classic": + case ScriptType::kClassic: + // TODO(hiroshige): Clarify how Step 22.2 is implemented for "classic". + break; - // 22.2. "Switch on the script's type:" - // TODO(hiroshige): Clarify how Step 22.2 is implemented for "classic". - // TODO(hiroshige): Implement Step 22.2 for "module". + // - "module": + case ScriptType::kModule: + // TODO(hiroshige): Implement inline module scripts. + element_document.AddConsoleMessage(ConsoleMessage::Create( + kJSMessageSource, kErrorMessageLevel, + "Inline module script is not yet supported", + SourceLocation::Create(element_document.Url().GetString(), + script_start_position.line_.OneBasedInt(), + script_start_position.column_.OneBasedInt(), + nullptr))); + return false; + } + } // [Intervention] // Since the asynchronous, low priority fetch for doc.written blocked // script is not for execution, return early from here. Watch for its // completion to be able to remove it from the memory cache. - if (document_write_intervention_ == - DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) { + if (GetScriptType() == ScriptType::kClassic && + document_write_intervention_ == + DocumentWriteIntervention::kFetchDocWrittenScriptDeferIdle) { pending_script_ = CreatePendingScript(); pending_script_->WatchForLoad(this); return true; @@ -467,9 +522,14 @@ // the element has a src attribute, and the element has a defer attribute, // and the element has been flagged as "parser-inserted", // and the element does not have an async attribute" - // TODO(hiroshige): Check the script's type and implement "module" case. - if (element_->HasSourceAttribute() && element_->DeferAttributeValue() && - parser_inserted_ && !element_->AsyncAttributeValue()) { + // - "If the script's type is "module", + // and the element has been flagged as "parser-inserted", + // and the element does not have an async attribute" + if ((GetScriptType() == ScriptType::kClassic && + element_->HasSourceAttribute() && element_->DeferAttributeValue() && + parser_inserted_ && !element_->AsyncAttributeValue()) || + (GetScriptType() == ScriptType::kModule && parser_inserted_ && + !element_->AsyncAttributeValue())) { // This clause is implemented by the caller-side of prepareScript(): // - HTMLParserScriptRunner::requestDeferredScript(), and // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs() @@ -485,7 +545,8 @@ // and the element has been flagged as "parser-inserted", // and the element does not have an async attribute" // TODO(hiroshige): Check the script's type. - if (element_->HasSourceAttribute() && parser_inserted_ && + if (GetScriptType() == ScriptType::kClassic && + element_->HasSourceAttribute() && parser_inserted_ && !element_->AsyncAttributeValue()) { // This clause is implemented by the caller-side of prepareScript(): // - HTMLParserScriptRunner::requestParsingBlockingScript() @@ -509,7 +570,11 @@ // Part of the condition check is done in // HTMLParserScriptRunner::processScriptElementInternal(). // TODO(hiroshige): Clean up the split condition check. - if (!element_->HasSourceAttribute() && parser_inserted_ && + // We check that the type is "classic" here, because according to the spec + // a "module" script doesn't reach the 5th Clause because the 4th Clause + // catches all "module" scripts. + if (GetScriptType() == ScriptType::kClassic && + !element_->HasSourceAttribute() && parser_inserted_ && !element_document.IsScriptExecutionReady()) { // The former part of this clause is // implemented by the caller-side of prepareScript(): @@ -527,9 +592,15 @@ // and the element has a src attribute, // and the element does not have an async attribute, // and the element does not have the "non-blocking" flag set" + // - "If the script's type is "module", + // and the element does not have an async attribute, + // and the element does not have the "non-blocking" flag set" // TODO(hiroshige): Check the script's type and implement "module" case. - if (element_->HasSourceAttribute() && !element_->AsyncAttributeValue() && - !non_blocking_) { + if ((GetScriptType() == ScriptType::kClassic && + element_->HasSourceAttribute() && !element_->AsyncAttributeValue() && + !non_blocking_) || + (GetScriptType() == ScriptType::kModule && + !element_->AsyncAttributeValue() && !non_blocking_)) { // "Add the element to the end of the list of scripts that will execute // in order as soon as possible associated with the node document of the // script element at the time the prepare a script algorithm started." @@ -550,8 +621,10 @@ // 4th Clause: // - "If the script's type is "classic", and the element has a src attribute" - // TODO(hiroshige): Check the script's type and implement "module" case. - if (element_->HasSourceAttribute()) { + // - "If the script's type is "module"" + if ((GetScriptType() == ScriptType::kClassic && + element_->HasSourceAttribute()) || + GetScriptType() == ScriptType::kModule) { // "The element must be added to the set of scripts that will execute // as soon as possible of the node document of the script element at the // time the prepare a script algorithm started." @@ -582,6 +655,8 @@ // This clause is executed only if the script's type is "classic" // and the element doesn't have a src attribute. + DCHECK_EQ(GetScriptType(), ScriptType::kClassic); + DCHECK(!is_external_script_); // Reset line numbering for nested writes. TextPosition position = element_document.IsInDocumentWrite() @@ -669,9 +744,36 @@ return true; } +void ScriptLoader::FetchModuleScriptTree( + const KURL& url, + Modulator* modulator, + const String& nonce, + ParserDisposition parser_state, + WebURLRequest::FetchCredentialsMode credentials_mode) { + // https://html.spec.whatwg.org/#prepare-a-script + // 21.6, "module": + // "Fetch a module script graph given url, settings, "script", + // cryptographic nonce, parser state, and + // module script credentials mode." + ModuleScriptFetchRequest module_request(url, nonce, parser_state, + credentials_mode); + + module_tree_client_ = ModulePendingScriptTreeClient::Create(); + + modulator->FetchTree(module_request, module_tree_client_); +} + PendingScript* ScriptLoader::CreatePendingScript() { - CHECK(resource_); - return ClassicPendingScript::Create(element_, resource_); + switch (GetScriptType()) { + case ScriptType::kClassic: + CHECK(resource_); + return ClassicPendingScript::Create(element_, resource_); + case ScriptType::kModule: + CHECK(module_tree_client_); + return ModulePendingScript::Create(element_, module_tree_client_); + } + NOTREACHED(); + return nullptr; } bool ScriptLoader::ExecuteScript(const Script* script) { @@ -698,6 +800,7 @@ // TODO(hiroshige): Move event dispatching code to doExecuteScript(). bool ScriptLoader::DoExecuteScript(const Script* script) { DCHECK(already_started_); + CHECK_EQ(script->GetScriptType(), GetScriptType()); if (script->IsEmpty()) return true; @@ -740,10 +843,13 @@ // or the script's type is module", // then increment the ignore-destructive-writes counter of the // script element's node document. Let neutralized doc be that Document." - // TODO(hiroshige): Implement "module" case. IgnoreDestructiveWriteCountIncrementer ignore_destructive_write_count_incrementer( - is_external_script_ || is_imported_script ? context_document : 0); + is_external_script_ || + script->GetScriptType() == ScriptType::kModule || + is_imported_script + ? context_document + : 0); // 4. "Let old script element be the value to which the script element's // node document's currentScript object was most recently set." @@ -754,18 +860,24 @@ // 1. "If the script element's root is not a shadow root, // then set the script element's node document's currentScript // attribute to the script element. Otherwise, set it to null." - context_document->PushCurrentScript(element_.Get()); + // - "module": + // 1. "Set the script element's node document's currentScript attribute + // to null." + ScriptElementBase* current_script = nullptr; + if (script->GetScriptType() == ScriptType::kClassic) + current_script = element_; + context_document->PushCurrentScript(current_script); + // - "classic": // 2. "Run the classic script given by the script's script." // Note: This is where the script is compiled and actually executed. - script->RunScript(frame, element_->GetDocument().GetSecurityOrigin()); - // - "module": - // TODO(hiroshige): Implement this. + // 2. "Run the module script given by the script's script." + script->RunScript(frame, element_->GetDocument().GetSecurityOrigin()); // 6. "Set the script element's node document's currentScript attribute // to old script element." - context_document->PopCurrentScript(element_.Get()); + context_document->PopCurrentScript(current_script); return true; @@ -791,11 +903,13 @@ DispatchErrorEvent(); } resource_ = nullptr; + module_tree_client_ = nullptr; } void ScriptLoader::PendingScriptFinished(PendingScript* pending_script) { DCHECK(!will_be_parser_executed_); DCHECK_EQ(pending_script_, pending_script); + DCHECK_EQ(pending_script_->GetScriptType(), GetScriptType()); // We do not need this script in the memory cache. The primary goals of // sending this fetch request are to let the third party server know
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.h b/third_party/WebKit/Source/core/dom/ScriptLoader.h index 1188afd7..862d0a57 100644 --- a/third_party/WebKit/Source/core/dom/ScriptLoader.h +++ b/third_party/WebKit/Source/core/dom/ScriptLoader.h
@@ -39,6 +39,9 @@ class ResourceFetcher; class ScriptResource; +class Modulator; +class ModulePendingScriptTreeClient; + class CORE_EXPORT ScriptLoader : public GarbageCollectedFinalized<ScriptLoader>, public PendingScriptClient { USING_GARBAGE_COLLECTED_MIXIN(ScriptLoader); @@ -75,7 +78,7 @@ String ScriptContent() const; // Creates a PendingScript for external script whose fetch is started in - // FetchClassicScript(). + // FetchClassicScript()/FetchModuleScriptTree(). PendingScript* CreatePendingScript(); // Returns false if and only if execution was blocked. @@ -150,6 +153,12 @@ CrossOriginAttributeValue, SecurityOrigin*, const String& encoding); + // https://html.spec.whatwg.org/#fetch-a-module-script-tree + void FetchModuleScriptTree(const KURL&, + Modulator*, + const String& nonce, + ParserDisposition, + WebURLRequest::FetchCredentialsMode); bool DoExecuteScript(const Script*); @@ -184,9 +193,6 @@ // https://html.spec.whatwg.org/#concept-script-type // "It is determined when the script is prepared" - // TODO(hiroshige): Currently |script_type_| is set but ignored, and - // thus is handled as if it is a classic script even if type is "module" - // and module scripts is enabled. ScriptType script_type_ = ScriptType::kClassic; // https://html.spec.whatwg.org/#concept-script-external @@ -219,6 +225,7 @@ DocumentWriteIntervention document_write_intervention_; Member<PendingScript> pending_script_; + Member<ModulePendingScriptTreeClient> module_tree_client_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ScriptModuleResolverImplTest.cpp b/third_party/WebKit/Source/core/dom/ScriptModuleResolverImplTest.cpp index 6921f7f7..e581c4b6 100644 --- a/third_party/WebKit/Source/core/dom/ScriptModuleResolverImplTest.cpp +++ b/third_party/WebKit/Source/core/dom/ScriptModuleResolverImplTest.cpp
@@ -61,7 +61,7 @@ scope.GetIsolate(), "import './target.js'; export const a = 42;", "referrer.js", kSharableCrossOrigin); KURL referrer_url(kParsedURLString, "https://example.com/referrer.js"); - ModuleScript* referrer_module_script = ModuleScript::Create( + ModuleScript* referrer_module_script = ModuleScript::CreateForTest( modulator, referrer_record, referrer_url, "", kParserInserted, WebURLRequest::kFetchCredentialsModeOmit); // TODO(kouhei): moduleScript->setInstantiateSuccess(); once @@ -76,8 +76,8 @@ "target.js", kSharableCrossOrigin); KURL url(kParsedURLString, "https://example.com/target.js"); ModuleScript* module_script = - ModuleScript::Create(modulator, record, url, "", kParserInserted, - WebURLRequest::kFetchCredentialsModeOmit); + ModuleScript::CreateForTest(modulator, record, url, "", kParserInserted, + WebURLRequest::kFetchCredentialsModeOmit); // TODO(kouhei): moduleScript->setInstantiateSuccess(); once // https://codereview.chromium.org/2782403002/ landed. return module_script;
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElement.h b/third_party/WebKit/Source/core/dom/custom/CustomElement.h index 57984e8..5d74979 100644 --- a/third_party/WebKit/Source/core/dom/custom/CustomElement.h +++ b/third_party/WebKit/Source/core/dom/custom/CustomElement.h
@@ -37,7 +37,7 @@ static bool IsValidName(const AtomicString& name) { // This quickly rejects all common built-in element names. - if (name.Find('-', 1) == kNotFound) + if (name.find('-', 1) == kNotFound) return false; if (!IsASCIILower(name[0]))
diff --git a/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp b/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp index 0a9ef55..778df42a 100644 --- a/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp +++ b/third_party/WebKit/Source/core/dom/custom/V0CustomElement.cpp
@@ -64,7 +64,7 @@ } static inline bool IsValidNCName(const AtomicString& name) { - if (kNotFound != name.Find(':')) + if (kNotFound != name.find(':')) return false; if (!name.GetString().Is8Bit()) { @@ -86,7 +86,7 @@ kNotFound != EmbedderCustomElementNames().Find(name)) return Document::IsValidName(name); - if ((valid_names & kStandardNames) && kNotFound != name.Find('-')) { + if ((valid_names & kStandardNames) && kNotFound != name.find('-')) { DEFINE_STATIC_LOCAL(Vector<AtomicString>, reserved_names, ()); if (reserved_names.IsEmpty()) { // FIXME(crbug.com/426605): We should be able to remove this.
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp index 03686dab..686f2ada 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -953,7 +953,8 @@ OpacityMode opacity_mode) { if (ShouldUseDisplayList()) { auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( - Size(), opacity_mode, context_->color_params()); + Size(), RecordingImageBufferSurface::kAllowFallback, opacity_mode, + context_->color_params()); if (surface->IsValid()) { CanvasMetrics::CountCanvasContextUsage( CanvasMetrics::kDisplayList2DCanvasImageBufferCreated);
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp index 316d1a8..2d3cd32 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp
@@ -288,6 +288,7 @@ DCHECK(script_loader); script_loader->SetFetchDocWrittenScriptDeferIdle(); script_loader->PrepareScript(script_start_position); + CHECK_EQ(script_loader->GetScriptType(), ScriptType::kClassic); } void EmitWarningForDocWriteScripts(const String& url, Document& document) {
diff --git a/third_party/WebKit/Source/core/inspector/V8InspectorString.h b/third_party/WebKit/Source/core/inspector/V8InspectorString.h index bb585cc..08bbb3c 100644 --- a/third_party/WebKit/Source/core/inspector/V8InspectorString.h +++ b/third_party/WebKit/Source/core/inspector/V8InspectorString.h
@@ -12,6 +12,7 @@ #include "platform/wtf/Assertions.h" #include "platform/wtf/text/StringBuilder.h" #include "platform/wtf/text/StringHash.h" +#include "platform/wtf/text/StringToNumber.h" #include "platform/wtf/text/StringView.h" #include "platform/wtf/text/WTFString.h" #include "v8/include/v8-inspector.h" @@ -44,6 +45,9 @@ static String fromDouble(double number) { return Decimal::FromDouble(number).ToString(); } + static double toDouble(const char* s, size_t len, bool* ok) { + return WTF::CharactersToDouble(reinterpret_cast<const LChar*>(s), len, ok); + } static size_t find(const String& s, const char* needle) { return s.Find(needle); }
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc index 8e58a02..62492de 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -49,6 +49,11 @@ origin_point.block_offset += content_size; return origin_point; } + +inline bool IsObjectReplacementCharacter(UChar character) { + return character == kObjectReplacementCharacter; +} + } // namespace NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm( @@ -474,7 +479,12 @@ baseline = LayoutUnit(baseline.Round()); // Check if the line fits into the constraint space in block direction. - LayoutUnit line_bottom = baseline + line_box.Metrics().descent; + LayoutUnit line_bottom = baseline; + + // See http://crrev.com/2840883002 + if (!Node()->Text().IsAllSpecialCharacters<IsObjectReplacementCharacter>()) + line_bottom += line_box.Metrics().descent; + if (!container_builder_.Children().IsEmpty() && ConstraintSpace().AvailableSize().block_size != NGSizeIndefinite && line_bottom > ConstraintSpace().AvailableSize().block_size) {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc index 9dae0ce..90b6555 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -416,10 +416,13 @@ PositionFloats(curr_bfc_offset_.block_offset, curr_bfc_offset_.block_offset, container_builder_.UnpositionedFloats(), tmp_space.Get()); + NGLogicalOffset origin_offset = curr_bfc_offset_; + origin_offset.inline_offset += border_and_padding_.inline_start; + // 2. Find an estimated layout opportunity for our fragment. NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( - tmp_space->Exclusions().get(), child_space.AvailableSize(), - curr_bfc_offset_, curr_child_margins_, fragment); + tmp_space->Exclusions().get(), child_space.AvailableSize(), origin_offset, + curr_child_margins_, fragment); // 3. If the found opportunity lies on the same line with our estimated // child's BFC offset then merge fragment's margins with the current @@ -435,11 +438,14 @@ PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_, MutableConstraintSpace()); + origin_offset = curr_bfc_offset_; + origin_offset.inline_offset += border_and_padding_.inline_start; + // 5. Find the final layout opportunity for the fragment after all pending // floats are positioned at the correct BFC block's offset. opportunity = FindLayoutOpportunityForFragment( MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(), - curr_bfc_offset_, curr_child_margins_, fragment); + origin_offset, curr_child_margins_, fragment); curr_bfc_offset_ = opportunity.offset; return curr_bfc_offset_;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_opportunity_iterator.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_opportunity_iterator.cc index dce977f6..5a7c894 100644 --- a/third_party/WebKit/Source/core/layout/ng/ng_layout_opportunity_iterator.cc +++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_opportunity_iterator.cc
@@ -271,10 +271,10 @@ NGLayoutOpportunity opportunity_candidate = opportunity_iter.Next(); while (!opportunity_candidate.IsEmpty()) { opportunity = opportunity_candidate; - // Checking opportunity's block size is not necessary as a float cannot be - // positioned on top of another float inside of the same constraint space. auto fragment_inline_size = fragment.InlineSize() + margins.InlineSum(); - if (opportunity.size.inline_size >= fragment_inline_size) + auto fragment_block_size = fragment.BlockSize() + margins.BlockSum(); + if (opportunity.size.inline_size >= fragment_inline_size && + opportunity.size.block_size >= fragment_block_size) break; opportunity_candidate = opportunity_iter.Next(); }
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp index 97e66fc..e6d6844b 100644 --- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp +++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp
@@ -207,8 +207,8 @@ // Step 9. Let module script be the result of creating a module script given // source text, module map settings object, response's url, cryptographic // nonce, parser state, and credentials mode. - module_script_ = CreateModuleScript( - source_text, GetResource()->GetResponse().Url(), modulator_, nonce_, + module_script_ = ModuleScript::Create( + source_text, modulator_, GetResource()->GetResponse().Url(), nonce_, parser_state_, GetResource()->GetResourceRequest().GetFetchCredentialsMode(), access_control_status); @@ -216,38 +216,6 @@ AdvanceState(State::kFinished); } -// https://html.spec.whatwg.org/#creating-a-module-script -ModuleScript* ModuleScriptLoader::CreateModuleScript( - const String& source_text, - const KURL& url, - Modulator* modulator, - const String& nonce, - ParserDisposition parser_state, - WebURLRequest::FetchCredentialsMode credentials_mode, - AccessControlStatus access_control_status) { - // Step 1. Let script be a new module script that this algorithm will - // subsequently initialize. - // Step 2. Set script's settings object to the environment settings object - // provided. - // Note: "script's settings object" will be "modulator". - - // Delegate to Modulator::compileModule to process Steps 3-6. - ScriptModule result = modulator->CompileModule(source_text, url.GetString(), - access_control_status); - // Step 6: "...return null, and abort these steps." - if (result.IsNull()) - return nullptr; - // Step 7. Set script's module record to result. - // Step 8. Set script's base URL to the script base URL provided. - // Step 9. Set script's cryptographic nonce to the cryptographic nonce - // provided. - // Step 10. Set script's parser state to the parser state. - // Step 11. Set script's credentials mode to the credentials mode provided. - // Step 12. Return script. - return ModuleScript::Create(modulator, result, url, nonce, parser_state, - credentials_mode); -} - DEFINE_TRACE(ModuleScriptLoader) { visitor->Trace(modulator_); visitor->Trace(module_script_);
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.h b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.h index 7115de85..c317983 100644 --- a/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.h +++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.h
@@ -69,14 +69,6 @@ ModuleScriptLoaderRegistry*, ModuleScriptLoaderClient*); - static ModuleScript* CreateModuleScript(const String& source_text, - const KURL&, - Modulator*, - const String& nonce, - ParserDisposition, - WebURLRequest::FetchCredentialsMode, - AccessControlStatus); - void AdvanceState(State new_state); #if DCHECK_IS_ON() static const char* StateToString(State);
diff --git a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerTest.cpp b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerTest.cpp index 80d66873..845e532 100644 --- a/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerTest.cpp +++ b/third_party/WebKit/Source/core/loader/modulescript/ModuleTreeLinkerTest.cpp
@@ -76,9 +76,9 @@ ScriptModule script_module = ScriptModule::Compile( script_state_->GetIsolate(), source_text.ToString(), url.GetString(), kSharableCrossOrigin); - ModuleScript* module_script = - ModuleScript::Create(this, script_module, url, "", kParserInserted, - WebURLRequest::kFetchCredentialsModeOmit); + ModuleScript* module_script = ModuleScript::CreateForTest( + this, script_module, url, "", kParserInserted, + WebURLRequest::kFetchCredentialsModeOmit); auto result_request = dependency_module_requests_map_.insert( script_module, dependency_module_requests); EXPECT_TRUE(result_request.is_new_entry); @@ -121,9 +121,9 @@ ScriptModule script_module = ScriptModule::Compile( script_state_->GetIsolate(), "export default 'pineapples';", url.GetString(), kSharableCrossOrigin); - ModuleScript* module_script = - ModuleScript::Create(this, script_module, url, "", kParserInserted, - WebURLRequest::kFetchCredentialsModeOmit); + ModuleScript* module_script = ModuleScript::CreateForTest( + this, script_module, url, "", kParserInserted, + WebURLRequest::kFetchCredentialsModeOmit); auto result_map = module_map_.insert(url, module_script); EXPECT_TRUE(result_map.is_new_entry);
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp index 8bb66a3e..7c4e644c 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp +++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -338,8 +338,6 @@ // See comments for each skipped flag below. // These are not generated in ComputedStyleBase - SetOriginalDisplay(other.OriginalDisplay()); - SetVerticalAlign(other.VerticalAlign()); SetHasViewportUnits(other.HasViewportUnits()); SetHasRemUnitsInternal(other.HasRemUnits()); @@ -472,10 +470,6 @@ bool ComputedStyle::NonInheritedEqual(const ComputedStyle& other) const { // compare everything except the pseudoStyle pointer return ComputedStyleBase::NonInheritedEqual(other) && - OriginalDisplay() == - other.OriginalDisplay() && // Not generated in ComputedStyleBase - VerticalAlign() == other.VerticalAlign() && // Not generated in - // ComputedStyleBase box_data_ == other.box_data_ && visual_data_ == other.visual_data_ && rare_non_inherited_data_ == other.rare_non_inherited_data_ &&
diff --git a/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp b/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp index f4f659d9..8c1bb05f 100644 --- a/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp +++ b/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp
@@ -452,6 +452,7 @@ ScriptLoader* script_loader = ScriptElementBase::FromElementIfPossible(e)->Loader(); DCHECK(script_loader); + CHECK_EQ(script_loader->GetScriptType(), ScriptType::kClassic); if (error_occurred) { script_loader->DispatchErrorEvent(); @@ -1112,9 +1113,16 @@ DCHECK(!pending_script_); requesting_script_ = true; - if (script_loader->PrepareScript( - script_start_position_, - ScriptLoader::kAllowLegacyTypeInTypeAttribute)) { + bool success = script_loader->PrepareScript( + script_start_position_, ScriptLoader::kAllowLegacyTypeInTypeAttribute); + + if (script_loader->GetScriptType() != ScriptType::kClassic) { + // XMLDocumentParser does not support a module script, and thus ignores it. + success = false; + VLOG(0) << "Module scripts in XML documents are not supported."; + } + + if (success) { // FIXME: Script execution should be shared between // the libxml2 and Qt XMLDocumentParser implementations.
diff --git a/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js b/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js index a6629289..ba434c5 100644 --- a/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js +++ b/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js
@@ -48,12 +48,12 @@ var match = url.match(Common.ParsedURL._urlRegex()); if (match) { this.isValid = true; - this.scheme = match[1].toLowerCase(); - this.host = match[2]; - this.port = match[3]; - this.path = match[4] || '/'; - this.queryParams = match[5] || ''; - this.fragment = match[6]; + this.scheme = match[2].toLowerCase(); + this.host = match[3]; + this.port = match[4]; + this.path = match[5] || '/'; + this.queryParams = match[6] || ''; + this.fragment = match[7]; } else { if (this.url.startsWith('data:')) { this.scheme = 'data'; @@ -97,12 +97,13 @@ if (Common.ParsedURL._urlRegexInstance) return Common.ParsedURL._urlRegexInstance; // RegExp groups: - // 1 - scheme (using the RFC3986 grammar) - // 2 - hostname - // 3 - ?port - // 4 - ?path - // 5 - ?query - // 6 - ?fragment + // 1 - scheme, hostname, ?port + // 2 - scheme (using the RFC3986 grammar) + // 3 - hostname + // 4 - ?port + // 5 - ?path + // 6 - ?query + // 7 - ?fragment var schemeRegex = /([A-Za-z][A-Za-z0-9+.-]*):\/\//; var hostRegex = /([^\s\/:]*)/; var portRegex = /(?::([\d]+))?/; @@ -111,7 +112,7 @@ var fragmentRegex = /(?:#(.*))?/; Common.ParsedURL._urlRegexInstance = new RegExp( - '^' + schemeRegex.source + hostRegex.source + portRegex.source + pathRegex.source + queryRegex.source + + '^(' + schemeRegex.source + hostRegex.source + portRegex.source + ')' + pathRegex.source + queryRegex.source + fragmentRegex.source + '$'); return Common.ParsedURL._urlRegexInstance; } @@ -210,8 +211,17 @@ * @return {!{url: string, lineNumber: (number|undefined), columnNumber: (number|undefined)}} */ static splitLineAndColumn(string) { + // Only look for line and column numbers in the path to avoid matching port numbers. + var beforePathMatch = string.match(Common.ParsedURL._urlRegex()); + var beforePath = ''; + var pathAndAfter = string; + if (beforePathMatch) { + beforePath = beforePathMatch[1]; + pathAndAfter = string.substring(beforePathMatch[1].length); + } + var lineColumnRegEx = /(?::(\d+))?(?::(\d+))?$/; - var lineColumnMatch = lineColumnRegEx.exec(string); + var lineColumnMatch = lineColumnRegEx.exec(pathAndAfter); var lineNumber; var columnNumber; console.assert(lineColumnMatch); @@ -227,7 +237,7 @@ } return { - url: string.substring(0, string.length - lineColumnMatch[0].length), + url: beforePath + pathAndAfter.substring(0, pathAndAfter.length - lineColumnMatch[0].length), lineNumber: lineNumber, columnNumber: columnNumber };
diff --git a/third_party/WebKit/Source/devtools/front_end/quick_open/module.json b/third_party/WebKit/Source/devtools/front_end/quick_open/module.json index 469f08d..58de963 100644 --- a/third_party/WebKit/Source/devtools/front_end/quick_open/module.json +++ b/third_party/WebKit/Source/devtools/front_end/quick_open/module.json
@@ -2,7 +2,7 @@ "extensions": [ { "type": "@QuickOpen.FilteredListWidget.Provider", - "title": "Run a command", + "title": "Run command", "prefix": ">", "className": "QuickOpen.CommandMenuProvider" }, @@ -29,7 +29,7 @@ { "type": "@UI.ActionDelegate", "actionId": "quickOpen.show", - "title": "Go to file...", + "title": "Open file", "className": "QuickOpen.QuickOpen.ShowActionDelegate", "order": 100, "bindings": [ @@ -42,6 +42,11 @@ "shortcut": "Ctrl+P Ctrl+O" } ] + }, + { + "type": "context-menu-item", + "location": "mainMenu/navigate", + "actionId": "quickOpen.show" } ], "dependencies": [
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js index 86fd83ac..84f38c1 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -54,6 +54,7 @@ this.textEditor.element.addEventListener('keydown', this._onKeyDown.bind(this), true); this.textEditor.element.addEventListener('keyup', this._onKeyUp.bind(this), true); this.textEditor.element.addEventListener('mousemove', this._onMouseMove.bind(this), false); + this.textEditor.element.addEventListener('mousedown', this._onMouseDown.bind(this), true); if (Runtime.experiments.isEnabled('continueToLocationMarkers')) { this.textEditor.element.addEventListener('wheel', event => { if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event)) @@ -92,6 +93,8 @@ this.onBindingChanged(); Bindings.debuggerWorkspaceBinding.addEventListener( Bindings.DebuggerWorkspaceBinding.Events.SourceMappingChanged, this._onSourceMappingChanged, this); + /** @type {?Map<!Object, !Function>} */ + this._continueToLocationDecorations = null; } /** @@ -382,10 +385,12 @@ } /** - * @param {!Event} event + * @param {!MouseEvent} event * @return {?UI.PopoverRequest} */ _getPopoverRequest(event) { + if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event)) + return null; var target = UI.context.flavor(SDK.Target); var debuggerModel = target ? target.model(SDK.DebuggerModel) : null; if (!debuggerModel || !debuggerModel.isPaused()) @@ -488,10 +493,8 @@ return; } if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event) && this._executionLocation) { - if (!this._continueToLocationShown) { + if (!this._continueToLocationDecorations) this._showContinueToLocations(); - this._continueToLocationShown = true; - } } } @@ -500,11 +503,31 @@ */ _onMouseMove(event) { if (this._executionLocation && UI.KeyboardShortcut.eventHasCtrlOrMeta(event)) { - if (!this._continueToLocationShown) { + if (!this._continueToLocationDecorations) this._showContinueToLocations(); - this._continueToLocationShown = true; - } + } + } + + /** + * @param {!MouseEvent} event + */ + _onMouseDown(event) { + if (!this._executionLocation || !UI.KeyboardShortcut.eventHasCtrlOrMeta(event)) return; + if (!this._continueToLocationDecorations) + return; + event.consume(); + var textPosition = this.textEditor.coordinatesToCursorPosition(event.x, event.y); + if (!textPosition) + return; + for (var decoration of this._continueToLocationDecorations.keys()) { + var range = decoration.find(); + if (range.from.line !== textPosition.startLine || range.to.line !== textPosition.startLine) + continue; + if (range.from.ch <= textPosition.startColumn && textPosition.startColumn <= range.to.ch) { + this._continueToLocationDecorations.get(decoration)(); + break; + } } } @@ -514,10 +537,7 @@ _onKeyUp(event) { if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event)) return; - if (!this._continueToLocationShown) - return; this._clearContinueToLocations(); - this._continueToLocationShown = false; } /** @@ -583,7 +603,7 @@ setImmediate(() => { this._generateValuesInSource(); if (Runtime.experiments.isEnabled('continueToLocationMarkers')) { - if (this._continueToLocationShown) + if (this._continueToLocationDecorations) this._showContinueToLocations(); } }); @@ -616,78 +636,46 @@ _showContinueToLocations() { if (!Runtime.experiments.isEnabled('continueToLocationMarkers')) return; + this._popoverHelper.hidePopover(); var executionContext = UI.context.flavor(SDK.ExecutionContext); if (!executionContext) return; var callFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame); if (!callFrame) return; - if (this._clearContinueToLocationsTimer) { - clearTimeout(this._clearContinueToLocationsTimer); - delete this._clearContinueToLocationsTimer; - } var localScope = callFrame.localScope(); if (!localScope) { - this.textEditor.operation(clearExistingLocations.bind(this)); + this._clearContinueToLocations(); return; } var start = localScope.startLocation(); var end = localScope.endLocation(); var debuggerModel = callFrame.debuggerModel; - var executionLocation = callFrame.location(); debuggerModel.getPossibleBreakpoints(start, end, true) .then(locations => this.textEditor.operation(renderLocations.bind(this, locations))); + /** * @param {!Array<!SDK.DebuggerModel.BreakLocation>} locations * @this {Sources.JavaScriptSourceFrame} */ function renderLocations(locations) { - clearExistingLocations.call(this); + this._clearContinueToLocations(); + this._continueToLocationDecorations = new Map(); for (var location of locations) { - var icon; - var isCurrent = location.lineNumber === executionLocation.lineNumber && - location.columnNumber === executionLocation.columnNumber; - if (!isCurrent || (location.type !== SDK.DebuggerModel.BreakLocationType.Call && - location.type !== SDK.DebuggerModel.BreakLocationType.Return)) { - icon = UI.Icon.create('smallicon-green-arrow'); - icon.addEventListener('click', location.continueToLocation.bind(location)); - } else if (location.type === SDK.DebuggerModel.BreakLocationType.Call) { - icon = UI.Icon.create('smallicon-step-in'); - icon.addEventListener('click', () => { - debuggerModel.scheduleStepIntoAsync(); - debuggerModel.stepInto(); - }); - } else if (location.type === SDK.DebuggerModel.BreakLocationType.Return) { - icon = UI.Icon.create('smallicon-step-out'); - icon.addEventListener('click', () => { - debuggerModel.stepOut(); - }); - } - icon.classList.add('cm-continue-to-location'); - icon.addEventListener('mousemove', hidePopoverAndConsumeEvent.bind(this)); - this.textEditor.addBookmark( - location.lineNumber, location.columnNumber, icon, - Sources.JavaScriptSourceFrame.continueToLocationDecorationSymbol); + var lineNumber = location.lineNumber; + var token = this.textEditor.tokenAtTextPosition(lineNumber, location.columnNumber); + if (!token || !token.type) + continue; + var line = this.textEditor.line(lineNumber); + var tokenContent = line.substring(token.startColumn, token.endColumn); + if (!this._isIdentifier(token.type) && (token.type !== 'js-keyword' || tokenContent !== 'this')) + continue; + + var highlightRange = new TextUtils.TextRange(lineNumber, token.startColumn, lineNumber, token.endColumn - 1); + var decoration = this.textEditor.highlightRange(highlightRange, 'source-frame-continue-to-location'); + this._continueToLocationDecorations.set(decoration, location.continueToLocation.bind(location)); } } - - /** - * @this {Sources.JavaScriptSourceFrame} - */ - function clearExistingLocations() { - var bookmarks = this.textEditor.bookmarks( - this.textEditor.fullRange(), Sources.JavaScriptSourceFrame.continueToLocationDecorationSymbol); - bookmarks.map(bookmark => bookmark.clear()); - } - - /** - * @param {!Event} event - * @this {Sources.JavaScriptSourceFrame} - */ - function hidePopoverAndConsumeEvent(event) { - event.consume(true); - this._popoverHelper.hidePopover(); - } } /** @@ -834,28 +822,32 @@ } clearExecutionLine() { - if (this.loaded && this._executionLocation) - this.textEditor.clearExecutionLine(); - delete this._executionLocation; - this._clearValueWidgetsTimer = setTimeout(this._clearValueWidgets.bind(this), 1000); - if (Runtime.experiments.isEnabled('continueToLocationMarkers')) - this._clearContinueToLocationsTimer = setTimeout(this._clearContinueToLocations.bind(this), 1000); + this.textEditor.operation(() => { + if (this.loaded && this._executionLocation) + this.textEditor.clearExecutionLine(); + delete this._executionLocation; + this._clearValueWidgetsTimer = setTimeout(this._clearValueWidgets.bind(this), 1000); + this._clearContinueToLocations(); + }); } _clearValueWidgets() { delete this._clearValueWidgetsTimer; - for (var line of this._valueWidgets.keys()) - this.textEditor.removeDecoration(this._valueWidgets.get(line), line); - this._valueWidgets.clear(); + this.textEditor.operation(() => { + for (var line of this._valueWidgets.keys()) + this.textEditor.removeDecoration(this._valueWidgets.get(line), line); + this._valueWidgets.clear(); + }); } _clearContinueToLocations() { - if (!Runtime.experiments.isEnabled('continueToLocationMarkers')) + if (!this._continueToLocationDecorations) return; - delete this._clearContinueToLocationsTimer; - var bookmarks = this.textEditor.bookmarks( - this.textEditor.fullRange(), Sources.JavaScriptSourceFrame.continueToLocationDecorationSymbol); - this.textEditor.operation(() => bookmarks.map(bookmark => bookmark.clear())); + this.textEditor.operation(() => { + for (var decoration of this._continueToLocationDecorations.keys()) + this.textEditor.removeHighlight(decoration); + delete this._continueToLocationDecorations; + }); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js index 1736ddc..13db19a 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
@@ -26,12 +26,8 @@ /** @type {!Map.<!Workspace.UISourceCode, !UI.Widget>} */ this._sourceViewByUISourceCode = new Map(); - var tabbedEditorPlaceholderText = - Host.isMac() ? Common.UIString('Hit \u2318+P to open a file') : Common.UIString('Hit Ctrl+P to open a file'); - if (Runtime.experiments.isEnabled('persistence2')) - tabbedEditorPlaceholderText += '\n\n' + Common.UIString('Drop in a folder to add to workspace'); this._editorContainer = new Sources.TabbedEditorContainer( - this, Common.settings.createLocalSetting('previouslyViewedFiles', []), tabbedEditorPlaceholderText); + this, Common.settings.createLocalSetting('previouslyViewedFiles', []), this._placeholderElement()); this._editorContainer.show(this._searchableView.element); this._editorContainer.addEventListener( Sources.TabbedEditorContainer.Events.EditorSelected, this._editorSelected, this); @@ -95,6 +91,28 @@ } /** + * @return {!Element} + */ + _placeholderElement() { + var shortcuts = [ + {actionId: 'quickOpen.show', description: Common.UIString('Open file')}, + {actionId: 'commandMenu.show', description: Common.UIString('Run command')} + ]; + + var element = createElementWithClass('span', 'tabbed-pane-placeholder'); + for (var shortcut of shortcuts) { + var shortcutKeyText = UI.shortcutRegistry.shortcutTitleForAction(shortcut.actionId); + var row = element.createChild('div', 'tabbed-pane-placeholder-row'); + row.createChild('div', 'tabbed-pane-placeholder-key').textContent = shortcutKeyText; + row.createChild('div', 'tabbed-pane-placeholder-value').textContent = shortcut.description; + } + if (Runtime.experiments.isEnabled('persistence2')) + element.createChild('div').textContent = Common.UIString('Drop in a folder to add to workspace'); + + return element; + } + + /** * @return {!Map.<!Workspace.UISourceCode, number>} */ static defaultUISourceCodeScores() {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js b/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js index 051eaad..7906348 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js
@@ -45,14 +45,14 @@ /** * @param {!Sources.TabbedEditorContainerDelegate} delegate * @param {!Common.Setting} setting - * @param {string} placeholderText + * @param {!Element} placeholderElement */ - constructor(delegate, setting, placeholderText) { + constructor(delegate, setting, placeholderElement) { super(); this._delegate = delegate; this._tabbedPane = new UI.TabbedPane(); - this._tabbedPane.setPlaceholderText(placeholderText); + this._tabbedPane.setPlaceholderElement(placeholderElement); this._tabbedPane.setTabDelegate(new Sources.EditorContainerTabDelegate(this)); this._tabbedPane.setCloseableTabs(true);
diff --git a/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css b/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css index 004fa99..f1a8984b 100644 --- a/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css +++ b/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css
@@ -28,16 +28,39 @@ background-color: rgb(255, 255, 194); } +.CodeMirror .source-frame-eval-expression-start { + border-left-width: 1px; + margin-left: -1px; +} + .CodeMirror .source-frame-eval-expression-end { border-right-width: 1px; margin-right: -1px; } -.CodeMirror .source-frame-eval-expression-start { +.CodeMirror .source-frame-continue-to-location { + outline: 0; + border: 1px solid transparent; + border-left-width: 0; + border-right-width: 0; + background-color: rgb(230, 236, 255); + cursor: pointer; +} + +.CodeMirror .source-frame-continue-to-location:hover { + border: 1px solid rgb(121, 141, 254); + background-color: rgb(171, 191, 254); +} +.CodeMirror .source-frame-continue-to-location-start { border-left-width: 1px; margin-left: -1px; } +.CodeMirror .source-frame-continue-to-location-end { + border-right-width: 1px; + margin-right: -1px; +} + .CodeMirror-readonly .CodeMirror-cursor { display: none; }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Popover.js b/third_party/WebKit/Source/devtools/front_end/ui/Popover.js index 6dd7e1ac..c5994a7a 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/Popover.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/Popover.js
@@ -34,7 +34,7 @@ UI.PopoverHelper = class { /** * @param {!Element} container - * @param {function(!Event):?UI.PopoverRequest} getRequest + * @param {function(!MouseEvent):?UI.PopoverRequest} getRequest */ constructor(container, getRequest) { this._disableOnClick = false; @@ -93,7 +93,7 @@ this._startHidePopoverTimer(0); this._stopShowPopoverTimer(); - this._startShowPopoverTimer(event, 0); + this._startShowPopoverTimer(/** @type {!MouseEvent} */ (event), 0); } /** @@ -108,7 +108,8 @@ this._stopShowPopoverTimer(); if (event.which && this._disableOnClick) return; - this._startShowPopoverTimer(event, this.isPopoverVisible() ? this._showTimeout * 0.6 : this._showTimeout); + this._startShowPopoverTimer( + /** @type {!MouseEvent} */ (event), this.isPopoverVisible() ? this._showTimeout * 0.6 : this._showTimeout); } /** @@ -154,7 +155,7 @@ } /** - * @param {!Event} event + * @param {!MouseEvent} event * @param {number} timeout */ _startShowPopoverTimer(event, timeout) {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js b/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js index a578b774..81bbe25 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js
@@ -489,10 +489,15 @@ } /** - * @param {string} text + * @param {!Element} element */ - setPlaceholderText(text) { - this._noTabsMessage = text; + setPlaceholderElement(element) { + this._placeholderElement = element; + + if (this._placeholderContainerElement) { + this._placeholderContainerElement.removeChildren(); + this._placeholderContainerElement.appendChild(element); + } } _innerUpdateTabElements() { @@ -501,15 +506,15 @@ if (!this._tabs.length) { this._contentElement.classList.add('has-no-tabs'); - if (this._noTabsMessage && !this._noTabsMessageElement) { - this._noTabsMessageElement = this._contentElement.createChild('div', 'tabbed-pane-placeholder fill'); - this._noTabsMessageElement.textContent = this._noTabsMessage; + if (this._placeholderElement && !this._placeholderContainerElement) { + this._placeholderContainerElement = this._contentElement.createChild('div', 'tabbed-pane-placeholder fill'); + this._placeholderContainerElement.appendChild(this._placeholderElement); } } else { this._contentElement.classList.remove('has-no-tabs'); - if (this._noTabsMessageElement) { - this._noTabsMessageElement.remove(); - delete this._noTabsMessageElement; + if (this._placeholderContainerElement) { + this._placeholderContainerElement.remove(); + delete this._placeholderContainerElement; } }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/tabbedPane.css b/third_party/WebKit/Source/devtools/front_end/ui/tabbedPane.css index ab6f320..da591de1 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/tabbedPane.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/tabbedPane.css
@@ -50,7 +50,27 @@ text-align: center; margin-top: 20px; text-shadow: rgba(255, 255, 255, 0.75) 0 1px 0; - white-space: pre; + line-height: 28px; + overflow: hidden; +} + +.tabbed-pane-placeholder-row { + display: flex; + white-space: nowrap; +} + +.tabbed-pane-placeholder-key { + flex: 1; + text-align: right; + padding-right: 14px; + overflow: hidden; + text-overflow: ellipsis; +} + +.tabbed-pane-placeholder-value { + flex: 1; + text-align: left; + padding-left: 14px; } .tabbed-pane-header {
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp index 3489a30..22cd88c7 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -519,8 +519,8 @@ TEST_F(CanvasRenderingContext2DTest, NoLayerPromotionByDefault) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -530,8 +530,8 @@ TEST_F(CanvasRenderingContext2DTest, NoLayerPromotionUnderOverdrawLimit) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -548,8 +548,8 @@ TEST_F(CanvasRenderingContext2DTest, LayerPromotionOverOverdrawLimit) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -566,8 +566,8 @@ TEST_F(CanvasRenderingContext2DTest, NoLayerPromotionUnderImageSizeRatioLimit) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -600,8 +600,8 @@ TEST_F(CanvasRenderingContext2DTest, LayerPromotionOverImageSizeRatioLimit) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -636,8 +636,8 @@ TEST_F(CanvasRenderingContext2DTest, NoLayerPromotionUnderExpensivePathPointCount) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -660,8 +660,8 @@ TEST_F(CanvasRenderingContext2DTest, LayerPromotionOverExpensivePathPointCount) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -683,8 +683,8 @@ TEST_F(CanvasRenderingContext2DTest, LayerPromotionWhenPathIsConcave) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -705,8 +705,8 @@ TEST_F(CanvasRenderingContext2DTest, NoLayerPromotionWithRectangleClip) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -721,8 +721,8 @@ TEST_F(CanvasRenderingContext2DTest, LayerPromotionWithComplexClip) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -744,8 +744,8 @@ TEST_F(CanvasRenderingContext2DTest, LayerPromotionWithBlurredShadow) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -763,8 +763,8 @@ TEST_F(CanvasRenderingContext2DTest, NoLayerPromotionWithSharpShadow) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -778,8 +778,8 @@ TEST_F(CanvasRenderingContext2DTest, NoFallbackWithSmallState) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -798,8 +798,8 @@ TEST_F(CanvasRenderingContext2DTest, FallbackWithLargeState) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -822,8 +822,8 @@ // does not support pixel geometry settings. // See: crbug.com/583809 CreateContext(kOpaque); - auto surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface)); @@ -835,8 +835,8 @@ TEST_F(CanvasRenderingContext2DTest, NonOpaqueDisplayListDoesNotFallBackForText) { CreateContext(kNonOpaque); - std::unique_ptr<RecordingImageBufferSurface> surface = - WTF::MakeUnique<RecordingImageBufferSurface>(IntSize(10, 10), kNonOpaque); + auto surface = WTF::MakeUnique<RecordingImageBufferSurface>( + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, kNonOpaque); auto* surface_ptr = surface.get(); CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(surface));
diff --git a/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp b/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp index 4bbff95..25bbd22 100644 --- a/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp +++ b/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp
@@ -91,7 +91,8 @@ PaintRenderingContext2D* rendering_context = PaintRenderingContext2D::Create( ImageBuffer::Create(WTF::WrapUnique(new RecordingImageBufferSurface( - size, has_alpha_ ? kNonOpaque : kOpaque))), + size, RecordingImageBufferSurface::kDisallowFallback, + has_alpha_ ? kNonOpaque : kOpaque))), has_alpha_, zoom); PaintSize* paint_size = PaintSize::Create(specified_size); StylePropertyMapReadonly* style_map =
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp index e535711..c8784980 100644 --- a/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp +++ b/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp
@@ -506,6 +506,8 @@ serialized_value->ToWireBytes(wire_bytes); RefPtr<SharedBuffer> value_buffer = SharedBuffer::AdoptVector(wire_bytes); + request->StorePutOperationBlobs(serialized_value->BlobDataHandles()); + BackendDB()->Put(transaction_->Id(), Id(), WebData(value_buffer), blob_info, key, static_cast<WebIDBPutMode>(put_mode), request->CreateWebCallbacks().release(), index_ids,
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBRequest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBRequest.cpp index bea4fbb..1ddd3180 100644 --- a/third_party/WebKit/Source/modules/indexeddb/IDBRequest.cpp +++ b/third_party/WebKit/Source/modules/indexeddb/IDBRequest.cpp
@@ -241,6 +241,7 @@ void IDBRequest::OnError(DOMException* error) { IDB_TRACE("IDBRequest::onError()"); + ClearPutOperationBlobs(); if (!ShouldEnqueueEvent()) return; @@ -289,6 +290,7 @@ void IDBRequest::OnSuccess(IDBKey* idb_key) { IDB_TRACE("IDBRequest::onSuccess(IDBKey)"); + ClearPutOperationBlobs(); if (!ShouldEnqueueEvent()) return; @@ -360,6 +362,7 @@ void IDBRequest::OnSuccessInternal(IDBAny* result) { DCHECK(GetExecutionContext()); DCHECK(!pending_cursor_); + DCHECK(transit_blob_handles_.IsEmpty()); SetResult(result); EnqueueEvent(Event::Create(EventTypeNames::success)); }
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h b/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h index 4f221aeb..69d4f1395 100644 --- a/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h +++ b/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h
@@ -29,6 +29,8 @@ #ifndef IDBRequest_h #define IDBRequest_h +#include <memory> + #include "bindings/core/v8/ActiveScriptWrappable.h" #include "bindings/core/v8/ScriptState.h" #include "bindings/core/v8/ScriptValue.h" @@ -43,10 +45,10 @@ #include "modules/indexeddb/IndexedDB.h" #include "platform/blob/BlobData.h" #include "platform/heap/Handle.h" +#include "platform/wtf/HashMap.h" #include "public/platform/WebBlobInfo.h" #include "public/platform/modules/indexeddb/WebIDBCursor.h" #include "public/platform/modules/indexeddb/WebIDBTypes.h" -#include <memory> namespace blink { @@ -141,6 +143,11 @@ IDBCursor* GetResultCursor() const; + void StorePutOperationBlobs( + HashMap<String, RefPtr<BlobDataHandle>> blob_handles) { + transit_blob_handles_ = std::move(blob_handles); + } + protected: IDBRequest(ScriptState*, IDBAny* source, IDBTransaction*); void EnqueueEvent(Event*); @@ -168,6 +175,8 @@ void AckReceivedBlobs(const IDBValue*); void AckReceivedBlobs(const Vector<RefPtr<IDBValue>>&); + void ClearPutOperationBlobs() { transit_blob_handles_.clear(); } + Member<IDBAny> source_; Member<IDBAny> result_; Member<DOMException> error_; @@ -187,6 +196,8 @@ Member<IDBKey> cursor_primary_key_; RefPtr<IDBValue> cursor_value_; + HashMap<String, RefPtr<BlobDataHandle>> transit_blob_handles_; + bool did_fire_upgrade_needed_event_ = false; bool prevent_propagation_ = false; bool result_dirty_ = true;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentDetailsInit.idl b/third_party/WebKit/Source/modules/payments/PaymentDetailsInit.idl index 1f9ddb6..9a784e38 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentDetailsInit.idl +++ b/third_party/WebKit/Source/modules/payments/PaymentDetailsInit.idl
@@ -5,5 +5,6 @@ // https://w3c.github.io/browser-payment-api/#paymentdetailsinit-dictionary dictionary PaymentDetailsInit : PaymentDetailsBase { + DOMString id; required PaymentItem total; };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp index 1c2bbb0..d245f988 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp +++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
@@ -39,6 +39,7 @@ #include "modules/payments/PaymentsValidators.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "platform/RuntimeEnabledFeatures.h" +#include "platform/UUID.h" #include "platform/mojo/MojoHelper.h" #include "platform/wtf/HashSet.h" #include "public/platform/InterfaceProvider.h" @@ -536,6 +537,11 @@ return; } + if (input.hasId()) + output->id = input.id(); + else + output->id = CreateCanonicalUUIDString(); + ValidateAndConvertTotal(input.total(), output->total, exception_state); } @@ -880,6 +886,8 @@ if (exception_state.HadException()) return; + id_ = validated_details->id; + if (options_.requestShipping()) shipping_type_ = GetValidShippingType(options_.shippingType()); @@ -975,7 +983,7 @@ complete_timer_.StartOneShot(kCompleteTimeoutSeconds, BLINK_FROM_HERE); - show_resolver_->Resolve(new PaymentResponse(std::move(response), this)); + show_resolver_->Resolve(new PaymentResponse(std::move(response), this, id_)); // Do not close the mojo connection here. The merchant website should call // PaymentResponse::complete(String), which will be forwarded over the mojo
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.h b/third_party/WebKit/Source/modules/payments/PaymentRequest.h index f3c1319..a36b56b 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentRequest.h +++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.h
@@ -61,6 +61,7 @@ ScriptPromise show(ScriptState*); ScriptPromise abort(ScriptState*); + const String& id() const { return id_; } PaymentAddress* getShippingAddress() const { return shipping_address_.Get(); } const String& shippingOption() const { return shipping_option_; } const String& shippingType() const { return shipping_type_; } @@ -116,6 +117,7 @@ PaymentOptions options_; Member<PaymentAddress> shipping_address_; + String id_; String shipping_option_; String shipping_type_; Member<ScriptPromiseResolver> show_resolver_;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.idl b/third_party/WebKit/Source/modules/payments/PaymentRequest.idl index e3e06d2..50e698e 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentRequest.idl +++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.idl
@@ -17,6 +17,7 @@ [CallWith=ScriptState] Promise<void> abort(); [CallWith=ScriptState, RuntimeEnabled=CanMakePayment] Promise<boolean> canMakePayment(); + readonly attribute DOMString id; [ImplementedAs=getShippingAddress] readonly attribute PaymentAddress? shippingAddress; readonly attribute DOMString? shippingOption; readonly attribute PaymentShippingType? shippingType;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp index b52a250..c7d0851a 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp +++ b/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp
@@ -631,5 +631,19 @@ EXPECT_TRUE(request->shippingOption().IsNull()); } +TEST(PaymentRequestTest, DetailsIdIsSet) { + V8TestingScope scope; + MakePaymentRequestOriginSecure(scope.GetDocument()); + PaymentDetailsInit details; + details.setTotal(BuildPaymentItemForTest()); + details.setId("my_payment_id"); + + PaymentRequest* request = PaymentRequest::Create( + scope.GetExecutionContext(), BuildPaymentMethodDataForTest(), details, + scope.GetExceptionState()); + + EXPECT_EQ("my_payment_id", request->id()); +} + } // namespace } // namespace blink
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp b/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp index 379ecc9..f28abe3 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp +++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp
@@ -15,8 +15,10 @@ PaymentResponse::PaymentResponse( payments::mojom::blink::PaymentResponsePtr response, - PaymentCompleter* payment_completer) - : method_name_(response->method_name), + PaymentCompleter* payment_completer, + const String& requestId) + : requestId_(requestId), + method_name_(response->method_name), stringified_details_(response->stringified_details), shipping_address_( response->shipping_address @@ -34,6 +36,7 @@ ScriptValue PaymentResponse::toJSONForBinding(ScriptState* script_state) const { V8ObjectBuilder result(script_state); + result.AddString("requestId", requestId()); result.AddString("methodName", methodName()); result.Add("details", details(script_state, ASSERT_NO_EXCEPTION));
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.h b/third_party/WebKit/Source/modules/payments/PaymentResponse.h index f3a713f..e105768 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentResponse.h +++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.h
@@ -30,11 +30,13 @@ public: PaymentResponse(payments::mojom::blink::PaymentResponsePtr, - PaymentCompleter*); + PaymentCompleter*, + const String& requestId); virtual ~PaymentResponse(); ScriptValue toJSONForBinding(ScriptState*) const; + const String& requestId() const { return requestId_; } const String& methodName() const { return method_name_; } ScriptValue details(ScriptState*, ExceptionState&) const; PaymentAddress* shippingAddress() const { return shipping_address_.Get(); } @@ -48,6 +50,7 @@ DECLARE_TRACE(); private: + String requestId_; String method_name_; String stringified_details_; Member<PaymentAddress> shipping_address_;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.idl b/third_party/WebKit/Source/modules/payments/PaymentResponse.idl index 71284189..9d21cb9 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentResponse.idl +++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.idl
@@ -17,6 +17,7 @@ ] interface PaymentResponse { serializer = {attribute}; + readonly attribute DOMString requestId; readonly attribute DOMString methodName; [RuntimeEnabled=PaymentRequestPayerName] readonly attribute DOMString? payerName; readonly attribute DOMString? payerEmail;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp index b8fea86..e3984bc 100644 --- a/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp +++ b/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp
@@ -55,7 +55,7 @@ MockPaymentCompleter* complete_callback = new MockPaymentCompleter; PaymentResponse* output = - new PaymentResponse(std::move(input), complete_callback); + new PaymentResponse(std::move(input), complete_callback, ""); EXPECT_EQ("foo", output->methodName()); EXPECT_EQ("standardShippingOption", output->shippingOption()); @@ -85,7 +85,7 @@ input->stringified_details = "transactionId"; MockPaymentCompleter* complete_callback = new MockPaymentCompleter; PaymentResponse* output = - new PaymentResponse(std::move(input), complete_callback); + new PaymentResponse(std::move(input), complete_callback, ""); ScriptValue details = output->details(scope.GetScriptState(), scope.GetExceptionState()); @@ -101,7 +101,7 @@ input->stringified_details = "{\"transactionId\": 123}"; MockPaymentCompleter* complete_callback = new MockPaymentCompleter; PaymentResponse* output = - new PaymentResponse(std::move(input), complete_callback); + new PaymentResponse(std::move(input), complete_callback, ""); EXPECT_CALL(*complete_callback, Complete(scope.GetScriptState(), PaymentCompleter::kSuccess)); @@ -117,7 +117,7 @@ input->stringified_details = "{\"transactionId\": 123}"; MockPaymentCompleter* complete_callback = new MockPaymentCompleter; PaymentResponse* output = - new PaymentResponse(std::move(input), complete_callback); + new PaymentResponse(std::move(input), complete_callback, ""); EXPECT_CALL(*complete_callback, Complete(scope.GetScriptState(), PaymentCompleter::kFail)); @@ -144,7 +144,7 @@ input->shipping_address->address_line.push_back("First floor"); PaymentResponse* output = - new PaymentResponse(std::move(input), new MockPaymentCompleter); + new PaymentResponse(std::move(input), new MockPaymentCompleter, ""); ScriptValue json_object = output->toJSONForBinding(scope.GetScriptState()); EXPECT_TRUE(json_object.IsObject()); @@ -154,7 +154,8 @@ .ToLocalChecked(), kDoNotExternalize); String expected = - "{\"methodName\":\"foo\",\"details\":{\"transactionId\":123}," + "{\"requestId\":\"\",\"methodName\":\"foo\",\"details\":{" + "\"transactionId\":123}," "\"shippingAddress\":{\"country\":\"US\",\"addressLine\":[\"340 Main " "St\"," "\"BIN1\",\"First "
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index dff63a1..31e7f16d 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -2207,6 +2207,11 @@ # TODO(toyoshim): Remove Platform dependency and move to loader/BUILD.gn "loader/fetch/ResourceResponseTest.cpp", + + # TODO(hongchan): Platform::Current()->CreateThread() returns nullptr + # without adding the test file into this section. Remove platform dependency + # when creating a valid thread becomes possible in the Blink unit test. + "audio/PushPullFIFOMultithreadTest.cpp", ] configs += [
diff --git a/third_party/WebKit/Source/platform/audio/AudioDestination.cpp b/third_party/WebKit/Source/platform/audio/AudioDestination.cpp index ff053c2..e71d5ec 100644 --- a/third_party/WebKit/Source/platform/audio/AudioDestination.cpp +++ b/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
@@ -29,7 +29,9 @@ #include "platform/audio/AudioDestination.h" #include <memory> +#include "platform/CrossThreadFunctional.h" #include "platform/Histogram.h" +#include "platform/WebTaskRunner.h" #include "platform/audio/AudioUtilities.h" #include "platform/audio/PushPullFIFO.h" #include "platform/weborigin/SecurityOrigin.h" @@ -37,6 +39,7 @@ #include "public/platform/Platform.h" #include "public/platform/WebAudioLatencyHint.h" #include "public/platform/WebSecurityOrigin.h" +#include "public/platform/WebThread.h" namespace blink { @@ -64,14 +67,16 @@ PassRefPtr<SecurityOrigin> security_origin) : number_of_output_channels_(number_of_output_channels), is_playing_(false), - callback_(callback), + rendering_thread_(WTF::WrapUnique( + Platform::Current()->CreateThread("WebAudio Rendering Thread"))), + fifo_(WTF::WrapUnique( + new PushPullFIFO(number_of_output_channels, kFIFOSize))), output_bus_(AudioBus::Create(number_of_output_channels, AudioUtilities::kRenderQuantumFrames, false)), render_bus_(AudioBus::Create(number_of_output_channels, AudioUtilities::kRenderQuantumFrames)), - fifo_(WTF::WrapUnique( - new PushPullFIFO(number_of_output_channels, kFIFOSize))), + callback_(callback), frames_elapsed_(0) { // Create WebAudioDevice. blink::WebAudioDevice is designed to support the // local input (e.g. loopback from OS audio system), but Chromium's media @@ -97,6 +102,9 @@ double delay, double delay_timestamp, size_t prior_frames_skipped) { + // This method is called by AudioDeviceThread. + DCHECK(!IsRenderingThread()); + CHECK_EQ(destination_data.size(), number_of_output_channels_); CHECK_EQ(number_of_frames, callback_buffer_size_); @@ -106,25 +114,36 @@ if (!fifo_ || fifo_->length() < number_of_frames) return; - frames_elapsed_ -= std::min(frames_elapsed_, prior_frames_skipped); - double output_position = - frames_elapsed_ / static_cast<double>(web_audio_device_->SampleRate()) - - delay; - output_position_.position = output_position; - output_position_.timestamp = delay_timestamp; - output_position_received_timestamp_ = base::TimeTicks::Now(); - // Associate the destination data array with the output bus then fill the // FIFO. for (unsigned i = 0; i < number_of_output_channels_; ++i) output_bus_->SetChannelMemory(i, destination_data[i], number_of_frames); - // Number of frames to render via WebAudio graph. |framesToRender > 0| means - // the frames in FIFO is not enough to fulfill the requested frames from the - // audio device. - size_t frames_to_render = number_of_frames > fifo_->FramesAvailable() - ? number_of_frames - fifo_->FramesAvailable() - : 0; + size_t frames_to_render = fifo_->Pull(output_bus_.Get(), number_of_frames); + + rendering_thread_->GetWebTaskRunner()->PostTask( + BLINK_FROM_HERE, + CrossThreadBind(&AudioDestination::RequestRenderOnWebThread, + CrossThreadUnretained(this), + number_of_frames, frames_to_render, + delay, delay_timestamp, prior_frames_skipped)); +} + +void AudioDestination::RequestRenderOnWebThread(size_t frames_requested, + size_t frames_to_render, + double delay, + double delay_timestamp, + size_t prior_frames_skipped) { + // This method is called by WebThread. + DCHECK(IsRenderingThread()); + + frames_elapsed_ -= std::min(frames_elapsed_, prior_frames_skipped); + AudioIOPosition output_position; + output_position.position = + frames_elapsed_ / static_cast<double>(web_audio_device_->SampleRate()) - + delay; + output_position.timestamp = delay_timestamp; + base::TimeTicks received_timestamp = base::TimeTicks::Now(); for (size_t pushed_frames = 0; pushed_frames < frames_to_render; pushed_frames += AudioUtilities::kRenderQuantumFrames) { @@ -132,27 +151,23 @@ // we do not want output position to get stuck so we promote it // using the elapsed time from the moment it was initially obtained. if (callback_buffer_size_ > AudioUtilities::kRenderQuantumFrames * 2) { - double delta = - (base::TimeTicks::Now() - output_position_received_timestamp_) - .InSecondsF(); - output_position_.position += delta; - output_position_.timestamp += delta; + double delta = (base::TimeTicks::Now() - received_timestamp).InSecondsF(); + output_position.position += delta; + output_position.timestamp += delta; } // Some implementations give only rough estimation of |delay| so // we might have negative estimation |outputPosition| value. - if (output_position_.position < 0.0) - output_position_.position = 0.0; + if (output_position.position < 0.0) + output_position.position = 0.0; // Process WebAudio graph and push the rendered output to FIFO. callback_.Render(nullptr, render_bus_.Get(), - AudioUtilities::kRenderQuantumFrames, output_position_); + AudioUtilities::kRenderQuantumFrames, output_position); fifo_->Push(render_bus_.Get()); } - fifo_->Pull(output_bus_.Get(), number_of_frames); - - frames_elapsed_ += number_of_frames; + frames_elapsed_ += frames_requested; } void AudioDestination::Start() { @@ -204,4 +219,9 @@ return is_buffer_size_valid; } +bool AudioDestination::IsRenderingThread() { + return static_cast<ThreadIdentifier>(rendering_thread_->ThreadId()) == + CurrentThread(); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/AudioDestination.h b/third_party/WebKit/Source/platform/audio/AudioDestination.h index 6bf30f3..64797f22 100644 --- a/third_party/WebKit/Source/platform/audio/AudioDestination.h +++ b/third_party/WebKit/Source/platform/audio/AudioDestination.h
@@ -43,6 +43,7 @@ class PushPullFIFO; class SecurityOrigin; class WebAudioLatencyHint; +class WebThread; // The AudioDestination class is an audio sink interface between the media // renderer and the Blink's WebAudio module. It has a FIFO to adapt the @@ -73,6 +74,14 @@ double delay_timestamp, size_t prior_frames_skipped) override; + // The actual render request to the WebAudio destination node. This triggers + // the WebAudio rendering pipe line on the web thread. + void RequestRenderOnWebThread(size_t frames_requested, + size_t frames_to_render, + double delay, + double delay_timestamp, + size_t prior_frames_skipped); + virtual void Start(); virtual void Stop(); @@ -90,32 +99,38 @@ static unsigned long MaxChannelCount(); private: - std::unique_ptr<WebAudioDevice> web_audio_device_; - unsigned number_of_output_channels_; - size_t callback_buffer_size_; - bool is_playing_; - - // The render callback function of WebAudio engine. (i.e. DestinationNode) - AudioIOCallback& callback_; - - // To pass the data from FIFO to the audio device callback. - RefPtr<AudioBus> output_bus_; - - // To push the rendered result from WebAudio graph into the FIFO. - RefPtr<AudioBus> render_bus_; - - // Resolves the buffer size mismatch between the WebAudio engine and - // the callback function from the actual audio device. - std::unique_ptr<PushPullFIFO> fifo_; - - size_t frames_elapsed_; - AudioIOPosition output_position_; - base::TimeTicks output_position_received_timestamp_; - // Check if the buffer size chosen by the WebAudioDevice is too large. bool CheckBufferSize(); size_t HardwareBufferSize(); + + bool IsRenderingThread(); + + std::unique_ptr<WebAudioDevice> web_audio_device_; + const unsigned number_of_output_channels_; + size_t callback_buffer_size_; + bool is_playing_; + + // Rendering thread for WebAudio graph. + std::unique_ptr<WebThread> rendering_thread_; + + // Accessed by both threads: resolves the buffer size mismatch between the + // WebAudio engine and the callback function from the actual audio device. + std::unique_ptr<PushPullFIFO> fifo_; + + // Accessed by device thread: to pass the data from FIFO to the device. + RefPtr<AudioBus> output_bus_; + + // Accessed by rendering thread: to push the rendered result from WebAudio + // graph into the FIFO. + RefPtr<AudioBus> render_bus_; + + // Accessed by rendering thread: the render callback function of WebAudio + // engine. (i.e. DestinationNode) + AudioIOCallback& callback_; + + // Accessed by rendering thread. + size_t frames_elapsed_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp b/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp index fdfafd7a..7d18c6e 100644 --- a/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp +++ b/third_party/WebKit/Source/platform/audio/PushPullFIFO.cpp
@@ -19,21 +19,18 @@ const size_t PushPullFIFO::kMaxFIFOLength = 65536; PushPullFIFO::PushPullFIFO(unsigned number_of_channels, size_t fifo_length) - : fifo_length_(fifo_length), - frames_available_(0), - index_read_(0), - index_write_(0), - overflow_count_(0), - underflow_count_(0) { + : fifo_length_(fifo_length) { CHECK_LE(fifo_length_, kMaxFIFOLength); fifo_bus_ = AudioBus::Create(number_of_channels, fifo_length_); } PushPullFIFO::~PushPullFIFO() {} -// Push the data from |inputBus| to FIFO. The size of push is determined by -// the length of |inputBus|. +// Push the data from |input_bus| to FIFO. The size of push is determined by +// the length of |input_bus|. void PushPullFIFO::Push(const AudioBus* input_bus) { + MutexLocker locker(lock_); + CHECK(input_bus); CHECK_EQ(input_bus->length(), AudioUtilities::kRenderQuantumFrames); SECURITY_CHECK(input_bus->length() <= fifo_length_); @@ -61,8 +58,8 @@ // Update the write index; wrap it around if necessary. index_write_ = (index_write_ + input_bus_length) % fifo_length_; - // In case of overflow, move the |indexRead| to the updated |indexWrite| to - // avoid reading overwritten frames by the next pull. + // In case of overflow, move the |index_read_| to the updated |index_write_| + // to avoid reading overwritten frames by the next pull. if (input_bus_length > fifo_length_ - frames_available_) { index_read_ = index_write_; if (++overflow_count_ < kMaxMessagesToLog) { @@ -80,16 +77,18 @@ DCHECK_EQ((index_read_ + frames_available_) % fifo_length_, index_write_); } -// Pull the data out of FIFO to |outputBus|. If remaining frame in the FIFO +// Pull the data out of FIFO to |output_bus|. If remaining frame in the FIFO // is less than the frames to pull, provides remaining frame plus the silence. -void PushPullFIFO::Pull(AudioBus* output_bus, size_t frames_requested) { +size_t PushPullFIFO::Pull(AudioBus* output_bus, size_t frames_requested) { + MutexLocker locker(lock_); + #if OS(ANDROID) if (!output_bus) { // Log when outputBus or FIFO object is invalid. (crbug.com/692423) LOG(WARNING) << "[WebAudio/PushPullFIFO::pull <" << static_cast<void*>(this) << ">] |outputBus| is invalid."; // Silently return to avoid crash. - return; + return 0; } // The following checks are in place to catch the inexplicable crash. @@ -110,6 +109,7 @@ << " >= " << fifo_length_ << ")"; } #endif + CHECK(output_bus); SECURITY_CHECK(frames_requested <= output_bus->length()); SECURITY_CHECK(frames_requested <= fifo_length_); @@ -162,10 +162,16 @@ // Update the number of frames in FIFO. frames_available_ -= frames_to_fill; DCHECK_EQ((index_read_ + frames_available_) % fifo_length_, index_write_); + + // |frames_requested > frames_available_| means the frames in FIFO is not + // enough to fulfill the requested frames from the audio device. + return frames_requested > frames_available_ + ? frames_requested - frames_available_ + : 0; } const PushPullFIFOStateForTest PushPullFIFO::GetStateForTest() const { - return {length(), NumberOfChannels(), FramesAvailable(), index_read_, + return {length(), NumberOfChannels(), frames_available_, index_read_, index_write_, overflow_count_, underflow_count_}; }
diff --git a/third_party/WebKit/Source/platform/audio/PushPullFIFO.h b/third_party/WebKit/Source/platform/audio/PushPullFIFO.h index 447ee221..017d89683 100644 --- a/third_party/WebKit/Source/platform/audio/PushPullFIFO.h +++ b/third_party/WebKit/Source/platform/audio/PushPullFIFO.h
@@ -7,6 +7,9 @@ #include "platform/audio/AudioBus.h" #include "platform/wtf/Allocator.h" +#include "platform/wtf/Functional.h" +#include "platform/wtf/Threading.h" +#include "platform/wtf/ThreadingPrimitives.h" #include "public/platform/WebCommon.h" namespace blink { @@ -26,6 +29,14 @@ // Blink-WebAudio and the renderer. The renderer's hardware callback buffer size // varies on the platform, but the WebAudio always renders 128 frames (render // quantum, RQ) thus FIFO is needed to handle the general case. +// +// Note that this object is concurrently accessed by two threads; WebAudio +// rendering thread (WebThread) in Blink and the audio device thread +// (AudioDeviceThread) from the media renderer. The push/pull operations touch +// most of variables in the class (index_write_, index_read_, frames_available_, +// and fifo_Bus_) so the thread safety must be handled with care. +// +// TODO(hongchan): add a unit test for multi-thread access. class BLINK_PLATFORM_EXPORT PushPullFIFO { USING_FAST_MALLOC(PushPullFIFO); WTF_MAKE_NONCOPYABLE(PushPullFIFO); @@ -34,50 +45,53 @@ // Maximum FIFO length. (512 render quanta) static const size_t kMaxFIFOLength; - // |fifoLength| cannot exceed |kMaxFIFOLength|. Otherwise it crashes. + // |fifo_length| cannot exceed |kMaxFIFOLength|. Otherwise it crashes. explicit PushPullFIFO(unsigned number_of_channels, size_t fifo_length); ~PushPullFIFO(); // Pushes the rendered frames by WebAudio engine. - // - The |inputBus| length is 128 frames (1 render quantum), fixed. + // - The |input_bus| length is 128 frames (1 render quantum), fixed. // - In case of overflow (FIFO full while push), the existing frames in FIFO - // will be overwritten and |indexRead| will be forcibly moved to - // |indexWrite| to avoid reading overwritten frames. + // will be overwritten and |index_read_| will be forcibly moved to + // |index_write_| to avoid reading overwritten frames. void Push(const AudioBus* input_bus); - // Pulling |framesRequested| by the audio device thread. - // - If |framesRequested| is bigger than the length of |outputBus|, it + // Pulls |frames_requested| by the audio device thread and returns the actual + // number of frames to be rendered by the source. (i.e. WebAudio graph) + // - If |frames_requested| is bigger than the length of |output_bus|, it // violates SECURITY_CHECK(). - // - If |framesRequested| is bigger than FIFO length, it violates + // - If |frames_requested| is bigger than FIFO length, it violates // SECURITY_CHECK(). // - In case of underflow (FIFO empty while pull), the remaining space in the // requested output bus will be filled with silence. Thus it will fulfill // the request from the consumer without causing error, but with a glitch. - void Pull(AudioBus* output_bus, size_t frames_requested); + size_t Pull(AudioBus* output_bus, size_t frames_requested); - size_t FramesAvailable() const { return frames_available_; } size_t length() const { return fifo_length_; } unsigned NumberOfChannels() const { return fifo_bus_->NumberOfChannels(); } - AudioBus* Bus() const { return fifo_bus_.Get(); } - // For unit test. Get the current configuration that consists of FIFO length, - // number of channels, read/write index position and under/overflow count. + // TODO(hongchan): For single thread unit test only. Consider refactoring. + AudioBus* GetFIFOBusForTest() const { return fifo_bus_.Get(); } + + // For single thread unit test only. Get the current configuration that + // consists of FIFO length, number of channels, read/write index position and + // under/overflow count. const PushPullFIFOStateForTest GetStateForTest() const; private: // The size of the FIFO. const size_t fifo_length_ = 0; - RefPtr<AudioBus> fifo_bus_; + unsigned overflow_count_ = 0; + unsigned underflow_count_ = 0; + // This lock protects variables below. + Mutex lock_; // The number of frames in the FIFO actually available for pulling. - size_t frames_available_; - - size_t index_read_; - size_t index_write_; - - unsigned overflow_count_; - unsigned underflow_count_; + size_t frames_available_ = 0; + size_t index_read_ = 0; + size_t index_write_ = 0; + RefPtr<AudioBus> fifo_bus_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/PushPullFIFOMultithreadTest.cpp b/third_party/WebKit/Source/platform/audio/PushPullFIFOMultithreadTest.cpp new file mode 100644 index 0000000..24b0fa91 --- /dev/null +++ b/third_party/WebKit/Source/platform/audio/PushPullFIFOMultithreadTest.cpp
@@ -0,0 +1,235 @@ +// 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 "platform/audio/PushPullFIFO.h" + +#include <memory> +#include <vector> +#include "platform/CrossThreadFunctional.h" +#include "platform/WaitableEvent.h" +#include "platform/WebTaskRunner.h" +#include "platform/audio/AudioUtilities.h" +#include "platform/testing/UnitTestHelpers.h" +#include "platform/wtf/Functional.h" +#include "platform/wtf/PtrUtil.h" +#include "public/platform/Platform.h" +#include "public/platform/WebThread.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +namespace { + +// To forcibly stop the message loop. +// TODO(hongchan): move this hack into Test class when the solution is found. +void FinishTest() { + LOG(INFO) << "FinishTest"; + testing::ExitRunLoop(); +} + +// To wait for spawned threads to finish their tasks. +// TODO(hongchan): move this hack into Test class when the solution is found. +void HoldTestForDuration(double duration_ms) { + LOG(INFO) << "HoldTestForDuration"; + Platform::Current()->CurrentThread()->GetWebTaskRunner()->PostDelayedTask( + BLINK_FROM_HERE, + WTF::Bind(&FinishTest), + duration_ms); + testing::EnterRunLoop(); +} + +// Base FIFOClient with an extra thread for looping and jitter control. The +// child class must define a specific task to run on the thread. +class FIFOClient { + public: + FIFOClient(PushPullFIFO* fifo, size_t bus_length, size_t jitter_range_ms) + : fifo_(fifo), + bus_(AudioBus::Create(fifo->NumberOfChannels(), bus_length)), + client_thread_(WTF::WrapUnique( + Platform::Current()->CreateThread("client thread"))), + jitter_range_ms_(jitter_range_ms) {} + + void Start(double duration_ms, double interval_ms) { + duration_ms_ = duration_ms; + interval_ms_ = interval_ms; + client_thread_->GetWebTaskRunner()->PostTask( + BLINK_FROM_HERE, + CrossThreadBind(&FIFOClient::RunTaskOnOwnThread, + CrossThreadUnretained(this))); + } + + virtual void Stop(int callback_counter) = 0; + virtual void RunTask() = 0; + + void Pull(size_t frames_to_pull) { + fifo_->Pull(bus_.Get(), frames_to_pull); + } + + void Push() { + fifo_->Push(bus_.Get()); + } + + private: + void RunTaskOnOwnThread() { + double interval_with_jitter = interval_ms_ + + (static_cast<double>(std::rand()) / RAND_MAX) * jitter_range_ms_; + elapsed_ms_ += interval_with_jitter; + ++counter_; + RunTask(); + if (elapsed_ms_ < duration_ms_) { + client_thread_->GetWebTaskRunner()->PostDelayedTask( + BLINK_FROM_HERE, + CrossThreadBind(&FIFOClient::RunTaskOnOwnThread, + CrossThreadUnretained(this)), + interval_with_jitter); + } else { + Stop(counter_); + } + } + + PushPullFIFO* fifo_; + RefPtr<AudioBus> bus_; + std::unique_ptr<WebThread> client_thread_; + + // Test duration. + double duration_ms_; + + // Interval between each callback. + double interval_ms_; + + // Jitter added to the regular pushing/pulling interval. + // (where j is 0 < j < jitter_range_ms) + double jitter_range_ms_; + + // Elapsed test duration. + double elapsed_ms_ = 0; + + // Counter variable for the total number of callbacks invoked. + int counter_ = 0; +}; + +// FIFO-pulling client (consumer). This mimics the audio device thread. +// |frames_to_pull| is variable. +class PullClient : public FIFOClient { + public: + PullClient(PushPullFIFO* fifo, size_t frames_to_pull, double jitter_range_ms) + : FIFOClient(fifo, frames_to_pull, jitter_range_ms), + frames_to_pull_(frames_to_pull) { + } + + void RunTask() override { + Pull(frames_to_pull_); + } + + void Stop(int callback_counter) override { + LOG(INFO) << "PullClient stopped. (" << callback_counter << " calls)"; + } + + private: + size_t frames_to_pull_; +}; + +// FIFO-pushing client (producer). This mimics the WebAudio rendering thread. +// The frames to push are static as 128 frames. +class PushClient : public FIFOClient { + public: + PushClient(PushPullFIFO* fifo, size_t frames_to_push, double jitter_range_ms) + : FIFOClient(fifo, frames_to_push, jitter_range_ms) {} + + void RunTask() override { + Push(); + } + + void Stop(int callback_counter) override { + LOG(INFO) << "PushClient stopped. (" << callback_counter << " calls)"; + } +}; + +struct FIFOSmokeTestParam { + const double sample_rate; + const unsigned number_of_channels; + const size_t fifo_length; + const double test_duration_ms; + // Buffer size for pulling. Equivalent of |callback_buffer_size|. + const size_t pull_buffer_size; + // Jitter range for the pulling interval. + const double pull_jitter_range_ms; + // Buffer size for pushing. Equivalent of WebAudio render quantum. + const size_t push_buffer_size; + // Jitter range for the pushing interval. + const double push_jitter_range_ms; +}; + +class PushPullFIFOSmokeTest + : public ::testing::TestWithParam<FIFOSmokeTestParam> {}; + +TEST_P(PushPullFIFOSmokeTest, SmokeTests) { + const FIFOSmokeTestParam param = GetParam(); + const double sample_rate = param.sample_rate * 4; + + const double pull_interval_ms = + param.pull_buffer_size / sample_rate * 1000; + const double push_interval_ms = + param.push_buffer_size / sample_rate * 1000; + + std::unique_ptr<PushPullFIFO> test_fifo = WTF::WrapUnique( + new PushPullFIFO(param.number_of_channels, param.fifo_length)); + std::unique_ptr<PullClient> pull_client = WTF::WrapUnique(new PullClient( + test_fifo.get(), param.pull_buffer_size, param.pull_jitter_range_ms)); + std::unique_ptr<PushClient> push_client = WTF::WrapUnique(new PushClient( + test_fifo.get(), param.push_buffer_size, param.push_jitter_range_ms)); + + LOG(INFO) << "PushPullFIFOSmokeTest - Start"; + + pull_client->Start(param.test_duration_ms, pull_interval_ms); + push_client->Start(param.test_duration_ms, push_interval_ms); + + // If the operation does not cause a crash for the test period, it's passed. + // Also give a bit more time to finish the tear-down process. + HoldTestForDuration(param.test_duration_ms + 150); +} + +FIFOSmokeTestParam smoke_test_params[] = { + // Test case 0 (OSX): 256 Pull, 128 Push, Minimal jitter. + // WebThread's priority is lower than the device thread, so its jitter range + // is slightly bigger than the other. + {48000, 2, 8192, 1000, 256, 1, 128, 2}, + + // Test case 1 (Windows): 441 Pull, 128 Push. Moderate Jitter. + // Windows' audio callback is known to be ~10ms and UMA data shows the + // evidence for it. The jitter range was determined speculatively. + {44100, 2, 8192, 1000, 441, 2, 128, 3}, + + // Test case 2 (Ubuntu/Linux): 512 Pull, 128 Push. Unstable callback, but + // fast CPU. A typical configuration for Ubuntu + PulseAudio setup. + // PulseAudio's callback is known to be rather unstable. + {48000, 2, 8192, 1000, 512, 8, 128, 1}, + + // Test case 3 (Android-Reference): 512 Pull, 128 Push. Similar to Linux, but + // low profile CPU. + {44100, 2, 8192, 1000, 512, 8, 128, 3}, + + // Test case 4 (Android-ExternalA): 441 Pull, 128 Push. Extreme jitter with + // low profile CPU. + {44100, 2, 8192, 1000, 441, 24, 128, 8}, + + // Test case 5 (Android-ExternalB): 5768 Pull, 128 Push. Huge callback with + // large jitter. Low profile CPU. + {44100, 2, 8192, 1000, 5768, 120, 128, 12}, + + // Test case 6 (User-specified buffer size): 960 Pull, 128 Push. Minimal + // Jitter. 960 frames = 20ms at 48KHz. + {48000, 2, 8192, 1000, 960, 1, 128, 1}, + + // Test case 7 (Longer test duration): 256 Pull, 128 Push. 10 seconds. + {48000, 2, 8192, 10000, 256, 0, 128, 1} +}; + +INSTANTIATE_TEST_CASE_P(PushPullFIFOSmokeTest, + PushPullFIFOSmokeTest, + ::testing::ValuesIn(smoke_test_params)); + +} // namespace + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/PushPullFIFOTest.cpp b/third_party/WebKit/Source/platform/audio/PushPullFIFOTest.cpp index 9351b42..c0d1b77 100644 --- a/third_party/WebKit/Source/platform/audio/PushPullFIFOTest.cpp +++ b/third_party/WebKit/Source/platform/audio/PushPullFIFOTest.cpp
@@ -6,51 +6,57 @@ #include <memory> #include <vector> +#include "platform/CrossThreadFunctional.h" +#include "platform/WebTaskRunner.h" #include "platform/audio/AudioUtilities.h" #include "platform/testing/TestingPlatformSupport.h" +#include "platform/wtf/Functional.h" #include "platform/wtf/PtrUtil.h" +#include "public/platform/Platform.h" +#include "public/platform/WebThread.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { namespace { -// Check the basic contract of FIFO. +// Check the basic contract of FIFO. This test only covers the single thread +// scenario. TEST(PushPullFIFOBasicTest, BasicTests) { // This suppresses the multi-thread warning for GTest. Potently it increases // the test execution time, but this specific test is very short and simple. ::testing::FLAGS_gtest_death_test_style = "threadsafe"; // FIFO length exceeding the maximum length allowed will cause crash. - // i.e.) m_fifoLength <= kMaxFIFOLength + // i.e.) fifo_length_ <= kMaxFIFOLength EXPECT_DEATH(new PushPullFIFO(2, PushPullFIFO::kMaxFIFOLength + 1), ""); std::unique_ptr<PushPullFIFO> test_fifo = WTF::WrapUnique(new PushPullFIFO(2, 1024)); // The input bus length must be |AudioUtilities::kRenderQuantumFrames|. - // i.e.) inputBus->length() == kRenderQuantumFrames - RefPtr<AudioBus> input_bus_of129_frames = + // i.e.) input_bus->length() == kRenderQuantumFrames + RefPtr<AudioBus> input_bus_129_frames = AudioBus::Create(2, AudioUtilities::kRenderQuantumFrames + 1); - EXPECT_DEATH(test_fifo->Push(input_bus_of129_frames.Get()), ""); - RefPtr<AudioBus> input_bus_of127_frames = + EXPECT_DEATH(test_fifo->Push(input_bus_129_frames.Get()), ""); + RefPtr<AudioBus> input_bus_127_frames = AudioBus::Create(2, AudioUtilities::kRenderQuantumFrames - 1); - EXPECT_DEATH(test_fifo->Push(input_bus_of127_frames.Get()), ""); + EXPECT_DEATH(test_fifo->Push(input_bus_127_frames.Get()), ""); // Pull request frames cannot exceed the length of output bus. - // i.e.) framesRequested <= outputBus->length() - RefPtr<AudioBus> output_bus_of512_frames = AudioBus::Create(2, 512); - EXPECT_DEATH(test_fifo->Pull(output_bus_of512_frames.Get(), 513), ""); + // i.e.) frames_requested <= output_bus->length() + RefPtr<AudioBus> output_bus_512_frames = AudioBus::Create(2, 512); + EXPECT_DEATH(test_fifo->Pull(output_bus_512_frames.Get(), 513), ""); // Pull request frames cannot exceed the length of FIFO. - // i.e.) framesRequested <= m_fifoLength - RefPtr<AudioBus> output_bus_of1025_frames = AudioBus::Create(2, 1025); - EXPECT_DEATH(test_fifo->Pull(output_bus_of1025_frames.Get(), 1025), ""); + // i.e.) frames_requested <= fifo_length_ + RefPtr<AudioBus> output_bus_1025_frames = AudioBus::Create(2, 1025); + EXPECT_DEATH(test_fifo->Pull(output_bus_1025_frames.Get(), 1025), ""); } // Fills each AudioChannel in an AudioBus with a series of linearly increasing -// values starting from |startingValue| and incrementing by 1. Then return value -// will be |startingValue| + |bus_length|. +// values starting from |starting_value| and incrementing by 1. Then return +// value will be |starting_value| + |bus_length|. size_t FillBusWithLinearRamp(AudioBus* target_bus, size_t starting_value) { for (unsigned c = 0; c < target_bus->NumberOfChannels(); ++c) { float* bus_channel = target_bus->Channel(c)->MutableData(); @@ -169,7 +175,8 @@ // Verify in-FIFO samples. for (const auto& sample : expected_state.fifo_samples) { - EXPECT_TRUE(VerifyBusValueAtIndex(fifo->Bus(), sample.index, sample.value)); + EXPECT_TRUE(VerifyBusValueAtIndex(fifo->GetFIFOBusForTest(), + sample.index, sample.value)); } // Verify samples from the most recent output bus.
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp index 23e4a518..da3a88f 100644 --- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp +++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -501,8 +501,8 @@ // Create and configure a recording (unaccelerated) surface. std::unique_ptr<ImageBufferSurface> surface = WTF::WrapUnique(new RecordingImageBufferSurface( - surface_->size(), surface_->GetOpacityMode(), - surface_->color_params())); + surface_->size(), RecordingImageBufferSurface::kAllowFallback, + surface_->GetOpacityMode(), surface_->color_params())); SetSurface(std::move(surface)); }
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp index 11f0991..5315caa 100644 --- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp +++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
@@ -20,9 +20,11 @@ RecordingImageBufferSurface::RecordingImageBufferSurface( const IntSize& size, + AllowFallback allow_fallback, OpacityMode opacity_mode, const CanvasColorParams& color_params) : ImageBufferSurface(size, opacity_mode, color_params), + allow_fallback_(allow_fallback), image_buffer_(0), current_frame_pixel_count_(0), previous_frame_pixel_count_(0), @@ -77,6 +79,7 @@ void RecordingImageBufferSurface::FallBackToRasterCanvas( FallbackReason reason) { + DCHECK(allow_fallback_ == kAllowFallback); CHECK(reason != kFallbackReasonUnknown); if (fallback_surface_) { @@ -315,8 +318,9 @@ return false; } - if (current_frame_->getRecordingCanvas()->getSaveCount() - 1 > - ExpensiveCanvasHeuristicParameters::kExpensiveRecordingStackDepth) { + if (allow_fallback_ == kAllowFallback && + current_frame_->getRecordingCanvas()->getSaveCount() - 1 > + ExpensiveCanvasHeuristicParameters::kExpensiveRecordingStackDepth) { // (getSaveCount() decremented to account for the intial recording canvas // save frame.) *fallback_reason = kFallbackReasonRunawayStateStack;
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h index 8ed5756c8..19938f7 100644 --- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h +++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h
@@ -23,14 +23,16 @@ USING_FAST_MALLOC(RecordingImageBufferSurface); public: - // If the fallbackFactory is null the buffer surface should only be used - // for one frame and should not be used for any operations which need a - // raster surface, (i.e. writePixels). - // Only #getRecord should be used to access the resulting frame. - RecordingImageBufferSurface( - const IntSize&, - OpacityMode = kNonOpaque, - const CanvasColorParams& = CanvasColorParams()); + enum AllowFallback : bool { kDisallowFallback, kAllowFallback }; + + // If |AllowFallback| is kDisallowFallback the buffer surface should only be + // used for one frame and should not be used for any operations which need a + // raster surface, (i.e. WritePixels()). + // Only GetRecord() should be used to access the resulting frame. + RecordingImageBufferSurface(const IntSize&, + AllowFallback, + OpacityMode = kNonOpaque, + const CanvasColorParams& = CanvasColorParams()); ~RecordingImageBufferSurface() override; // Implementation of ImageBufferSurface interfaces @@ -106,6 +108,7 @@ bool FinalizeFrameInternal(FallbackReason*); int ApproximateOpCount(); + const AllowFallback allow_fallback_; std::unique_ptr<PaintRecorder> current_frame_; sk_sp<PaintRecord> previous_frame_; std::unique_ptr<UnacceleratedImageBufferSurface> fallback_surface_;
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp index e4d44dc..3b4b653 100644 --- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
@@ -29,7 +29,8 @@ protected: RecordingImageBufferSurfaceTest() { auto test_surface = WTF::MakeUnique<RecordingImageBufferSurface>( - IntSize(10, 10), kNonOpaque); + IntSize(10, 10), RecordingImageBufferSurface::kAllowFallback, + kNonOpaque); test_surface_ = test_surface.get(); // We create an ImageBuffer in order for the |test_surface| to be // properly initialized with a GraphicsContext
diff --git a/third_party/WebKit/Source/platform/wtf/text/AtomicString.h b/third_party/WebKit/Source/platform/wtf/text/AtomicString.h index 1aa0d61..ecdb99fe 100644 --- a/third_party/WebKit/Source/platform/wtf/text/AtomicString.h +++ b/third_party/WebKit/Source/platform/wtf/text/AtomicString.h
@@ -98,14 +98,14 @@ UChar operator[](unsigned i) const { return string_[i]; } // Find characters. - size_t Find(UChar c, unsigned start = 0) const { + size_t find(UChar c, unsigned start = 0) const { return string_.find(c, start); } - size_t Find(LChar c, unsigned start = 0) const { + size_t find(LChar c, unsigned start = 0) const { return string_.find(c, start); } - size_t Find(char c, unsigned start = 0) const { - return Find(static_cast<LChar>(c), start); + size_t find(char c, unsigned start = 0) const { + return find(static_cast<LChar>(c), start); } size_t Find(CharacterMatchFunctionPtr match_function, unsigned start = 0) const { @@ -132,7 +132,7 @@ return string_.FindIgnoringASCIICase(value, start); } - bool Contains(char c) const { return Find(c) != kNotFound; } + bool Contains(char c) const { return find(c) != kNotFound; } bool Contains( const StringView& value, TextCaseSensitivity case_sensitivity = kTextCaseSensitive) const {
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py index 62c523a..8328a63 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
@@ -1097,9 +1097,8 @@ def _shorten_filename(self, filename): finder = WebKitFinder(self._port.host.filesystem) - # TODO(tkent): Can we use path_from_layout_tests() instead? - if filename.startswith(finder.path_from_webkit_base()): - return self._port.host.filesystem.relpath(filename, finder.path_from_webkit_base()) + if filename.startswith(finder.path_from_chromium_base()): + return self._port.host.filesystem.relpath(filename, finder.path_from_chromium_base()) return filename def _report_warnings(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py index c8aea18..9ffc1a2 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py
@@ -387,6 +387,12 @@ self.assertEqual(expectations.get_expectations(test_name1), set([PASS, FAIL, TIMEOUT])) self.assertEqual(expectations.get_expectations(test_name2), set([CRASH])) + def test_shorten_filename(self): + expectations = TestExpectations(self._port, self.get_basic_tests()) + self.assertEquals(expectations._shorten_filename('/out-of-checkout/TestExpectations'), + '/out-of-checkout/TestExpectations') + self.assertEquals(expectations._shorten_filename('/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations'), + 'third_party/WebKit/LayoutTests/TestExpectations') class SkippedTests(Base):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py index b4f0616..a77e180d1 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -67,7 +67,7 @@ # TODO(qyearsley): Simplify this to use LocalWPT.fetch when csswg-test # is merged into web-platform-tests (crbug.com/706118). - temp_repo_path = self.finder.path_from_webkit_base(dest_dir_name) + temp_repo_path = self.finder.path_from_layout_tests(dest_dir_name) _log.info('Cloning repo: %s', repo_url) _log.info('Local path: %s', temp_repo_path) self.run(['git', 'clone', repo_url, temp_repo_path]) @@ -139,8 +139,9 @@ _log.warning('Checkout has local commits; aborting. Use --allow-local-commits to allow this.') return False - if self.fs.exists(self.finder.path_from_webkit_base(WPT_DEST_NAME)): - _log.warning('WebKit/%s exists; aborting.', WPT_DEST_NAME) + temp_repo_path = self.finder.path_from_layout_tests(WPT_DEST_NAME) + if self.fs.exists(temp_repo_path): + _log.warning('%s exists; aborting.', temp_repo_path) return False return True @@ -162,7 +163,7 @@ def clean_up_temp_repo(self, temp_repo_path): _log.info('Deleting temp repo directory %s.', temp_repo_path) - self.rmtree(temp_repo_path) + self.fs.rmtree(temp_repo_path) def _copy_resources(self): """Copies resources from wpt to LayoutTests/resources. @@ -248,7 +249,7 @@ basename != 'OWNERS') files_to_delete = self.fs.files_under(dest_path, file_filter=should_remove) for subpath in files_to_delete: - self.remove('LayoutTests', 'external', subpath) + self.remove(self.finder.path_from_layout_tests('external', subpath)) def _commit_changes(self, commit_message): _log.info('Committing changes.') @@ -286,7 +287,7 @@ def run(self, cmd, exit_on_failure=True, cwd=None, stdin=''): _log.debug('Running command: %s', ' '.join(cmd)) - cwd = cwd or self.finder.webkit_base() + cwd = cwd or self.finder.path_from_layout_tests() proc = self.executive.popen(cmd, stdout=self.executive.PIPE, stderr=self.executive.PIPE, stdin=self.executive.PIPE, cwd=cwd) out, err = proc.communicate(stdin) if proc.returncode or self.verbose: @@ -311,16 +312,10 @@ _log.debug('cp %s %s', source, destination) self.fs.copyfile(source, destination) - def remove(self, *comps): - dest = self.finder.path_from_webkit_base(*comps) + def remove(self, dest): _log.debug('rm %s', dest) self.fs.remove(dest) - def rmtree(self, *comps): - dest = self.finder.path_from_webkit_base(*comps) - _log.debug('rm -fr %s', dest) - self.fs.rmtree(dest) - def do_auto_update(self): """Attempts to upload a CL, make any required adjustments, and commit.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py index 2a3f3c5..db22c11 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
@@ -25,11 +25,11 @@ self.assertEqual(return_code, 0) self.assertLog([ 'INFO: Cloning repo: https://chromium.googlesource.com/external/w3c/web-platform-tests.git\n', - 'INFO: Local path: /mock-checkout/third_party/WebKit/wpt\n', + 'INFO: Local path: /mock-checkout/third_party/WebKit/LayoutTests/wpt\n', 'INFO: There were exportable but not-yet-exported commits:\n', 'INFO: https://chromium.googlesource.com/chromium/src/+/deadbeef\n', 'INFO: Aborting import to prevent clobbering these commits.\n', - 'INFO: Deleting temp repo directory /mock-checkout/third_party/WebKit/wpt.\n', + 'INFO: Deleting temp repo directory /mock-checkout/third_party/WebKit/LayoutTests/wpt.\n', ]) def test_update_test_expectations(self):
diff --git a/third_party/closure_compiler/externs/networking_private.js b/third_party/closure_compiler/externs/networking_private.js index e911ff8..f8fc26f5 100644 --- a/third_party/closure_compiler/externs/networking_private.js +++ b/third_party/closure_compiler/externs/networking_private.js
@@ -767,6 +767,7 @@ * @typedef {{ * BatteryPercentage: (number|undefined), * Carrier: (string|undefined), + * HasConnectedToHost: boolean, * SignalStrength: (number|undefined) * }} * @see https://developer.chrome.com/extensions/networkingPrivate#type-TetherProperties @@ -775,16 +776,6 @@ /** * @typedef {{ - * BatteryPercentage: (!chrome.networkingPrivate.ManagedLong|undefined), - * Carrier: (!chrome.networkingPrivate.ManagedDOMString|undefined), - * SignalStrength: (!chrome.networkingPrivate.ManagedLong|undefined) - * }} - * @see https://developer.chrome.com/extensions/networkingPrivate#type-ManagedTetherProperties - */ -chrome.networkingPrivate.ManagedTetherProperties; - -/** - * @typedef {{ * AutoConnect: (boolean|undefined), * Host: (string|undefined), * IPsec: (!chrome.networkingPrivate.IPSecProperties|undefined), @@ -968,7 +959,7 @@ * StaticIPConfig: (!chrome.networkingPrivate.ManagedIPConfigProperties|undefined), * SavedIPConfig: (!chrome.networkingPrivate.IPConfigProperties|undefined), * Source: (string|undefined), - * Tether: (!chrome.networkingPrivate.ManagedTetherProperties|undefined), + * Tether: (!chrome.networkingPrivate.TetherProperties|undefined), * Type: !chrome.networkingPrivate.NetworkType, * VPN: (!chrome.networkingPrivate.ManagedVPNProperties|undefined), * WiFi: (!chrome.networkingPrivate.ManagedWiFiProperties|undefined),
diff --git a/third_party/custom_tabs_client/BUILD.gn b/third_party/custom_tabs_client/BUILD.gn index f98ff51..dd0a56c3d 100644 --- a/third_party/custom_tabs_client/BUILD.gn +++ b/third_party/custom_tabs_client/BUILD.gn
@@ -43,6 +43,8 @@ android_library("custom_tabs_support_java") { java_files = [ + "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsIntent.java", + "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionItem.java", "src/customtabs/src/android/support/customtabs/CustomTabsCallback.java", "src/customtabs/src/android/support/customtabs/CustomTabsClient.java", "src/customtabs/src/android/support/customtabs/CustomTabsIntent.java",
diff --git a/third_party/custom_tabs_client/README.chromium b/third_party/custom_tabs_client/README.chromium index 1714401f..fac3ac31 100644 --- a/third_party/custom_tabs_client/README.chromium +++ b/third_party/custom_tabs_client/README.chromium
@@ -13,4 +13,7 @@ management. Also inside demos there is another application that launches custom tabs in different modes. +The example applicaton also presents how to use Browser Actions, including +creating request intent and adding custom items. + Local Modifications: none
diff --git a/third_party/inspector_protocol/README.chromium b/third_party/inspector_protocol/README.chromium index f3fd10d..b1863f9 100644 --- a/third_party/inspector_protocol/README.chromium +++ b/third_party/inspector_protocol/README.chromium
@@ -2,7 +2,7 @@ Short Name: inspector_protocol URL: https://chromium.googlesource.com/deps/inspector_protocol/ Version: 0 -Revision: 13768f332cacb5170d64b8fcce1887b78fec2d86 +Revision: efefa86c3183d307f0a0e53bf568fe57c5b58849 License: BSD License File: LICENSE Security Critical: no
diff --git a/third_party/inspector_protocol/lib/Parser_cpp.template b/third_party/inspector_protocol/lib/Parser_cpp.template index 4bf6beb..f3dde5a 100644 --- a/third_party/inspector_protocol/lib/Parser_cpp.template +++ b/third_party/inspector_protocol/lib/Parser_cpp.template
@@ -51,19 +51,13 @@ buffer.push_back(static_cast<char>(characters[i])); } buffer.push_back('\0'); - char* endptr; - double result = std::strtod(buffer.data(), &endptr); - *ok = !(*endptr); - return result; + return StringUtil::toDouble(buffer.data(), length, ok); } double charactersToDouble(const uint8_t* characters, size_t length, bool* ok) { std::string buffer(reinterpret_cast<const char*>(characters), length); - char* endptr; - double result = std::strtod(buffer.data(), &endptr); - *ok = !(*endptr); - return result; + return StringUtil::toDouble(buffer.data(), length, ok); } template<typename Char>
diff --git a/third_party/netty-tcnative/BUILD.gn b/third_party/netty-tcnative/BUILD.gn index 9fecf9c..521a81a 100644 --- a/third_party/netty-tcnative/BUILD.gn +++ b/third_party/netty-tcnative/BUILD.gn
@@ -11,37 +11,15 @@ shared_library("netty-tcnative-so") { output_name = "netty-tcnative" sources = [ - "src/c/address.c", "src/c/bb.c", - "src/c/dir.c", "src/c/error.c", - "src/c/file.c", - "src/c/info.c", "src/c/jnilib.c", - "src/c/lock.c", - "src/c/misc.c", - "src/c/mmap.c", - "src/c/multicast.c", - "src/c/network.c", - "src/c/os.c", - "src/c/os_unix_system.c", - "src/c/os_unix_uxpipe.c", - "src/c/poll.c", - "src/c/pool.c", - "src/c/proc.c", - "src/c/shm.c", + "src/c/native_constants.c", "src/c/ssl.c", "src/c/ssl_private.h", "src/c/sslcontext.c", - "src/c/sslinfo.c", - "src/c/sslnetwork.c", "src/c/sslutils.c", - "src/c/stdlib.c", "src/c/tcn.h", - "src/c/tcn_api.h", - "src/c/tcn_version.h", - "src/c/thread.c", - "src/c/user.c", ] include_dirs = [ "../apache-portable-runtime/src/include" ] defines = [ "HAVE_OPENSSL" ] @@ -56,47 +34,14 @@ # Builds the Java part of netty-tcnative library. android_library("netty-tcnative_java") { java_files = [ - "src/java/src/org/apache/tomcat/Apr.java", - "src/java/src/org/apache/tomcat/jni/Address.java", - "src/java/src/org/apache/tomcat/jni/BIOCallback.java", - "src/java/src/org/apache/tomcat/jni/Buffer.java", - "src/java/src/org/apache/tomcat/jni/CertificateVerifier.java", - "src/java/src/org/apache/tomcat/jni/Directory.java", - "src/java/src/org/apache/tomcat/jni/Error.java", - "src/java/src/org/apache/tomcat/jni/FileInfo.java", - "src/java/src/org/apache/tomcat/jni/File.java", - "src/java/src/org/apache/tomcat/jni/Global.java", - "src/java/src/org/apache/tomcat/jni/Library.java", - "src/java/src/org/apache/tomcat/jni/LibraryNotFoundError.java", - "src/java/src/org/apache/tomcat/jni/Local.java", - "src/java/src/org/apache/tomcat/jni/Lock.java", - "src/java/src/org/apache/tomcat/jni/Mmap.java", - "src/java/src/org/apache/tomcat/jni/Multicast.java", - "src/java/src/org/apache/tomcat/jni/OS.java", - "src/java/src/org/apache/tomcat/jni/PasswordCallback.java", - "src/java/src/org/apache/tomcat/jni/Poll.java", - "src/java/src/org/apache/tomcat/jni/PoolCallback.java", - "src/java/src/org/apache/tomcat/jni/Pool.java", - "src/java/src/org/apache/tomcat/jni/Procattr.java", - "src/java/src/org/apache/tomcat/jni/ProcErrorCallback.java", - "src/java/src/org/apache/tomcat/jni/Proc.java", - "src/java/src/org/apache/tomcat/jni/Registry.java", - "src/java/src/org/apache/tomcat/jni/SessionTicketKey.java", - "src/java/src/org/apache/tomcat/jni/Shm.java", - "src/java/src/org/apache/tomcat/jni/Sockaddr.java", - "src/java/src/org/apache/tomcat/jni/socket/AprSocketContext.java", - "src/java/src/org/apache/tomcat/jni/socket/AprSocket.java", - "src/java/src/org/apache/tomcat/jni/socket/HostInfo.java", - "src/java/src/org/apache/tomcat/jni/Socket.java", - "src/java/src/org/apache/tomcat/jni/SSLContext.java", - "src/java/src/org/apache/tomcat/jni/SSLExt.java", - "src/java/src/org/apache/tomcat/jni/SSL.java", - "src/java/src/org/apache/tomcat/jni/SSLSocket.java", - "src/java/src/org/apache/tomcat/jni/Status.java", - "src/java/src/org/apache/tomcat/jni/Stdlib.java", - "src/java/src/org/apache/tomcat/jni/Thread.java", - "src/java/src/org/apache/tomcat/jni/Time.java", - "src/java/src/org/apache/tomcat/jni/User.java", + "src/java/io/netty/internal/tcnative/Buffer.java", + "src/java/io/netty/internal/tcnative/CertificateRequestedCallback.java", + "src/java/io/netty/internal/tcnative/CertificateVerifier.java", + "src/java/io/netty/internal/tcnative/Library.java", + "src/java/io/netty/internal/tcnative/NativeStaticallyReferencedJniMethods.java", + "src/java/io/netty/internal/tcnative/SessionTicketKey.java", + "src/java/io/netty/internal/tcnative/SSL.java", + "src/java/io/netty/internal/tcnative/SSLContext.java", ] run_findbugs_override = false deps = [
diff --git a/third_party/netty-tcnative/README.chromium b/third_party/netty-tcnative/README.chromium index 0cc63a1f..377ab58 100644 --- a/third_party/netty-tcnative/README.chromium +++ b/third_party/netty-tcnative/README.chromium
@@ -1,10 +1,9 @@ Name: Tomcat Native Fork for Netty Short Name: netty-tcnative -URL: https://github.com/netty/netty-tcnative -SHA: 856865181ca38c07b7d2be619903ee98f6f77a23 netty-tcnative-1.1.33.zip -Version: 1.1.33 -Date: October 13, 2015 -Revision: 2aa47be27783ec31086ca9881402f845543de4e6 +URL: https://github.com/netty/netty-tcnative.git +Version: 2.0.0.Final +Date: March 9, 2017 +Revision: 28d9d70090f1b18927f4554621648cc1922d6e05 License: Apache 2.0 License File: NOT_SHIPPED Security Critical: no @@ -21,161 +20,16 @@ Local Modifications: -diff -ruN ./original/src/main/c/ssl.c ./src/third_party/netty-tcnative/src/c/ssl.c ---- ./original/src/main/c/ssl.c 2015-10-13 08:36:59.000000000 -0400 -+++ ./src/third_party/netty-tcnative/src/c/ssl.c 2016-01-04 10:18:31.729765992 -0500 -@@ -1821,7 +1821,7 @@ - verify = SSL_VERIFY_NONE; - - UNREFERENCED(o); -- TCN_ASSERT(ctx != 0); -+ TCN_ASSERT(c->ctx != 0); - c->verify_mode = level; - - if (c->verify_mode == SSL_CVERIFY_UNSET) - -diff --git a/c/ssl.c b/c/ssl.c -index 89e6cad..97c7982 100644 ---- a/c/ssl.c -+++ b/c/ssl.c -@@ -231,26 +231,38 @@ static const jint supported_ssl_opts = 0 - - static int ssl_tmp_key_init_rsa(int bits, int idx) - { --#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(OPENSSL_USE_DEPRECATED) -- if (!(SSL_temp_keys[idx] = -- RSA_generate_key(bits, RSA_F4, NULL, NULL))) { -+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) -+ return 0; -+#else -+ - #ifdef OPENSSL_FIPS -- /** -- * With FIPS mode short RSA keys cannot be -- * generated. -- */ -- if (bits < 1024) -- return 0; -- else --#endif -- return 1; -- } -- else { -+ /** -+ * Short RSA keys cannot be generated in FIPS mode. -+ */ -+ if (bits < 1024) - return 0; -- } --#else -- return 0; - #endif -+ -+ BIGNUM *e = BN_new(); -+ RSA *rsa = RSA_new(); -+ int ret = 1; -+ -+ if (e == NULL || -+ rsa == NULL || -+ !BN_set_word(e, RSA_F4) || -+ RSA_generate_key_ex(rsa, bits, e, NULL) != 1) { -+ goto err; -+ } -+ -+ SSL_temp_keys[idx] = rsa; -+ rsa = NULL; -+ ret = 0; -+ -+err: -+ BN_free(e); -+ RSA_free(rsa); -+ return ret; -+#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ - } - - static int ssl_tmp_key_init_dh(int bits, int idx) -@@ -610,45 +622,6 @@ int SSL_rand_seed(const char *file) - return RAND_status(); - } - --static int ssl_rand_make(const char *file, int len, int base64) --{ -- int r; -- int num = len; -- BIO *out = NULL; -- -- out = BIO_new(BIO_s_file()); -- if (out == NULL) -- return 0; -- if ((r = BIO_write_filename(out, (char *)file)) < 0) { -- BIO_free_all(out); -- return 0; -- } -- if (base64) { -- BIO *b64 = BIO_new(BIO_f_base64()); -- if (b64 == NULL) { -- BIO_free_all(out); -- return 0; -- } -- out = BIO_push(b64, out); -- } -- while (num > 0) { -- unsigned char buf[4096]; -- int len = num; -- if (len > sizeof(buf)) -- len = sizeof(buf); -- r = RAND_bytes(buf, len); -- if (r <= 0) { -- BIO_free_all(out); -- return 0; -- } -- BIO_write(out, buf, len); -- num -= len; -- } -- r = BIO_flush(out); -- BIO_free_all(out); -- return r > 0 ? 1 : 0; --} -- - TCN_IMPLEMENT_CALL(jint, SSL, initialize)(TCN_STDARGS, jstring engine) - { - int r = 0; -@@ -785,17 +758,6 @@ TCN_IMPLEMENT_CALL(jboolean, SSL, randSave)(TCN_STDARGS, jstring file) - return r ? JNI_TRUE : JNI_FALSE; - } - --TCN_IMPLEMENT_CALL(jboolean, SSL, randMake)(TCN_STDARGS, jstring file, -- jint length, jboolean base64) --{ -- TCN_ALLOC_CSTRING(file); -- int r; -- UNREFERENCED(o); -- r = ssl_rand_make(J2S(file), length, base64); -- TCN_FREE_CSTRING(file); -- return r ? JNI_TRUE : JNI_FALSE; --} -- - TCN_IMPLEMENT_CALL(void, SSL, randSet)(TCN_STDARGS, jstring file) - { - TCN_ALLOC_CSTRING(file); - diff --git a/c/sslcontext.c b/c/sslcontext.c -index 925ca2a..78afe61 100644 +index 5668298..25bfb6e 100644 --- a/c/sslcontext.c +++ b/c/sslcontext.c -@@ -1464,7 +1464,11 @@ static const char* authentication_method(const SSL* ssl) { - case SSL2_VERSION: - return SSL_TXT_RSA; - default: -+#if defined(OPENSSL_IS_BORINGSSL) -+ return cipher_authentication_method(SSL_get_pending_cipher(ssl)); -+#else - return cipher_authentication_method(ssl->s3->tmp.new_cipher); -+#endif - } - } - } +@@ -1178,7 +1178,7 @@ static int SSL_cert_verify(X509_STORE_CTX *ctx, void *arg) { + tcn_ssl_ctxt_t *c = SSL_get_app_data2(ssl); + TCN_ASSERT(c != NULL); + tcn_ssl_verify_config_t* verify_config = SSL_get_app_data4(ssl); +- TCN_ASSERT(verify_confg != NULL); ++ TCN_ASSERT(verify_config != NULL); - -025da0aad4f9c2fdeebb64bcebf11bbf2c12a2bd and -fd68c837b156ddb4b054e03d99a401e93068b34d were backported from upstream. + // Get a stack of all certs in the chain + STACK_OF(X509) *sk = ctx->untrusted;
diff --git a/third_party/netty4/README.chromium b/third_party/netty4/README.chromium index 5cce515..947623a7 100644 --- a/third_party/netty4/README.chromium +++ b/third_party/netty4/README.chromium
@@ -1,9 +1,9 @@ Name: Netty Short Name: netty URL: http://netty.io/ -SHA: f40598a04aae5fa4b24810f30aaaf4a61c9c4385 netty-4.1.0.Beta8.tar.bz2 -Version: 4.1.0.Beta8 -Date: November 10, 2015 +SHA: 3b0025e08168eebc97b232fef333a716dc4d42bd netty-4.1.9.Final.tar.bz2 +Version: 4.1.9.Final +Date: March 10, 2017 License: Apache 2.0 License File: NOT_SHIPPED Security Critical: no @@ -16,13 +16,4 @@ simplifies and streamlines network programming such as TCP and UDP socket server. Local Modifications: -Replaced netty-all jar files with the nightly build version -and deleted all 4.1.0.Beta8 version jars. - -URL: https://oss.sonatype.org/content/repositories/snapshots/io/netty/netty-all/4.1.0.CR1-SNAPSHOT/ -SHA: 2748f46eca4216a08e75dd9ce618f61ed067c4f5 netty-all-4.1.0.CR1-20160111.120759-50-sources.jar -Date: January 11, 2016 - -URL: https://oss.sonatype.org/content/repositories/snapshots/io/netty/netty-all/4.1.0.CR1-SNAPSHOT/ -SHA: 16cc4addd84c7fb3444e6d79f7d8cef74adefc7d netty-all-4.1.0.CR1-20160111.120759-50.jar -Date: January 11, 2016 +None
diff --git a/third_party/netty4/netty4.gni b/third_party/netty4/netty4.gni index bb17fc6d..27e045df 100644 --- a/third_party/netty4/netty4.gni +++ b/third_party/netty4/netty4.gni
@@ -4,4 +4,5 @@ # Defines location of netty4 jar file. -NETTY4_JAR_FILE = "//third_party/netty4/src/jar/all-in-one/netty-all-4.1.0.CR1-20160111.120759-50.jar" +NETTY4_JAR_FILE = + "//third_party/netty4/src/jar/all-in-one/netty-all-4.1.9.Final.jar"
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index a9336494..74b3d8b 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -722,7 +722,7 @@ ], 'android_cronet_data_reduction_proxy_release_bot_minimal_symbols_arm_no_neon': [ - 'android', 'cronet', 'data_reduction_proxy', 'release_bot', 'minimal_symbols', 'arm_no_neon', + 'android', 'cronet', 'release_bot', 'minimal_symbols', 'arm_no_neon', ], 'android_cronet_debug_static_bot_arm64': [ @@ -738,7 +738,7 @@ ], 'android_cronet_data_reduction_proxy_release_bot_minimal_symbols_arm_no_neon': [ - 'android', 'cronet', 'data_reduction_proxy', 'release_bot', 'minimal_symbols', 'arm_no_neon', + 'android', 'cronet', 'release_bot', 'minimal_symbols', 'arm_no_neon', ], 'android_cronet_debug_static_bot_arm64': [ @@ -1654,10 +1654,6 @@ 'cros_passthrough': True, }, - 'data_reduction_proxy': { - 'gn_args': 'cronet_enable_data_reduction_proxy_support=true', - }, - 'dcheck_always_on': { 'gn_args': 'dcheck_always_on=true', },
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 12b8f38..4913a17 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -9498,7 +9498,7 @@ </histogram> <histogram name="Cryptohome.DircryptoMigrationEndStatus" - enum="DircryptoMigrationStartStatus"> + enum="DircryptoMigrationEndStatus"> <owner>dspaid@chromium.org</owner> <summary> The status of the user home directory migration from ecryptfs to @@ -9528,6 +9528,14 @@ </summary> </histogram> +<histogram name="Cryptohome.HomedirEncryptionType" enum="HomedirEncryptionType"> + <owner>dspaid@chromium.org</owner> + <summary> + The encryption type used for a user's cryptohome directory. This is logged + each time the cryptohome is mounted. + </summary> +</histogram> + <histogram name="Cryptohome.MigrationToGaiaId" enum="CryptohomeMigrationToGaiaId"> <owner>alemate@chromium.org</owner> @@ -20821,6 +20829,11 @@ </summary> </histogram> +<histogram name="Feedback.RequestSource" enum="FeedbackSource"> + <owner>afakhry@chromium.org</owner> + <summary>Records the source that requested showing the feedback app.</summary> +</histogram> + <histogram name="FileBrowser.CloudImport.UserAction" enum="CloudImportUserAction"> <owner>smckay@google.com</owner> @@ -97389,6 +97402,17 @@ <int value="1970" label="GATTServerDisconnectedEvent"/> </enum> +<enum name="FeedbackSource" type="int"> + <int value="0" label="Arc App"/> + <int value="1" label="Ash"/> + <int value="2" label="Browser Command"/> + <int value="3" label="MD Settings About Page"/> + <int value="4" label="Old Settings About Page"/> + <int value="5" label="Profile Error Dialog"/> + <int value="6" label="SadTab Page"/> + <int value="7" label="Supervised User Interstitial"/> +</enum> + <enum name="FetchRequestMode" type="int"> <int value="0" label="SameOrigin"/> <int value="1" label="NoCORS"/> @@ -100048,6 +100072,11 @@ </int> </enum> +<enum name="HomedirEncryptionType" type="int"> + <int value="1" label="Ecryptfs"/> + <int value="2" label="Ext4 Dir Encryption"/> +</enum> + <enum name="HotwordAvailability" type="int"> <int value="0" label="Unavailable -- reason may be unknown"/> <int value="1" label="Available"/> @@ -119324,6 +119353,20 @@ <affected-histogram name="Autofill.SaveCreditCardPrompt"/> </histogram_suffixes> +<histogram_suffixes name="AutofillSaveCreditCardPromptPreviousUserDecision" + separator="."> + <suffix name="PreviouslyAccepted" + label="User had previously accepted save credit card prompt"/> + <suffix name="PreviouslyDenied" + label="User had previously denied save credit card prompt"/> + <affected-histogram name="Autofill.CreditCardInfoBar.Local"/> + <affected-histogram name="Autofill.CreditCardInfoBar.Server"/> + <affected-histogram name="Autofill.SaveCreditCardPrompt.Local.FirstShow"/> + <affected-histogram name="Autofill.SaveCreditCardPrompt.Local.Reshows"/> + <affected-histogram name="Autofill.SaveCreditCardPrompt.Upload.FirstShow"/> + <affected-histogram name="Autofill.SaveCreditCardPrompt.Upload.Reshows"/> +</histogram_suffixes> + <histogram_suffixes name="AutofillSaveCreditCardPromptShow" separator="."> <suffix name="FirstShow" label="first time prompt is shown for a single credit card submit"/>
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc index 1edf5a5d..e1b69559 100644 --- a/ui/aura/client/aura_constants.cc +++ b/ui/aura/client/aura_constants.cc
@@ -32,6 +32,7 @@ DEFINE_UI_CLASS_PROPERTY_KEY( bool, kAccessibilityFocusFallsbackToWidgetKey, true); +DEFINE_UI_CLASS_PROPERTY_KEY(bool, kActivateOnPointerKey, true); DEFINE_UI_CLASS_PROPERTY_KEY(bool, kAlwaysOnTopKey, false); DEFINE_UI_CLASS_PROPERTY_KEY(bool, kAnimationsDisabledKey, false); DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::ImageSkia, kAppIconKey, nullptr);
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h index bcfab7f..b67a543f0 100644 --- a/ui/aura/client/aura_constants.h +++ b/ui/aura/client/aura_constants.h
@@ -36,6 +36,11 @@ AURA_EXPORT extern const WindowProperty<bool>* const kAccessibilityFocusFallsbackToWidgetKey; +// A property key to store whether activation on pointer event is enabled or +// not. The default value is true, which means windows are activated when a +// pointer down event occurs on them. +AURA_EXPORT extern const WindowProperty<bool>* const kActivateOnPointerKey; + // A property key to store always-on-top flag. AURA_EXPORT extern const WindowProperty<bool>* const kAlwaysOnTopKey;
diff --git a/ui/aura/mus/in_flight_change.cc b/ui/aura/mus/in_flight_change.cc index 844d3f8..d806f5b 100644 --- a/ui/aura/mus/in_flight_change.cc +++ b/ui/aura/mus/in_flight_change.cc
@@ -181,24 +181,22 @@ window()->SetPropertyFromServer(property_name_, revert_value_.get()); } -// InFlightPredefinedCursorChange --------------------------------------------- +// InFlightCursorChange ---------------------------------------------------- -InFlightPredefinedCursorChange::InFlightPredefinedCursorChange( - WindowMus* window, - ui::mojom::CursorType revert_value) - : InFlightChange(window, ChangeType::PREDEFINED_CURSOR), +InFlightCursorChange::InFlightCursorChange(WindowMus* window, + const ui::CursorData& revert_value) + : InFlightChange(window, ChangeType::CURSOR), revert_cursor_(revert_value) {} -InFlightPredefinedCursorChange::~InFlightPredefinedCursorChange() {} +InFlightCursorChange::~InFlightCursorChange() {} -void InFlightPredefinedCursorChange::SetRevertValueFrom( - const InFlightChange& change) { +void InFlightCursorChange::SetRevertValueFrom(const InFlightChange& change) { revert_cursor_ = - static_cast<const InFlightPredefinedCursorChange&>(change).revert_cursor_; + static_cast<const InFlightCursorChange&>(change).revert_cursor_; } -void InFlightPredefinedCursorChange::Revert() { - window()->SetPredefinedCursorFromServer(revert_cursor_); +void InFlightCursorChange::Revert() { + window()->SetCursorFromServer(revert_cursor_); } // InFlightVisibleChange -------------------------------------------------------
diff --git a/ui/aura/mus/in_flight_change.h b/ui/aura/mus/in_flight_change.h index 50920e9..738237f8 100644 --- a/ui/aura/mus/in_flight_change.h +++ b/ui/aura/mus/in_flight_change.h
@@ -16,6 +16,7 @@ #include "base/optional.h" #include "cc/surfaces/local_surface_id.h" #include "ui/aura/window_observer.h" +#include "ui/base/cursor/cursor_data.h" #include "ui/base/ui_base_types.h" #include "ui/gfx/geometry/rect.h" @@ -46,7 +47,7 @@ NEW_TOP_LEVEL_WINDOW, NEW_WINDOW, OPACITY, - PREDEFINED_CURSOR, + CURSOR, PROPERTY, REMOVE_CHILD, REMOVE_TRANSIENT_WINDOW_FROM_PARENT, @@ -271,20 +272,19 @@ DISALLOW_COPY_AND_ASSIGN(InFlightPropertyChange); }; -class InFlightPredefinedCursorChange : public InFlightChange { +class InFlightCursorChange : public InFlightChange { public: - InFlightPredefinedCursorChange(WindowMus* window, - ui::mojom::CursorType revert_value); - ~InFlightPredefinedCursorChange() override; + InFlightCursorChange(WindowMus* window, const ui::CursorData& revert_value); + ~InFlightCursorChange() override; // InFlightChange: void SetRevertValueFrom(const InFlightChange& change) override; void Revert() override; private: - ui::mojom::CursorType revert_cursor_; + ui::CursorData revert_cursor_; - DISALLOW_COPY_AND_ASSIGN(InFlightPredefinedCursorChange); + DISALLOW_COPY_AND_ASSIGN(InFlightCursorChange); }; class InFlightVisibleChange : public InFlightChange {
diff --git a/ui/aura/mus/window_manager_delegate.h b/ui/aura/mus/window_manager_delegate.h index 0441963..917fe539 100644 --- a/ui/aura/mus/window_manager_delegate.h +++ b/ui/aura/mus/window_manager_delegate.h
@@ -48,7 +48,7 @@ virtual void SetFrameDecorationValues( ui::mojom::FrameDecorationValuesPtr values) = 0; virtual void SetNonClientCursor(Window* window, - ui::mojom::CursorType non_client_cursor) = 0; + const ui::CursorData& non_client_cursor) = 0; virtual void AddAccelerators( std::vector<ui::mojom::WmAcceleratorPtr> accelerators,
diff --git a/ui/aura/mus/window_mus.h b/ui/aura/mus/window_mus.h index 40e8b4a..af7692c 100644 --- a/ui/aura/mus/window_mus.h +++ b/ui/aura/mus/window_mus.h
@@ -81,7 +81,7 @@ const base::Optional<cc::LocalSurfaceId>& local_surface_id) = 0; virtual void SetVisibleFromServer(bool visible) = 0; virtual void SetOpacityFromServer(float opacity) = 0; - virtual void SetPredefinedCursorFromServer(ui::mojom::CursorType cursor) = 0; + virtual void SetCursorFromServer(const ui::CursorData& cursor) = 0; virtual void SetPropertyFromServer(const std::string& property_name, const std::vector<uint8_t>* data) = 0; virtual void SetFrameSinkIdFromServer(
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc index d5cec711..4c605a0 100644 --- a/ui/aura/mus/window_port_mus.cc +++ b/ui/aura/mus/window_port_mus.cc
@@ -69,12 +69,12 @@ window_tree_client_->SetImeVisibility(this, visible, std::move(state)); } -void WindowPortMus::SetPredefinedCursor(ui::mojom::CursorType cursor_id) { - if (cursor_id == predefined_cursor_) +void WindowPortMus::SetCursor(const ui::CursorData& cursor) { + if (cursor_.IsSameAs(cursor)) return; - window_tree_client_->SetPredefinedCursor(this, predefined_cursor_, cursor_id); - predefined_cursor_ = cursor_id; + window_tree_client_->SetCursor(this, cursor_, cursor); + cursor_ = cursor; } void WindowPortMus::SetEventTargetingPolicy( @@ -270,11 +270,10 @@ window_->layer()->SetOpacity(opacity); } -void WindowPortMus::SetPredefinedCursorFromServer( - ui::mojom::CursorType cursor) { +void WindowPortMus::SetCursorFromServer(const ui::CursorData& cursor) { // As this does nothing more than set the cursor we don't need to use // ServerChange. - predefined_cursor_ = cursor; + cursor_ = cursor; } void WindowPortMus::SetPropertyFromServer(
diff --git a/ui/aura/mus/window_port_mus.h b/ui/aura/mus/window_port_mus.h index ec0a6ac2..8c102005 100644 --- a/ui/aura/mus/window_port_mus.h +++ b/ui/aura/mus/window_port_mus.h
@@ -61,8 +61,8 @@ void SetTextInputState(mojo::TextInputStatePtr state); void SetImeVisibility(bool visible, mojo::TextInputStatePtr state); - ui::mojom::CursorType predefined_cursor() const { return predefined_cursor_; } - void SetPredefinedCursor(ui::mojom::CursorType cursor_id); + const ui::CursorData& cursor() const { return cursor_; } + void SetCursor(const ui::CursorData& cursor); // Sets the EventTargetingPolicy, default is TARGET_AND_DESCENDANTS. void SetEventTargetingPolicy(ui::mojom::EventTargetingPolicy policy); @@ -224,7 +224,7 @@ const base::Optional<cc::LocalSurfaceId>& local_surface_id) override; void SetVisibleFromServer(bool visible) override; void SetOpacityFromServer(float opacity) override; - void SetPredefinedCursorFromServer(ui::mojom::CursorType cursor) override; + void SetCursorFromServer(const ui::CursorData& cursor) override; void SetPropertyFromServer( const std::string& property_name, const std::vector<uint8_t>* property_data) override; @@ -286,7 +286,7 @@ cc::LocalSurfaceIdAllocator local_surface_id_allocator_; gfx::Size last_surface_size_; - ui::mojom::CursorType predefined_cursor_ = ui::mojom::CursorType::kNull; + ui::CursorData cursor_; DISALLOW_COPY_AND_ASSIGN(WindowPortMus); };
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc index d272bad..52b15cb 100644 --- a/ui/aura/mus/window_tree_client.cc +++ b/ui/aura/mus/window_tree_client.cc
@@ -302,14 +302,14 @@ tree_->SetCanFocus(WindowMus::Get(window)->server_id(), can_focus); } -void WindowTreeClient::SetPredefinedCursor(WindowMus* window, - ui::mojom::CursorType old_cursor, - ui::mojom::CursorType new_cursor) { +void WindowTreeClient::SetCursor(WindowMus* window, + const ui::CursorData& old_cursor, + const ui::CursorData& new_cursor) { DCHECK(tree_); const uint32_t change_id = ScheduleInFlightChange( - base::MakeUnique<InFlightPredefinedCursorChange>(window, old_cursor)); - tree_->SetPredefinedCursor(change_id, window->server_id(), new_cursor); + base::MakeUnique<InFlightCursorChange>(window, old_cursor)); + tree_->SetCursor(change_id, window->server_id(), new_cursor); } void WindowTreeClient::SetWindowTextInputState(WindowMus* window, @@ -1341,18 +1341,17 @@ focus_synchronizer_->SetFocusFromServer(focused_window); } -void WindowTreeClient::OnWindowPredefinedCursorChanged( - Id window_id, - ui::mojom::CursorType cursor) { +void WindowTreeClient::OnWindowCursorChanged(Id window_id, + ui::CursorData cursor) { WindowMus* window = GetWindowByServerId(window_id); if (!window) return; - InFlightPredefinedCursorChange new_change(window, cursor); + InFlightCursorChange new_change(window, cursor); if (ApplyServerChangeToExistingInFlightChange(new_change)) return; - window->SetPredefinedCursorFromServer(cursor); + window->SetCursorFromServer(cursor); } void WindowTreeClient::OnWindowSurfaceChanged( @@ -1770,10 +1769,10 @@ } void WindowTreeClient::SetNonClientCursor(Window* window, - ui::mojom::CursorType cursor_id) { + const ui::CursorData& cursor) { if (window_manager_client_) { window_manager_client_->WmSetNonClientCursor( - WindowMus::Get(window)->server_id(), cursor_id); + WindowMus::Get(window)->server_id(), cursor); } }
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h index 57616e9..0e5a550 100644 --- a/ui/aura/mus/window_tree_client.h +++ b/ui/aura/mus/window_tree_client.h
@@ -130,9 +130,9 @@ void SetCanAcceptDrops(WindowMus* window, bool can_accept_drops); void SetEventTargetingPolicy(WindowMus* window, ui::mojom::EventTargetingPolicy policy); - void SetPredefinedCursor(WindowMus* window, - ui::mojom::CursorType old_cursor, - ui::mojom::CursorType new_cursor); + void SetCursor(WindowMus* window, + const ui::CursorData& old_cursor, + const ui::CursorData& new_cursor); void SetWindowTextInputState(WindowMus* window, mojo::TextInputStatePtr state); void SetImeVisibility(WindowMus* window, @@ -384,8 +384,7 @@ uint32_t window_id, int64_t display_id) override; void OnWindowFocused(Id focused_window_id) override; - void OnWindowPredefinedCursorChanged(Id window_id, - ui::mojom::CursorType cursor) override; + void OnWindowCursorChanged(Id window_id, ui::CursorData cursor) override; void OnWindowSurfaceChanged(Id window_id, const cc::SurfaceInfo& surface_info) override; void OnDragDropStart( @@ -466,7 +465,7 @@ void SetFrameDecorationValues( ui::mojom::FrameDecorationValuesPtr values) override; void SetNonClientCursor(Window* window, - ui::mojom::CursorType cursor_id) override; + const ui::CursorData& cursor) override; void AddAccelerators(std::vector<ui::mojom::WmAcceleratorPtr> accelerators, const base::Callback<void(bool)>& callback) override; void RemoveAccelerator(uint32_t id) override;
diff --git a/ui/aura/test/mus/test_window_manager_client.cc b/ui/aura/test/mus/test_window_manager_client.cc index 02fec597..713c3cc 100644 --- a/ui/aura/test/mus/test_window_manager_client.cc +++ b/ui/aura/test/mus/test_window_manager_client.cc
@@ -53,9 +53,9 @@ void TestWindowManagerClient::WmSetFrameDecorationValues( ui::mojom::FrameDecorationValuesPtr values) {} -void TestWindowManagerClient::WmSetNonClientCursor( - uint32_t window_id, - ui::mojom::CursorType cursor_id) {} +void TestWindowManagerClient::WmSetNonClientCursor(uint32_t window_id, + ui::CursorData cursor_data) { +} void TestWindowManagerClient::OnWmCreatedTopLevelWindow( uint32_t change_id,
diff --git a/ui/aura/test/mus/test_window_manager_client.h b/ui/aura/test/mus/test_window_manager_client.h index a68bb39..e46d314 100644 --- a/ui/aura/test/mus/test_window_manager_client.h +++ b/ui/aura/test/mus/test_window_manager_client.h
@@ -47,7 +47,7 @@ void WmSetFrameDecorationValues( ui::mojom::FrameDecorationValuesPtr values) override; void WmSetNonClientCursor(uint32_t window_id, - ui::mojom::CursorType cursor_id) override; + ui::CursorData cursor_data) override; void OnWmCreatedTopLevelWindow(uint32_t change_id, Id transport_window_id) override; void OnAcceleratorAck(
diff --git a/ui/aura/test/mus/test_window_tree.cc b/ui/aura/test/mus/test_window_tree.cc index 603d61a..fdf553f 100644 --- a/ui/aura/test/mus/test_window_tree.cc +++ b/ui/aura/test/mus/test_window_tree.cc
@@ -254,9 +254,9 @@ uint32_t window_id, ui::mojom::EventTargetingPolicy policy) {} -void TestWindowTree::SetPredefinedCursor(uint32_t change_id, - uint32_t window_id, - ui::mojom::CursorType cursor_id) { +void TestWindowTree::SetCursor(uint32_t change_id, + Id transport_window_id, + ui::CursorData cursor_data) { OnChangeReceived(change_id); }
diff --git a/ui/aura/test/mus/test_window_tree.h b/ui/aura/test/mus/test_window_tree.h index 916e8a1d..5f7bc7c 100644 --- a/ui/aura/test/mus/test_window_tree.h +++ b/ui/aura/test/mus/test_window_tree.h
@@ -175,9 +175,9 @@ void SetCanFocus(uint32_t window_id, bool can_focus) override; void SetEventTargetingPolicy(uint32_t window_id, ui::mojom::EventTargetingPolicy policy) override; - void SetPredefinedCursor(uint32_t change_id, - uint32_t window_id, - ui::mojom::CursorType cursor_id) override; + void SetCursor(uint32_t change_id, + Id transport_window_id, + ui::CursorData cursor_data) override; void SetWindowTextInputState(uint32_t window_id, mojo::TextInputStatePtr state) override; void SetImeVisibility(uint32_t window_id,
diff --git a/ui/base/cursor/cursor_data.cc b/ui/base/cursor/cursor_data.cc index c49400e..6c39f5a 100644 --- a/ui/base/cursor/cursor_data.cc +++ b/ui/base/cursor/cursor_data.cc
@@ -30,10 +30,14 @@ CursorData::CursorData(const CursorData& cursor) = default; +CursorData::CursorData(CursorData&& cursor) = default; + CursorData::~CursorData() {} CursorData& CursorData::operator=(const CursorData& cursor) = default; +CursorData& CursorData::operator=(CursorData&& cursor) = default; + bool CursorData::IsType(CursorType cursor_type) const { return cursor_type_ == cursor_type; }
diff --git a/ui/base/cursor/cursor_data.h b/ui/base/cursor/cursor_data.h index c3879692d..6b3f5d2 100644 --- a/ui/base/cursor/cursor_data.h +++ b/ui/base/cursor/cursor_data.h
@@ -45,9 +45,11 @@ float scale_factor, const base::TimeDelta& frame_delay); CursorData(const CursorData& cursor); + CursorData(CursorData&& cursor); ~CursorData(); CursorData& operator=(const CursorData& cursor); + CursorData& operator=(CursorData&& cursor); CursorType cursor_type() const { return cursor_type_; } const base::TimeDelta& frame_delay() const { return frame_delay_; }
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js index 544b6600..2955630 100644 --- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js +++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -548,6 +548,15 @@ var shareEntries; var taskId = this.fileOperationManager_.generateTaskId(); + var item = new ProgressCenterItem(); + item.id = taskId; + if (toMove) { + item.message = strf('MOVE_ITEMS_REMAINING', sourceURLs.length); + } else { + item.message = strf('COPY_ITEMS_REMAINING', sourceURLs.length); + } + this.progressCenter_.updateItem(item); + FileTransferController.URLsToEntriesWithAccess(sourceURLs) .then( /**
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc index a5ad059..1d054ac 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.cc +++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -35,6 +35,10 @@ #include "ui/wm/core/window_util.h" #include "ui/wm/public/activation_client.h" +#if defined(USE_OZONE) +#include "ui/base/cursor/ozone/cursor_data_factory_ozone.h" +#endif + namespace views { namespace { @@ -131,8 +135,21 @@ void SetCursor(gfx::NativeCursor cursor, wm::NativeCursorManagerDelegate* delegate) override { - aura::WindowPortMus::Get(window_)->SetPredefinedCursor( - ui::mojom::CursorType(cursor.native_type())); + ui::CursorData mojo_cursor; + if (cursor.platform()) { +#if defined(USE_OZONE) + mojo_cursor = + ui::CursorDataFactoryOzone::GetCursorData(cursor.platform()); +#else + NOTIMPLEMENTED() + << "Can't pass native platform cursors on non-ozone platforms"; + mojo_cursor = ui::CursorData(ui::CursorType::kPointer); +#endif + } else { + mojo_cursor = ui::CursorData(cursor.native_type()); + } + + aura::WindowPortMus::Get(window_)->SetCursor(mojo_cursor); delegate->CommitCursor(cursor); } @@ -143,8 +160,8 @@ if (visible) { SetCursor(delegate->GetCursor(), delegate); } else { - aura::WindowPortMus::Get(window_)->SetPredefinedCursor( - ui::mojom::CursorType::kNone); + aura::WindowPortMus::Get(window_)->SetCursor( + ui::CursorData(ui::CursorType::kNone)); } }
diff --git a/ui/wm/core/base_focus_rules.cc b/ui/wm/core/base_focus_rules.cc index e38aa2e5..70086b2 100644 --- a/ui/wm/core/base_focus_rules.cc +++ b/ui/wm/core/base_focus_rules.cc
@@ -16,7 +16,7 @@ aura::Window* GetFocusedWindow(aura::Window* context) { aura::client::FocusClient* focus_client = aura::client::GetFocusClient(context); - return focus_client ? focus_client->GetFocusedWindow() : NULL; + return focus_client ? focus_client->GetFocusedWindow() : nullptr; } } // namespace @@ -24,11 +24,9 @@ //////////////////////////////////////////////////////////////////////////////// // BaseFocusRules, protected: -BaseFocusRules::BaseFocusRules() { -} +BaseFocusRules::BaseFocusRules() = default; -BaseFocusRules::~BaseFocusRules() { -} +BaseFocusRules::~BaseFocusRules() = default; bool BaseFocusRules::IsWindowConsideredVisibleForActivation( aura::Window* window) const { @@ -78,7 +76,8 @@ return !GetModalTransient(window); } -bool BaseFocusRules::CanFocusWindow(aura::Window* window) const { +bool BaseFocusRules::CanFocusWindow(aura::Window* window, + const ui::Event* event) const { // It is possible to focus a NULL window, it is equivalent to clearing focus. if (!window) return true; @@ -101,7 +100,7 @@ parent = parent->parent(); child = child->parent(); } - return NULL; + return nullptr; } aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const { @@ -133,11 +132,11 @@ parent = parent->parent(); child = child->parent(); } - return NULL; + return nullptr; } aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const { - if (CanFocusWindow(window)) + if (CanFocusWindow(window, nullptr)) return window; // |window| may be in a hierarchy that is non-activatable, in which case we @@ -150,7 +149,7 @@ if (toplevel) activatable = GetNextActivatableWindow(toplevel); if (!activatable) - return NULL; + return nullptr; } if (!activatable->Contains(window)) { @@ -161,7 +160,7 @@ return activatable->Contains(focused) ? focused : activatable; } - while (window && !CanFocusWindow(window)) + while (window && !CanFocusWindow(window, nullptr)) window = window->parent(); return window; } @@ -172,7 +171,7 @@ // Can be called from the RootWindow's destruction, which has a NULL parent. if (!ignore->parent()) - return NULL; + return nullptr; // In the basic scenarios handled by BasicFocusRules, the pool of activatable // windows is limited to the |ignore|'s siblings. @@ -188,7 +187,7 @@ if (CanActivateWindow(cur)) return cur; } - return NULL; + return nullptr; } } // namespace wm
diff --git a/ui/wm/core/base_focus_rules.h b/ui/wm/core/base_focus_rules.h index 0e84e29..990a368 100644 --- a/ui/wm/core/base_focus_rules.h +++ b/ui/wm/core/base_focus_rules.h
@@ -28,7 +28,8 @@ // Overridden from FocusRules: bool IsToplevelWindow(aura::Window* window) const override; bool CanActivateWindow(aura::Window* window) const override; - bool CanFocusWindow(aura::Window* window) const override; + bool CanFocusWindow(aura::Window* window, + const ui::Event* event) const override; aura::Window* GetToplevelWindow(aura::Window* window) const override; aura::Window* GetActivatableWindow(aura::Window* window) const override; aura::Window* GetFocusableWindow(aura::Window* window) const override;
diff --git a/ui/wm/core/focus_controller.cc b/ui/wm/core/focus_controller.cc index 230de21..68b6d80 100644 --- a/ui/wm/core/focus_controller.cc +++ b/ui/wm/core/focus_controller.cc
@@ -38,8 +38,8 @@ // FocusController, public: FocusController::FocusController(FocusRules* rules) - : active_window_(NULL), - focused_window_(NULL), + : active_window_(nullptr), + focused_window_(nullptr), updating_focus_(false), updating_activation_(false), rules_(rules), @@ -47,8 +47,7 @@ DCHECK(rules); } -FocusController::~FocusController() { -} +FocusController::~FocusController() = default; //////////////////////////////////////////////////////////////////////////////// // FocusController, aura::client::ActivationClient implementation: @@ -127,7 +126,8 @@ void FocusController::OnMouseEvent(ui::MouseEvent* event) { if (event->type() == ui::ET_MOUSE_PRESSED && !event->handled()) - WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target())); + WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()), + event); } void FocusController::OnScrollEvent(ui::ScrollEvent* event) { @@ -140,7 +140,8 @@ if (event->type() == ui::ET_GESTURE_BEGIN && event->details().touch_points() == 1 && !event->handled()) { - WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target())); + WindowFocusedFromInputEvent(static_cast<aura::Window*>(event->target()), + event); } } @@ -196,7 +197,7 @@ // that the rules could redirect activation activation and/or focus. aura::Window* focusable = rules_->GetFocusableWindow(window); aura::Window* activatable = - focusable ? rules_->GetActivatableWindow(focusable) : NULL; + focusable ? rules_->GetActivatableWindow(focusable) : nullptr; // We need valid focusable/activatable windows in the event we're not clearing // focus. "Clearing focus" is inferred by whether or not |window| passed to @@ -224,7 +225,7 @@ void FocusController::SetFocusedWindow(aura::Window* window) { if (updating_focus_ || window == focused_window_) return; - DCHECK(rules_->CanFocusWindow(window)); + DCHECK(rules_->CanFocusWindow(window, nullptr)); if (window) DCHECK_EQ(window, rules_->GetFocusableWindow(window)); @@ -247,7 +248,7 @@ for (auto& observer : focus_observers_) { observer.OnWindowFocused( focused_window_, - window_tracker.Contains(lost_focus) ? lost_focus : NULL); + window_tracker.Contains(lost_focus) ? lost_focus : nullptr); } if (window_tracker.Contains(lost_focus)) { aura::client::FocusChangeObserver* observer = @@ -260,7 +261,7 @@ if (observer) { observer->OnWindowFocused( focused_window_, - window_tracker.Contains(lost_focus) ? lost_focus : NULL); + window_tracker.Contains(lost_focus) ? lost_focus : nullptr); } } @@ -300,7 +301,7 @@ if (active_window_) StackActiveWindow(); - aura::client::ActivationChangeObserver* observer = NULL; + aura::client::ActivationChangeObserver* observer = nullptr; if (window_tracker.Contains(lost_activation)) { observer = aura::client::GetActivationChangeObserver(lost_activation); if (observer) @@ -310,12 +311,12 @@ if (observer) { observer->OnWindowActivated( reason, active_window_, - window_tracker.Contains(lost_activation) ? lost_activation : NULL); + window_tracker.Contains(lost_activation) ? lost_activation : nullptr); } for (auto& observer : activation_observers_) { observer.OnWindowActivated( reason, active_window_, - window_tracker.Contains(lost_activation) ? lost_activation : NULL); + window_tracker.Contains(lost_activation) ? lost_activation : nullptr); } } @@ -338,7 +339,7 @@ aura::Window* next_activatable = rules_->GetNextActivatableWindow(window); SetActiveWindow(aura::client::ActivationChangeObserver::ActivationReason:: WINDOW_DISPOSITION_CHANGED, - NULL, next_activatable); + nullptr, next_activatable); if (!(active_window_ && active_window_->Contains(focused_window_))) SetFocusedWindow(next_activatable); } else if (window->Contains(focused_window_)) { @@ -347,11 +348,12 @@ } } -void FocusController::WindowFocusedFromInputEvent(aura::Window* window) { +void FocusController::WindowFocusedFromInputEvent(aura::Window* window, + const ui::Event* event) { // Only focus |window| if it or any of its parents can be focused. Otherwise // FocusWindow() will focus the topmost window, which may not be the // currently focused one. - if (rules_->CanFocusWindow(GetToplevelWindow(window))) { + if (rules_->CanFocusWindow(GetToplevelWindow(window), event)) { FocusAndActivateWindow( aura::client::ActivationChangeObserver::ActivationReason::INPUT_EVENT, window);
diff --git a/ui/wm/core/focus_controller.h b/ui/wm/core/focus_controller.h index 66b2b8d..c59003f0 100644 --- a/ui/wm/core/focus_controller.h +++ b/ui/wm/core/focus_controller.h
@@ -116,7 +116,8 @@ // Called when an attempt is made to focus or activate a window via an input // event targeted at that window. Rules determine the best focusable window // for the input window. - void WindowFocusedFromInputEvent(aura::Window* window); + void WindowFocusedFromInputEvent(aura::Window* window, + const ui::Event* event); aura::Window* active_window_; aura::Window* focused_window_;
diff --git a/ui/wm/core/focus_controller_unittest.cc b/ui/wm/core/focus_controller_unittest.cc index 110a47c8..169c01c32 100644 --- a/ui/wm/core/focus_controller_unittest.cc +++ b/ui/wm/core/focus_controller_unittest.cc
@@ -335,9 +335,11 @@ CanFocusOrActivate(window) || window->Contains(focus_restriction_); return can_activate ? BaseFocusRules::CanActivateWindow(window) : false; } - bool CanFocusWindow(aura::Window* window) const override { - return CanFocusOrActivate(window) ? - BaseFocusRules::CanFocusWindow(window) : false; + bool CanFocusWindow(aura::Window* window, + const ui::Event* event) const override { + return CanFocusOrActivate(window) + ? BaseFocusRules::CanFocusWindow(window, event) + : false; } aura::Window* GetActivatableWindow(aura::Window* window) const override { return BaseFocusRules::GetActivatableWindow(
diff --git a/ui/wm/core/focus_rules.h b/ui/wm/core/focus_rules.h index cb9a4ddb..b8d0874 100644 --- a/ui/wm/core/focus_rules.h +++ b/ui/wm/core/focus_rules.h
@@ -11,6 +11,10 @@ class Window; } +namespace ui { +class Event; +} + namespace wm { // Implemented by an object that establishes the rules about what can be @@ -26,9 +30,11 @@ virtual bool IsToplevelWindow(aura::Window* window) const = 0; // Returns true if |window| can be activated or focused. virtual bool CanActivateWindow(aura::Window* window) const = 0; - // For CanFocusWindow(), NULL is supported, because NULL is a valid focusable - // window (in the case of clearing focus). - virtual bool CanFocusWindow(aura::Window* window) const = 0; + // For CanFocusWindow(), NULL window is supported, because NULL is a valid + // focusable window (in the case of clearing focus). + // If |event| is non-null it is the event triggering the focus change. + virtual bool CanFocusWindow(aura::Window* window, + const ui::Event* event) const = 0; // Returns the toplevel window containing |window|. Not all toplevel windows // are activatable, call GetActivatableWindow() instead to return the