diff --git a/DEPS b/DEPS index fdc6aaa..84579bba 100644 --- a/DEPS +++ b/DEPS
@@ -146,7 +146,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': '13c48a77b19c1455c2d3f5a73d056ee8c636e406', + 'v8_revision': 'ffcc6abeb7796e08165267d860887e8fe865f233', # 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. @@ -154,7 +154,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '3fe8c3a3039670535efcc10527ff9cd1b5bf67df', + 'angle_revision': '4e71b2bc254677bdeac521a371402a92f6747776', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -162,7 +162,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': 'babd1d4ac7c4060fb907ac90ee08f52c603c6358', + 'pdfium_revision': '808e9b88cf2e17fc4fe8cbfe6454e0680edd099d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -177,7 +177,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling googletest # and whatever else without interference from each other. - 'googletest_revision': 'd7003576dd133856432e2e07340f45926242cc3a', + 'googletest_revision': '437e1008c97b6bf595fec85da42c6925babd96b2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling lighttpd # and whatever else without interference from each other. @@ -205,7 +205,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': '123c46068daa0b5660f02168df9b76a2a255ef71', + 'catapult_revision': '5cc5f6ebf6015e0b69d04148f07aa33abe8a4b76', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -806,7 +806,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'ad2a337ea4a61727f898d8d18eb2aae3a2e13027', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a9ca4d92eba0effcf4cab93d6d8e6019696321d3', 'condition': 'checkout_linux', }, @@ -1191,7 +1191,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'cdf9e8af571361f67af4df2ff051aaeba89c950c', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '579543531e4b15861bb2f1975e39d55aec4f7b5f', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1310,7 +1310,7 @@ Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f', 'src/third_party/snappy/src': - Var('chromium_git') + '/external/github.com/google/snappy.git' + '@' + '3f194acb57e0487531c96b97af61dcbd025a78a3', + Var('chromium_git') + '/external/github.com/google/snappy.git' + '@' + '156cd8939c5fba7fa68ae08db843377ecc07b4b5', 'src/third_party/sqlite4java': { 'packages': [ @@ -1400,7 +1400,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@75b74536acd5cf16f92f6e9864d1ba17afcf51cc', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e46877813496a66cdc6d74a0d04f9573e52daca8', 'condition': 'checkout_src_internal', },
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 2f43503..fda251c5 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -478,7 +478,7 @@ # * Sequence of paths to *not* check (regexps). _BANNED_CPP_FUNCTIONS = ( ( - r'\bNULL\b', + r'/\bNULL\b', ( 'New code should not use NULL. Use nullptr instead.', ), @@ -498,7 +498,7 @@ (), ), ( - r'XSelectInput|CWEventMask|XCB_CW_EVENT_MASK', + r'/XSelectInput|CWEventMask|XCB_CW_EVENT_MASK', ( 'Chrome clients wishing to select events on X windows should use', 'ui::XScopedEventSelector. It is safe to ignore this warning only if', @@ -513,7 +513,7 @@ ), ), ( - r'XInternAtom|xcb_intern_atom', + r'/XInternAtom|xcb_intern_atom', ( 'Use gfx::GetAtom() instead of interning atoms directly.', ), @@ -707,7 +707,7 @@ (), ), ( - r'std::regex', + 'std::regex', ( 'Using std::regex adds unnecessary binary size to Chrome. Please use', 're2::RE2 instead (crbug.com/755321)', @@ -935,7 +935,7 @@ (), ), ( - r'RunThisRunLoop', + 'RunThisRunLoop', ( 'RunThisRunLoop is deprecated, use RunLoop directly instead.', ), @@ -943,7 +943,7 @@ (), ), ( - r'RunAllPendingInMessageLoop()', + 'RunAllPendingInMessageLoop()', ( "Prefer RunLoop over RunAllPendingInMessageLoop, please contact gab@", "if you're convinced you need this.", @@ -952,7 +952,7 @@ (), ), ( - r'RunAllPendingInMessageLoop(BrowserThread', + 'RunAllPendingInMessageLoop(BrowserThread', ( 'RunAllPendingInMessageLoop is deprecated. Use RunLoop for', 'BrowserThread::UI, TestBrowserThreadBundle::RunIOThreadUntilIdle', @@ -971,7 +971,7 @@ (), ), ( - r'GetDeferredQuitTaskForRunLoop', + 'GetDeferredQuitTaskForRunLoop', ( "GetDeferredQuitTaskForRunLoop shouldn't be needed, please contact", "gab@ if you found a use case where this is the only solution.", @@ -1011,7 +1011,7 @@ ), ), ( - r'std::random_shuffle', + 'std::random_shuffle', ( 'std::random_shuffle is deprecated in C++14, and removed in C++17. Use', 'base::RandomShuffle instead.'
diff --git a/WATCHLISTS b/WATCHLISTS index 737203c..add4f7b3 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -837,7 +837,12 @@ 'filepath': 'tools/perf/contrib/cros_benchmarks', }, 'crostini': { - 'filepath': 'crostini', + 'filepath': 'cicerone'\ + '|components/exo'\ + '|concierge'\ + '|crostini'\ + '|guest_os'\ + '|plugin_vm', }, 'cups_printing' : { 'filepath': 'chrome/browser/resources/settings/printing_page/'\
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index a554873..f5d3487b 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1195,8 +1195,6 @@ "wm/tablet_mode/internal_input_devices_event_blocker.h", "wm/tablet_mode/scoped_skip_user_session_blocked_check.cc", "wm/tablet_mode/scoped_skip_user_session_blocked_check.h", - "wm/tablet_mode/tablet_mode_backdrop_delegate_impl.cc", - "wm/tablet_mode/tablet_mode_backdrop_delegate_impl.h", "wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc", "wm/tablet_mode/tablet_mode_controller.cc", "wm/tablet_mode/tablet_mode_event_handler.cc", @@ -1252,7 +1250,6 @@ "wm/work_area_insets.h", "wm/workspace/backdrop_controller.cc", "wm/workspace/backdrop_controller.h", - "wm/workspace/backdrop_delegate.h", "wm/workspace/magnetism_matcher.cc", "wm/workspace/magnetism_matcher.h", "wm/workspace/multi_window_resize_controller.cc", @@ -1643,7 +1640,6 @@ "keyboard/keyboard_controller_impl_unittest.cc", "keyboard/virtual_keyboard_controller_unittest.cc", "keyboard/virtual_keyboard_unittest.cc", - "kiosk_next/kiosk_next_home_controller_unittest.cc", "kiosk_next/kiosk_next_shell_controller_unittest.cc", "kiosk_next/kiosk_next_shell_test_util.cc", "kiosk_next/kiosk_next_shell_test_util.h", @@ -2185,6 +2181,7 @@ public_deps = [ "//ash", + "//dbus", "//services/service_manager/public/cpp/test:test_support", "//testing/gtest", "//third_party/blink/public:blink_headers",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 07c5f7f3..b8e4b19 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -737,7 +737,7 @@ <!-- Virtual Desks --> <message name="IDS_ASH_DESKS_NEW_DESK_BUTTON" desc="The label of the new virtual desk (a.k.a. workspaces) button."> - New Desk + New desk </message> <message name="IDS_ASH_DESKS_DESK_1_MINI_VIEW_TITLE" desc="The label of the first virtual desk thumbnail."> Desk 1
diff --git a/ash/ash_strings_grd/IDS_ASH_DESKS_NEW_DESK_BUTTON.png.sha1 b/ash/ash_strings_grd/IDS_ASH_DESKS_NEW_DESK_BUTTON.png.sha1 index 030473f..e8de1b4 100644 --- a/ash/ash_strings_grd/IDS_ASH_DESKS_NEW_DESK_BUTTON.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_DESKS_NEW_DESK_BUTTON.png.sha1
@@ -1 +1 @@ -8254d07d8a4676a52a79a98e0287ea5f80843262 \ No newline at end of file +2811b931f24f85df00b6918842a8e381dad7e27e \ No newline at end of file
diff --git a/ash/autoclick/autoclick_controller.cc b/ash/autoclick/autoclick_controller.cc index fe6e1f0d..980360e 100644 --- a/ash/autoclick/autoclick_controller.cc +++ b/ash/autoclick/autoclick_controller.cc
@@ -268,8 +268,8 @@ // TODO(katie): Don't call this on the very first time scrollable bounds // are found for each time the type is changed to scroll. We want the // default first position of the scrollbar to be next to the menu bubble. - // TODO(katie): Set the scroll bubble position using the bounds. - menu_bubble_controller_->SetScrollPoint(scroll_location_); + menu_bubble_controller_->SetScrollPosition(bounds_in_screen, + scroll_location_); } void AutoclickController::UpdateAutoclickMenuBoundsIfNeeded() {
diff --git a/ash/kiosk_next/kiosk_next_home_controller_unittest.cc b/ash/kiosk_next/kiosk_next_home_controller_unittest.cc deleted file mode 100644 index 10ec17c..0000000 --- a/ash/kiosk_next/kiosk_next_home_controller_unittest.cc +++ /dev/null
@@ -1,116 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/kiosk_next/kiosk_next_home_controller.h" - -#include "ash/home_screen/home_screen_controller.h" -#include "ash/kiosk_next/kiosk_next_shell_test_util.h" -#include "ash/kiosk_next/mock_kiosk_next_shell_client.h" -#include "ash/public/cpp/app_types.h" -#include "ash/public/cpp/ash_features.h" -#include "ash/shell.h" -#include "ash/test/ash_test_base.h" -#include "ash/wm/overview/overview_controller.h" -#include "ash/wm/window_state.h" -#include "base/test/scoped_feature_list.h" -#include "ui/aura/client/aura_constants.h" -#include "ui/aura/client/window_types.h" -#include "ui/aura/test/test_window_delegate.h" -#include "ui/base/hit_test.h" -#include "ui/events/test/event_generator.h" - -namespace ash { -namespace { - -class KioskNextHomeControllerTest : public AshTestBase { - public: - KioskNextHomeControllerTest() = default; - ~KioskNextHomeControllerTest() override = default; - - void SetUp() override { - scoped_feature_list_.InitAndEnableFeature(features::kKioskNextShell); - set_start_session(false); - AshTestBase::SetUp(); - client_ = std::make_unique<MockKioskNextShellClient>(); - LogInKioskNextUser(GetSessionControllerClient()); - SetUpHomeWindow(); - } - - void TearDown() override { - home_screen_window_.reset(); - client_.reset(); - AshTestBase::TearDown(); - } - - void SetUpHomeWindow() { - auto* delegate = - aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(); - - home_screen_window_.reset( - CreateTestWindowInShellWithDelegate(delegate, 0, gfx::Rect())); - home_screen_window_->SetProperty(aura::client::kAppType, - static_cast<int>(AppType::CHROME_APP)); - home_screen_window_->set_owned_by_parent(false); - Shell::GetContainer(Shell::GetPrimaryRootWindow(), - kShellWindowId_HomeScreenContainer) - ->AddChild(home_screen_window_.get()); - - auto* window_state = wm::GetWindowState(home_screen_window_.get()); - window_state->Maximize(); - home_screen_window_->Show(); - } - - // TestWindowDelegate always returns its |window_component_| when - // TestWindowDelegate::GetNonClientComponent(const gfx::Point& point) is - // called, regardless of the location. Therefore individual tests have to set - // the |window_component_|. KioskNextHomeController's event handler starts - // overview only if the window component which the gesture event touches is - // HTCLIENT. - void SetWindowComponent(int component) { - auto* delegate = static_cast<aura::test::TestWindowDelegate*>( - home_screen_window_->delegate()); - delegate->set_window_component(component); - } - - protected: - std::unique_ptr<aura::Window> home_screen_window_; - std::unique_ptr<MockKioskNextShellClient> client_; - base::test::ScopedFeatureList scoped_feature_list_; - - private: - DISALLOW_COPY_AND_ASSIGN(KioskNextHomeControllerTest); -}; - -TEST_F(KioskNextHomeControllerTest, CheckWindows) { - auto* kiosk_next_home_controller = - Shell::Get()->home_screen_controller()->delegate(); - - EXPECT_EQ(kiosk_next_home_controller->GetHomeScreenWindow(), - home_screen_window_.get()); -} - -TEST_F(KioskNextHomeControllerTest, TestGestureToOverview) { - SetWindowComponent(HTCLIENT); - - ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); - - generator.GestureScrollSequence(gfx::Point(50, 0), gfx::Point(50, 20), - base::TimeDelta::FromMilliseconds(10), 10); - - EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); -} - -TEST_F(KioskNextHomeControllerTest, TestGestureToNoOverview) { - SetWindowComponent(HTNOWHERE); - - ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); - - generator.GestureScrollSequence(gfx::Point(50, 0), gfx::Point(50, 20), - base::TimeDelta::FromMilliseconds(10), 10); - - EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); -} - -} // namespace -} // namespace ash
diff --git a/ash/multi_user/multi_user_window_manager_impl.cc b/ash/multi_user/multi_user_window_manager_impl.cc index f43ce74..a7440e5 100644 --- a/ash/multi_user/multi_user_window_manager_impl.cc +++ b/ash/multi_user/multi_user_window_manager_impl.cc
@@ -530,7 +530,8 @@ bool unowned_view_state = visibility_item->second; transient_window_to_visibility_.erase(visibility_item); - if (unowned_view_state && !window->IsVisible()) { + if (unowned_view_state && !window->IsVisible() && + desks_util::BelongsToActiveDesk(window)) { // To prevent these commands from being recorded as any other commands, we // are suppressing any window entry changes while this is going on. // Instead of calling SetWindowVisible, only show gets called here since all
diff --git a/ash/shelf/back_button_unittest.cc b/ash/shelf/back_button_unittest.cc index 51f1479..a279527 100644 --- a/ash/shelf/back_button_unittest.cc +++ b/ash/shelf/back_button_unittest.cc
@@ -9,18 +9,13 @@ #include "ash/accelerators/accelerator_controller_impl.h" #include "ash/app_list/test/app_list_test_helper.h" #include "ash/app_list/views/app_list_view.h" -#include "ash/kiosk_next/kiosk_next_shell_test_util.h" -#include "ash/kiosk_next/mock_kiosk_next_shell_client.h" -#include "ash/public/cpp/ash_features.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_view.h" #include "ash/shelf/shelf_view_test_api.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/overview_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/run_loop.h" -#include "base/test/scoped_feature_list.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/test_accelerator_target.h" #include "ui/events/test/event_generator.h" @@ -124,72 +119,4 @@ EXPECT_EQ(1, target_back_release.accelerator_count()); } -class KioskNextBackButtonTest : public BackButtonTest { - public: - KioskNextBackButtonTest() { - scoped_feature_list_.InitAndEnableFeature(features::kKioskNextShell); - } - - void SetUp() override { - set_start_session(false); - BackButtonTest::SetUp(); - client_ = std::make_unique<MockKioskNextShellClient>(); - } - - void TearDown() override { - client_.reset(); - BackButtonTest::TearDown(); - } - - void SimulateKioskNextSession() { - LogInKioskNextUser(GetSessionControllerClient()); - - // Update test_api_ because its reference to ShelfView is outdated. - test_api_ = std::make_unique<ShelfViewTestAPI>( - GetPrimaryShelf()->GetShelfViewForTesting()); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<MockKioskNextShellClient> client_; - - DISALLOW_COPY_AND_ASSIGN(KioskNextBackButtonTest); -}; - -TEST_F(KioskNextBackButtonTest, BackKeySequenceGenerated) { - SimulateKioskNextSession(); - - // Tablet mode should be enabled in Kiosk Next. - ASSERT_TRUE(Shell::Get()->tablet_mode_controller()->InTabletMode()); - test_api()->RunMessageLoopUntilAnimationsDone(); - - // Enter Overview mode, since the shelf view is hidden from the Kiosk Next - // home screen. - OverviewController* overview_controller = Shell::Get()->overview_controller(); - ASSERT_TRUE(overview_controller->StartOverview()); - ASSERT_TRUE(overview_controller->InOverviewSession()); - test_api()->RunMessageLoopUntilAnimationsDone(); - - // Register an accelerator that looks for back releases. - ui::Accelerator accelerator_back_release(ui::VKEY_BROWSER_BACK, ui::EF_NONE); - accelerator_back_release.set_key_state(ui::Accelerator::KeyState::RELEASED); - ui::TestAcceleratorTarget target_back_release; - Shell::Get()->accelerator_controller()->Register({accelerator_back_release}, - &target_back_release); - - // Verify that when pressing down the back button, the accelerator is not - // triggered yet. - ui::test::EventGenerator* generator = GetEventGenerator(); - generator->MoveMouseTo(back_button()->GetBoundsInScreen().CenterPoint()); - generator->PressLeftButton(); - EXPECT_EQ(0, target_back_release.accelerator_count()); - EXPECT_TRUE(overview_controller->InOverviewSession()); - - // Verify that by releasing the back button, the accelerator is triggered, - // exiting Overview mode and sending a release event. - generator->ReleaseLeftButton(); - EXPECT_EQ(1, target_back_release.accelerator_count()); - EXPECT_FALSE(overview_controller->InOverviewSession()); -} - } // namespace ash
diff --git a/ash/shelf/home_button.cc b/ash/shelf/home_button.cc index ccb2863..caaaffc 100644 --- a/ash/shelf/home_button.cc +++ b/ash/shelf/home_button.cc
@@ -7,7 +7,6 @@ #include <math.h> // std::ceil #include "ash/app_list/app_list_controller_impl.h" -#include "ash/kiosk_next/kiosk_next_shell_controller_impl.h" #include "ash/public/cpp/shelf_types.h" #include "ash/shelf/shelf_button_delegate.h" #include "ash/shelf/shelf_constants.h"
diff --git a/ash/shelf/home_button_unittest.cc b/ash/shelf/home_button_unittest.cc index f3eb520..ac2a066 100644 --- a/ash/shelf/home_button_unittest.cc +++ b/ash/shelf/home_button_unittest.cc
@@ -13,9 +13,6 @@ #include "ash/assistant/assistant_ui_controller.h" #include "ash/assistant/model/assistant_ui_model.h" #include "ash/assistant/test/test_assistant_service.h" -#include "ash/kiosk_next/kiosk_next_shell_test_util.h" -#include "ash/kiosk_next/mock_kiosk_next_shell_client.h" -#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/voice_interaction_controller.h" #include "ash/root_window_controller.h" #include "ash/session/session_controller_impl.h" @@ -25,7 +22,6 @@ #include "ash/shelf/shelf_view_test_api.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/overview_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/command_line.h" #include "base/run_loop.h" @@ -249,50 +245,4 @@ ->visibility()); } -class KioskNextHomeButtonTest : public HomeButtonTest { - public: - KioskNextHomeButtonTest() { - scoped_feature_list_.InitAndEnableFeature(features::kKioskNextShell); - } - - void SetUp() override { - set_start_session(false); - HomeButtonTest::SetUp(); - client_ = std::make_unique<MockKioskNextShellClient>(); - } - - void TearDown() override { - client_.reset(); - HomeButtonTest::TearDown(); - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<MockKioskNextShellClient> client_; - - DISALLOW_COPY_AND_ASSIGN(KioskNextHomeButtonTest); -}; - -TEST_F(KioskNextHomeButtonTest, TapToGoHome) { - LogInKioskNextUser(GetSessionControllerClient()); - - ShelfViewTestAPI test_api(GetPrimaryShelf()->GetShelfViewForTesting()); - test_api.RunMessageLoopUntilAnimationsDone(); - - // Enter Overview mode. - OverviewController* overview_controller = Shell::Get()->overview_controller(); - ASSERT_TRUE(overview_controller->StartOverview()); - ASSERT_TRUE(overview_controller->InOverviewSession()); - test_api.RunMessageLoopUntilAnimationsDone(); - - // Tapping the home button should exit Overview mode. - gfx::Point center = home_button()->GetCenterPoint(); - views::View::ConvertPointToScreen(home_button(), ¢er); - GetEventGenerator()->GestureTapDownAndUp(center); - test_api.RunMessageLoopUntilAnimationsDone(); - EXPECT_FALSE(overview_controller->InOverviewSession()); - - // TODO(michaelpg): Create a Home Screen aura::Window* and verify its state. -} - } // namespace ash
diff --git a/ash/shell/content/client/shell_browser_main_parts.cc b/ash/shell/content/client/shell_browser_main_parts.cc index 897d07d..331007d 100644 --- a/ash/shell/content/client/shell_browser_main_parts.cc +++ b/ash/shell/content/client/shell_browser_main_parts.cc
@@ -19,115 +19,105 @@ #include "ash/shell/window_type_launcher.h" #include "ash/shell/window_watcher.h" #include "ash/shell_init_params.h" -#include "ash/wallpaper/wallpaper_controller_impl.h" +#include "ash/test/ash_test_helper.h" #include "base/bind.h" #include "base/command_line.h" -#include "base/i18n/icu_util.h" #include "base/run_loop.h" -#include "base/strings/string_number_conversions.h" -#include "base/time/time.h" -#include "chromeos/audio/cras_audio_handler.h" #include "chromeos/dbus/biod/biod_client.h" -#include "chromeos/dbus/power/power_manager_client.h" -#include "chromeos/dbus/power/power_policy_controller.h" #include "components/exo/file_helper.h" #include "content/public/browser/context_factory.h" #include "content/public/browser/system_connector.h" #include "content/public/common/content_switches.h" #include "content/shell/browser/shell_browser_context.h" -#include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "net/base/net_module.h" #include "services/service_manager/public/cpp/connector.h" -#include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" -#include "ui/base/material_design/material_design_controller.h" #include "ui/base/ui_base_features.h" -#include "ui/base/ui_base_paths.h" -#include "ui/compositor/compositor.h" #include "ui/views/examples/examples_window_with_content.h" -#include "ui/wm/core/wm_state.h" namespace ash { namespace shell { ShellBrowserMainParts::ShellBrowserMainParts( - const content::MainFunctionParams& parameters) {} + const content::MainFunctionParams& parameters) + : parameters_(parameters) {} ShellBrowserMainParts::~ShellBrowserMainParts() = default; void ShellBrowserMainParts::PreMainMessageLoopStart() {} void ShellBrowserMainParts::PostMainMessageLoopStart() { - chromeos::PowerManagerClient::InitializeFake(); chromeos::BiodClient::InitializeFake(); } void ShellBrowserMainParts::ToolkitInitialized() { - wm_state_.reset(new ::wm::WMState); + // A ViewsDelegate is required. + views_delegate_ = std::make_unique<ShellViewsDelegate>(); } void ShellBrowserMainParts::PreMainMessageLoopRun() { browser_context_.reset(new content::ShellBrowserContext(false)); - // A ViewsDelegate is required. - if (!views::ViewsDelegate::GetInstance()) - views_delegate_ = std::make_unique<ShellViewsDelegate>(); + ash_test_helper_ = std::make_unique<AshTestHelper>(); - // Create CrasAudioHandler for testing since g_browser_process - // is absent. - chromeos::CrasAudioHandler::InitializeForTesting(); + AshTestHelper::InitParams init_params; + init_params.start_session = true; + init_params.provide_local_state = true; - bluez::BluezDBusManager::InitializeFake(); + if (parameters_.ui_task) { + init_params.config_type = AshTestHelper::kUnitTest; + } else { + init_params.config_type = AshTestHelper::kShell; + } - chromeos::PowerPolicyController::Initialize( - chromeos::PowerManagerClient::Get()); + ShellInitParams shell_init_params; + shell_init_params.delegate = + std::make_unique<ash::shell::ShellDelegateImpl>(); + shell_init_params.context_factory = content::GetContextFactory(); + shell_init_params.context_factory_private = + content::GetContextFactoryPrivate(); + shell_init_params.connector = content::GetSystemConnector(); + shell_init_params.keyboard_ui_factory = + std::make_unique<TestKeyboardUIFactory>(); - ui::MaterialDesignController::Initialize(); - ash::ShellInitParams init_params; - init_params.delegate = std::make_unique<ash::shell::ShellDelegateImpl>(); - init_params.context_factory = content::GetContextFactory(); - init_params.context_factory_private = content::GetContextFactoryPrivate(); - init_params.connector = content::GetSystemConnector(); - init_params.keyboard_ui_factory = std::make_unique<TestKeyboardUIFactory>(); - ash::Shell::CreateInstance(std::move(init_params)); - - prefs_provider_ = std::make_unique<TestPrefServiceProvider>(); - - // Initialize session controller client and create fake user sessions. The - // fake user sessions makes ash into the logged in state. - example_session_controller_client_ = - std::make_unique<ExampleSessionControllerClient>( - Shell::Get()->session_controller(), prefs_provider_.get()); - example_session_controller_client_->Initialize(); + ash_test_helper_->SetUp(init_params, std::move(shell_init_params)); window_watcher_ = std::make_unique<WindowWatcher>(); - ash::shell::InitWindowTypeLauncher( - base::BindRepeating(&views::examples::ShowExamplesWindowWithContent, - base::Passed(base::OnceClosure()), - base::Unretained(browser_context_.get()), nullptr), - base::BindRepeating(&EmbeddedBrowser::Create, - base::Unretained(browser_context_.get()), - GURL("https://www.google.com"))); - - example_app_list_client_ = std::make_unique<ExampleAppListClient>( - Shell::Get()->app_list_controller()); - - ash::Shell::Get()->wallpaper_controller()->ShowDefaultWallpaperForTesting(); - ash::Shell::GetPrimaryRootWindow()->GetHost()->Show(); ash::Shell::Get()->InitWaylandServer(nullptr); + + if (!parameters_.ui_task) { + // Initialize session controller client and create fake user sessions. The + // fake user sessions makes ash into the logged in state. + example_session_controller_client_ = + std::make_unique<ExampleSessionControllerClient>( + Shell::Get()->session_controller(), + ash_test_helper_->prefs_provider()); + example_session_controller_client_->Initialize(); + + example_app_list_client_ = std::make_unique<ExampleAppListClient>( + Shell::Get()->app_list_controller()); + + ash::shell::InitWindowTypeLauncher( + base::BindRepeating(views::examples::ShowExamplesWindowWithContent, + base::Passed(base::OnceClosure()), + base::Unretained(browser_context_.get()), nullptr), + base::BindRepeating(base::IgnoreResult(&EmbeddedBrowser::Create), + base::Unretained(browser_context_.get()), + GURL("https://www.google.com"))); + } } void ShellBrowserMainParts::PostMainMessageLoopRun() { window_watcher_.reset(); - ash::Shell::DeleteInstance(); + example_app_list_client_.reset(); + example_session_controller_client_.reset(); - chromeos::CrasAudioHandler::Shutdown(); - - chromeos::PowerPolicyController::Shutdown(); + ash_test_helper_->TearDown(); + ash_test_helper_.reset(); views_delegate_.reset(); @@ -139,10 +129,15 @@ } bool ShellBrowserMainParts::MainMessageLoopRun(int* result_code) { - base::RunLoop run_loop; - example_session_controller_client_->set_quit_closure( - run_loop.QuitWhenIdleClosure()); - run_loop.Run(); + if (parameters_.ui_task) { + parameters_.ui_task->Run(); + delete parameters_.ui_task; + } else { + base::RunLoop run_loop; + example_session_controller_client_->set_quit_closure( + run_loop.QuitWhenIdleClosure()); + run_loop.Run(); + } return true; }
diff --git a/ash/shell/content/client/shell_browser_main_parts.h b/ash/shell/content/client/shell_browser_main_parts.h index db781041..067890a 100644 --- a/ash/shell/content/client/shell_browser_main_parts.h +++ b/ash/shell/content/client/shell_browser_main_parts.h
@@ -9,9 +9,10 @@ #include "base/macros.h" #include "content/public/browser/browser_main_parts.h" +#include "content/public/common/main_function_params.h" namespace content { -class ShellBrowserContext; +class BrowserContext; struct MainFunctionParams; } @@ -19,12 +20,8 @@ class ViewsDelegate; } -namespace wm { -class WMState; -} - namespace ash { -class TestPrefServiceProvider; +class AshTestHelper; namespace shell { class ExampleAppListClient; @@ -44,19 +41,17 @@ bool MainMessageLoopRun(int* result_code) override; void PostMainMessageLoopRun() override; - content::ShellBrowserContext* browser_context() { - return browser_context_.get(); - } + content::BrowserContext* browser_context() { return browser_context_.get(); } private: - std::unique_ptr<content::ShellBrowserContext> browser_context_; + std::unique_ptr<content::BrowserContext> browser_context_; std::unique_ptr<views::ViewsDelegate> views_delegate_; std::unique_ptr<WindowWatcher> window_watcher_; - std::unique_ptr<wm::WMState> wm_state_; std::unique_ptr<ExampleSessionControllerClient> example_session_controller_client_; std::unique_ptr<ExampleAppListClient> example_app_list_client_; - std::unique_ptr<TestPrefServiceProvider> prefs_provider_; + std::unique_ptr<ash::AshTestHelper> ash_test_helper_; + content::MainFunctionParams parameters_; DISALLOW_COPY_AND_ASSIGN(ShellBrowserMainParts); };
diff --git a/ash/system/accessibility/autoclick_menu_bubble_controller.cc b/ash/system/accessibility/autoclick_menu_bubble_controller.cc index 3eee0b6..f4c237b1 100644 --- a/ash/system/accessibility/autoclick_menu_bubble_controller.cc +++ b/ash/system/accessibility/autoclick_menu_bubble_controller.cc
@@ -194,9 +194,13 @@ resting_bounds, GetScrollAnchorAlignmentForPosition(new_position)); } -void AutoclickMenuBubbleController::SetScrollPoint( - gfx::Point scroll_location_in_dips) { - scroll_bubble_controller_->SetScrollPoint(scroll_location_in_dips); +void AutoclickMenuBubbleController::SetScrollPosition( + gfx::Rect scroll_bounds_in_dips, + const gfx::Point& scroll_point_in_dips) { + if (!scroll_bubble_controller_) + return; + scroll_bubble_controller_->SetScrollPosition(scroll_bounds_in_dips, + scroll_point_in_dips); } void AutoclickMenuBubbleController::ShowBubble(AutoclickEventType type,
diff --git a/ash/system/accessibility/autoclick_menu_bubble_controller.h b/ash/system/accessibility/autoclick_menu_bubble_controller.h index ec3e904f..2dc3b4a 100644 --- a/ash/system/accessibility/autoclick_menu_bubble_controller.h +++ b/ash/system/accessibility/autoclick_menu_bubble_controller.h
@@ -29,8 +29,10 @@ // Sets the menu's position on the screen. void SetPosition(AutoclickMenuPosition position); - // Set the scroll menu's position on the screen. - void SetScrollPoint(gfx::Point scroll_location_in_dips); + // Set the scroll menu's position on the screen. The rect is the bounds of + // the scrollable area, and the point is the user-selected scroll point. + void SetScrollPosition(gfx::Rect scroll_bounds_in_dips, + const gfx::Point& scroll_point_in_dips); void ShowBubble(AutoclickEventType event_type, AutoclickMenuPosition position);
diff --git a/ash/system/accessibility/autoclick_menu_bubble_controller_unittest.cc b/ash/system/accessibility/autoclick_menu_bubble_controller_unittest.cc index ff7f6aa..939f76f 100644 --- a/ash/system/accessibility/autoclick_menu_bubble_controller_unittest.cc +++ b/ash/system/accessibility/autoclick_menu_bubble_controller_unittest.cc
@@ -26,6 +26,7 @@ // The buffers in dips around a scroll point where the scroll menu is shown. const int kScrollViewBoundsXBuffer = 110; const int kScrollViewBoundsYBuffer = 10; +const int kScrollViewBoundsRectBuffer = 18; ui::GestureEvent CreateTapEvent() { return ui::GestureEvent(0, 0, 0, base::TimeTicks(), @@ -305,20 +306,35 @@ } } -TEST_F(AutoclickMenuBubbleControllerTest, ScrollBubbleManualPositioning) { - UpdateDisplay("1000x800"); +TEST_F(AutoclickMenuBubbleControllerTest, + ScrollBubbleManualPositioningLargeScrollBounds) { AccessibilityControllerImpl* controller = Shell::Get()->accessibility_controller(); controller->SetAutoclickEventType(AutoclickEventType::kScroll); - const struct { bool is_RTL; } kTestCases[] = {{true}, {false}}; + // With large scrollable bounds, the scroll bubble should just be positioned + // near the scroll point. Try with high density bounds and LTR/RTL languages. + const struct { + bool is_RTL; + gfx::Rect scroll_bounds; + std::string display_spec; + } kTestCases[] = { + {true, gfx::Rect(0, 0, 1000, 800), "1000x800"}, + {false, gfx::Rect(0, 0, 1000, 800), "1000x800"}, + {false, gfx::Rect(100, 100, 800, 600), "1000x800"}, + {true, gfx::Rect(200, 0, 600, 600), "1000x800"}, + {true, gfx::Rect(0, 0, 1000, 800), "2000x1600*2"}, + {false, gfx::Rect(0, 0, 1000, 800), "2000x1600*2"}, + }; for (auto& test : kTestCases) { + UpdateDisplay(test.display_spec); base::i18n::SetRTLForTesting(test.is_RTL); + gfx::Rect scroll_bounds = test.scroll_bounds; controller->SetAutoclickMenuPosition(AutoclickMenuPosition::kTopRight); // Start with a point no where near the autoclick menu. gfx::Point point = gfx::Point(400, 400); - GetBubbleController()->SetScrollPoint(point); + GetBubbleController()->SetScrollPosition(scroll_bounds, point); // In-line with the point in the Y axis. EXPECT_LT(abs(GetScrollViewBounds().right_center().y() - point.y()), @@ -335,21 +351,21 @@ // Moving the autoclick bubble doesn't impact the scroll bubble once it // has been manually set. - gfx::Rect scroll_bounds = GetScrollViewBounds(); + gfx::Rect bubble_bounds = GetScrollViewBounds(); controller->SetAutoclickMenuPosition(AutoclickMenuPosition::kBottomRight); - EXPECT_EQ(scroll_bounds, GetScrollViewBounds()); + EXPECT_EQ(bubble_bounds, GetScrollViewBounds()); // If we position it by the edge of the screen, it should stay on-screen, // regardless of LTR vs RTL. point = gfx::Point(0, 0); - GetBubbleController()->SetScrollPoint(point); + GetBubbleController()->SetScrollPosition(scroll_bounds, point); EXPECT_LT(abs(GetScrollViewBounds().x() - point.x()), kScrollViewBoundsXBuffer); EXPECT_LT(abs(GetScrollViewBounds().y() - point.y()), kScrollViewBoundsYBuffer); point = gfx::Point(1000, 400); - GetBubbleController()->SetScrollPoint(point); + GetBubbleController()->SetScrollPosition(scroll_bounds, point); EXPECT_LT(abs(GetScrollViewBounds().right() - point.x()), kScrollViewBoundsXBuffer); EXPECT_LT(abs(GetScrollViewBounds().left_center().y() - point.y()), @@ -357,4 +373,132 @@ } } +TEST_F(AutoclickMenuBubbleControllerTest, + ScrollBubbleManualPositioningSmallScrollBounds) { + UpdateDisplay("1200x1000"); + AccessibilityControllerImpl* controller = + Shell::Get()->accessibility_controller(); + controller->SetAutoclickEventType(AutoclickEventType::kScroll); + + const struct { + bool is_RTL; + gfx::Rect scroll_bounds; + gfx::Point scroll_point; + bool expect_bounds_on_right; + bool expect_bounds_on_left; + bool expect_bounds_on_top; + bool expect_bounds_on_bottom; + } kTestCases[] = { + // Small centered bounds, point closest to the right side. + {true, gfx::Rect(400, 350, 300, 300), gfx::Point(555, 500), + true /* on right */, false, false, false}, + {false, gfx::Rect(400, 350, 300, 300), gfx::Point(555, 500), + true /* on right */, false, false, false}, + {false, gfx::Rect(400, 350, 300, 300), gfx::Point(650, 400), + true /* on right */, false, false, false}, + + // Small centered bounds, point closest to the left side. + {true, gfx::Rect(400, 350, 300, 300), gfx::Point(545, 500), false, + true /* on left */, false, false}, + {false, gfx::Rect(400, 350, 300, 300), gfx::Point(545, 500), false, + true /* on left */, false, false}, + {false, gfx::Rect(400, 350, 300, 300), gfx::Point(410, 400), false, + true /* on left */, false, false}, + + // Point closest to the top of the bounds. + {true, gfx::Rect(400, 350, 300, 300), gfx::Point(550, 400), false, false, + true /* on top */, false}, + {false, gfx::Rect(400, 350, 300, 300), gfx::Point(550, 400), false, false, + true /* on top */, false}, + {false, gfx::Rect(400, 350, 300, 300), gfx::Point(402, 351), false, false, + true /* on top */, false}, + + // Point closest to the bottom of the bounds. + {true, gfx::Rect(400, 350, 300, 300), gfx::Point(550, 550), false, false, + false, true /* on bottom */}, + {false, gfx::Rect(400, 350, 300, 300), gfx::Point(550, 550), false, false, + false, true /* on bottom */}, + {false, gfx::Rect(400, 350, 300, 300), gfx::Point(450, 649), false, false, + false, true /* on bottom */}, + + // These bounds only have space on the right and bottom. Even points + // close to the top left get mapped to the right or bottom. + {false, gfx::Rect(100, 100, 300, 300), gfx::Point(130, 120), + true /* on right */, false, false, false}, + {true, gfx::Rect(100, 100, 300, 300), gfx::Point(130, 120), + true /* on right */, false, false, false}, + {false, gfx::Rect(100, 100, 300, 300), gfx::Point(120, 130), false, false, + false, true /* on bottom */}, + + // These bounds only have space on the top and left. Even points + // close to the bottom right get mapped to the top or left. + {false, gfx::Rect(900, 600, 300, 300), gfx::Point(1075, 800), false, + true /* on left */, false, false}, + {false, gfx::Rect(900, 600, 300, 300), gfx::Point(1075, 800), false, + true /* on left */, false, false}, + {false, gfx::Rect(900, 600, 300, 300), gfx::Point(1100, 775), false, + false, true /* on top */, false}, + + // These bounds have space above/below, but not left/right. + {false, gfx::Rect(400, 100, 300, 800), gfx::Point(525, 110), false, + true /* on left */, false, false}, + {false, gfx::Rect(400, 100, 300, 800), gfx::Point(525, 845), false, + true /* on left */, false, false}, + {false, gfx::Rect(400, 100, 300, 800), gfx::Point(575, 845), + true /* on right */, false, false, false}, + + // These bounds have space left/right, but not above/below. + {false, gfx::Rect(100, 350, 1000, 300), gfx::Point(200, 450), false, + false, true /* on top */, false}, + {false, gfx::Rect(100, 350, 1000, 300), gfx::Point(200, 550), false, + false, false, true /* on bottom */}, + {false, gfx::Rect(100, 350, 1000, 300), gfx::Point(1000, 550), false, + false, false, true /* on bottom */}, + }; + for (auto& test : kTestCases) { + base::i18n::SetRTLForTesting(test.is_RTL); + gfx::Rect scroll_bounds = test.scroll_bounds; + gfx::Point scroll_point = test.scroll_point; + GetBubbleController()->SetScrollPosition(scroll_bounds, scroll_point); + + if (test.expect_bounds_on_right) { + // The scroll view should be on the right of the bounds and centered + // vertically on the scroll point. + EXPECT_LT(abs(GetScrollViewBounds().y() + + GetScrollViewBounds().height() / 2 - scroll_point.y()), + kScrollViewBoundsYBuffer); + EXPECT_LT(GetScrollViewBounds().x() - scroll_bounds.right(), + kScrollViewBoundsRectBuffer); + EXPECT_GT(GetScrollViewBounds().x() - scroll_bounds.right(), 0); + } else if (test.expect_bounds_on_left) { + // The scroll view should be on the left of the bounds and centered + // vertically on the scroll point. + EXPECT_LT(abs(GetScrollViewBounds().y() + + GetScrollViewBounds().height() / 2 - scroll_point.y()), + kScrollViewBoundsYBuffer); + EXPECT_LT(scroll_bounds.x() - GetScrollViewBounds().right(), + kScrollViewBoundsRectBuffer); + EXPECT_GT(scroll_bounds.x() - GetScrollViewBounds().right(), 0); + } else if (test.expect_bounds_on_top) { + // The scroll view should be on the top of the bounds and centered + // horizontally on the scroll point. + EXPECT_LT(abs(GetScrollViewBounds().x() + + GetScrollViewBounds().width() / 2 - scroll_point.x()), + kScrollViewBoundsYBuffer); + EXPECT_LT(scroll_bounds.y() - GetScrollViewBounds().bottom(), + kScrollViewBoundsRectBuffer); + EXPECT_GT(scroll_bounds.y() - GetScrollViewBounds().bottom(), 0); + } else if (test.expect_bounds_on_bottom) { + // The scroll view should be on the bottom of the bounds and centered + // horizontally on the scroll point. + EXPECT_LT(abs(GetScrollViewBounds().x() + + GetScrollViewBounds().width() / 2 - scroll_point.x()), + kScrollViewBoundsYBuffer); + EXPECT_LT(GetScrollViewBounds().y() - scroll_bounds.bottom(), + kScrollViewBoundsRectBuffer); + EXPECT_GT(GetScrollViewBounds().y() - scroll_bounds.bottom(), -1); + } + } +} + } // namespace ash
diff --git a/ash/system/accessibility/autoclick_scroll_bubble_controller.cc b/ash/system/accessibility/autoclick_scroll_bubble_controller.cc index fa14d4f..0c16237 100644 --- a/ash/system/accessibility/autoclick_scroll_bubble_controller.cc +++ b/ash/system/accessibility/autoclick_scroll_bubble_controller.cc
@@ -16,6 +16,7 @@ #include "ash/wm/workspace/workspace_layout_manager.h" #include "ash/wm/workspace_controller.h" #include "ui/aura/window_tree_host.h" +#include "ui/display/manager/display_manager.h" #include "ui/events/event_utils.h" namespace ash { @@ -24,7 +25,17 @@ // Autoclick scroll menu constants. constexpr int kAutoclickScrollMenuSizeDips = 192; const int kScrollPointBufferDips = 100; +const int kScrollRectBufferDips = 8; +struct Position { + int distance; + views::BubbleBorder::Arrow arrow; + bool is_horizontal; +}; + +bool comparePositions(Position first, Position second) { + return first.distance < second.distance; +} } // namespace AutoclickScrollBubbleController::AutoclickScrollBubbleController() {} @@ -38,22 +49,121 @@ gfx::Rect rect, views::BubbleBorder::Arrow alignment) { menu_bubble_rect_ = rect; - if (set_scroll_point_) + menu_bubble_alignment_ = alignment; + if (set_scroll_rect_) return; bubble_view_->SetArrow(alignment); bubble_view_->UpdateAnchorRect(rect); } -void AutoclickScrollBubbleController::SetScrollPoint( - gfx::Point scroll_location_in_dips) { - set_scroll_point_ = true; - gfx::Rect anchor = - gfx::Rect(scroll_location_in_dips.x(), scroll_location_in_dips.y(), 0, 0); - // Buffer around the point so that the scroll bubble does not overlap it. - // ScrollBubbleController will automatically layout to avoid edges. - anchor.Inset(-kScrollPointBufferDips, -kScrollPointBufferDips); - bubble_view_->SetArrow(views::BubbleBorder::Arrow::LEFT_CENTER); - bubble_view_->UpdateAnchorRect(anchor); +void AutoclickScrollBubbleController::SetScrollPosition( + gfx::Rect scroll_bounds_in_dips, + const gfx::Point& scroll_point_in_dips) { + // TODO(katie): Support multiple displays. + aura::Window* window = Shell::GetPrimaryRootWindow(); + gfx::Rect work_area = + WorkAreaInsets::ForWindow(window)->user_work_area_bounds(); + + // If the on-screen width and height of the scroll bounds are larger than a + // threshold size, simply offset the scroll menu bubble from the scroll point + // position. This ensures the scroll bubble does not end up too far away from + // the user's scroll point. + gfx::Rect on_screen_scroll_bounds(scroll_bounds_in_dips); + on_screen_scroll_bounds.Intersect(work_area); + if (on_screen_scroll_bounds.width() > 2 * kAutoclickScrollMenuSizeDips && + on_screen_scroll_bounds.height() > 2 * kAutoclickScrollMenuSizeDips) { + set_scroll_rect_ = true; + gfx::Rect anchor = + gfx::Rect(scroll_point_in_dips.x(), scroll_point_in_dips.y(), 0, 0); + // Buffer around the point so that the scroll bubble does not overlap it. + // ScrollBubbleController will automatically layout to avoid edges. + anchor.Inset(-kScrollPointBufferDips, -kScrollPointBufferDips); + bubble_view_->SetArrow(views::BubbleBorder::Arrow::LEFT_CENTER); + bubble_view_->UpdateAnchorRect(anchor); + return; + } + + // Otherwise, the scrollable area bounds are small compared to the scroll + // scroll bubble, so we should not overlap the scroll bubble if possible. + // Try to show the scroll bubble on the side of the rect closest to the point. + scroll_bounds_in_dips.Inset( + -kScrollRectBufferDips, -kScrollRectBufferDips, -kScrollRectBufferDips, + -kScrollRectBufferDips - kCollisionWindowWorkAreaInsetsDp); + + // Determine whether there will be space to show the scroll bubble between the + // scroll bounds and display bounds. + work_area.Inset(kAutoclickScrollMenuSizeDips, kAutoclickScrollMenuSizeDips); + bool fits_left = scroll_bounds_in_dips.x() > work_area.x(); + bool fits_right = scroll_bounds_in_dips.right() < work_area.right(); + bool fits_above = scroll_bounds_in_dips.y() > work_area.y(); + bool fits_below = scroll_bounds_in_dips.bottom() < work_area.bottom(); + + // The scroll bubble will fit outside the bounds of the scrollable area. + // Determine its exact position based on the scroll point: + // First, try to lay out the scroll bubble on the side of the scroll bounds + // closest to the scroll point. + // + // ------------------ + // | | + // | *| <-- Here, the scroll point is closest to the right + // | | edge so the bubble should be laid out on the + // | | right of the scroll bounds. + // ------------------ + // + std::vector<Position> positions; + if (fits_right) { + positions.push_back( + {scroll_bounds_in_dips.right() - scroll_point_in_dips.x(), + // Put it on the right. Note that in RTL languages right and left + // arrows + // are swapped. + base::i18n::IsRTL() ? views::BubbleBorder::Arrow::RIGHT_CENTER + : views::BubbleBorder::Arrow::LEFT_CENTER, + true}); + } + if (fits_left) { + positions.push_back({scroll_point_in_dips.x() - scroll_bounds_in_dips.x(), + // Put it on the left. Note that in RTL languages right + // and left arrows are swapped. + base::i18n::IsRTL() + ? views::BubbleBorder::Arrow::LEFT_CENTER + : views::BubbleBorder::Arrow::RIGHT_CENTER, + true}); + } + if (fits_below) { + positions.push_back( + {scroll_bounds_in_dips.bottom() - scroll_point_in_dips.y(), + views::BubbleBorder::Arrow::TOP_CENTER, false}); + } + if (fits_above) { + positions.push_back({scroll_point_in_dips.y() - scroll_bounds_in_dips.y(), + views::BubbleBorder::Arrow::BOTTOM_CENTER, false}); + } + + // If the scroll bubble doesn't fit between the scroll bounds and display + // edges, re-pin the scroll bubble to the menu bubble. + set_scroll_rect_ = !positions.empty(); + if (!set_scroll_rect_) { + UpdateAnchorRect(menu_bubble_rect_, menu_bubble_alignment_); + return; + } + + // Sort positions based on distance. + std::stable_sort(positions.begin(), positions.end(), comparePositions); + + // Position on the optimal side depending on the shortest distance. + bubble_view_->SetArrow(positions.front().arrow); + if (positions.front().is_horizontal) { + // Center it vertically on the scroll point. + bubble_view_->UpdateAnchorRect(gfx::Rect(scroll_bounds_in_dips.x(), + scroll_point_in_dips.y(), + scroll_bounds_in_dips.width(), 0)); + } else { + // Center horizontally on scroll point. + bubble_view_->UpdateAnchorRect(gfx::Rect(scroll_point_in_dips.x(), + scroll_bounds_in_dips.y(), 0, + scroll_bounds_in_dips.height())); + } } void AutoclickScrollBubbleController::ShowBubble(
diff --git a/ash/system/accessibility/autoclick_scroll_bubble_controller.h b/ash/system/accessibility/autoclick_scroll_bubble_controller.h index 75ff362..8357656 100644 --- a/ash/system/accessibility/autoclick_scroll_bubble_controller.h +++ b/ash/system/accessibility/autoclick_scroll_bubble_controller.h
@@ -20,7 +20,8 @@ void UpdateAnchorRect(gfx::Rect rect, views::BubbleBorder::Arrow alignment); - void SetScrollPoint(gfx::Point scroll_location_in_dips); + void SetScrollPosition(gfx::Rect scroll_bounds_in_dips, + const gfx::Point& scroll_point_in_dips); void ShowBubble(gfx::Rect anchor_rect, views::BubbleBorder::Arrow alignment); void CloseBubble(); @@ -47,11 +48,13 @@ AutoclickScrollView* scroll_view_ = nullptr; views::Widget* bubble_widget_ = nullptr; - // Whether the scroll bubble should be positioned based on a fixed point + // Whether the scroll bubble should be positioned based on a fixed rect // or just relative to the rect passed in UpdateAnchorRect. - bool set_scroll_point_ = false; + bool set_scroll_rect_ = false; gfx::Rect menu_bubble_rect_; + views::BubbleBorder::Arrow menu_bubble_alignment_ = + views::BubbleBorder::Arrow::TOP_LEFT; DISALLOW_COPY_AND_ASSIGN(AutoclickScrollBubbleController); };
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc index f3553310..7ced499 100644 --- a/ash/test/ash_test_base.cc +++ b/ash/test/ash_test_base.cc
@@ -137,7 +137,11 @@ // default state. shell::ToplevelWindow::ClearSavedStateForTest(); - ash_test_helper_->SetUp(start_session_, provide_local_state_); + AshTestHelper::InitParams params; + params.start_session = start_session_; + params.provide_local_state = provide_local_state_; + params.config_type = AshTestHelper::kUnitTest; + ash_test_helper_->SetUp(params); Shell::GetPrimaryRootWindow()->Show(); Shell::GetPrimaryRootWindow()->GetHost()->Show();
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc index fe162ef..01946ed 100644 --- a/ash/test/ash_test_helper.cc +++ b/ash/test/ash_test_helper.cc
@@ -25,7 +25,6 @@ #include "ash/session/test_pref_service_provider.h" #include "ash/session/test_session_controller_client.h" #include "ash/shell.h" -#include "ash/shell_init_params.h" #include "ash/system/message_center/test_notifier_settings_controller.h" #include "ash/system/model/system_tray_model.h" #include "ash/system/screen_layout_observer.h" @@ -72,7 +71,6 @@ AshTestHelper::AshTestHelper() : command_line_(std::make_unique<base::test::ScopedCommandLine>()) { - ui::test::EnableTestConfigForPlatformWindows(); } AshTestHelper::~AshTestHelper() { @@ -81,7 +79,8 @@ ScreenAsh::DeleteScreenForShutdown(); } -void AshTestHelper::SetUp(bool start_session, bool provide_local_state) { +void AshTestHelper::SetUp(const InitParams& init_params, + base::Optional<ShellInitParams> shell_init_params) { // TODO(jamescook): Can we do this without changing command line? // Use the origin (1,1) so that it doesn't over // lap with the native mouse cursor. @@ -91,23 +90,27 @@ ::switches::kHostWindowBounds, "1+1-800x600"); } + if (init_params.config_type == kUnitTest) { + // Default for unit tests but not for perf tests. + zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( + ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); + TabletModeController::SetUseScreenshotForTest(false); + ui::test::EnableTestConfigForPlatformWindows(); + display::ResetDisplayIdForTest(); + ui::InitializeInputMethodForTesting(); + } + statistics_provider_ = std::make_unique<chromeos::system::ScopedFakeStatisticsProvider>(); ui::test::EventGeneratorDelegate::SetFactoryFunction( base::BindRepeating(&aura::test::EventGeneratorDelegateAura::Create)); - display::ResetDisplayIdForTest(); wm_state_ = std::make_unique<::wm::WMState>(); // Only create a ViewsDelegate if the test didn't create one already. if (!views::ViewsDelegate::GetInstance()) test_views_delegate_ = std::make_unique<AshTestViewsDelegate>(); - // Disable animations during tests. - zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); - ui::InitializeInputMethodForTesting(); - // Creates Shell and hook with Desktop. if (!test_shell_delegate_) test_shell_delegate_ = new TestShellDelegate; @@ -137,7 +140,7 @@ ui::MaterialDesignController::Initialize(); - CreateShell(provide_local_state); + CreateShell(init_params.provide_local_state, std::move(shell_init_params)); // Reset aura::Env to eliminate test dependency (https://crbug.com/586514). aura::test::EnvTestHelper env_helper(aura::Env::GetInstance()); @@ -167,38 +170,43 @@ system_tray_client_ = std::make_unique<TestSystemTrayClient>(); shell->system_tray_model()->SetClient(system_tray_client_.get()); - if (start_session) + if (init_params.start_session) session_controller_client_->CreatePredefinedUserSessions(1); - // Tests that change the display configuration generally don't care about - // the notifications and the popup UI can interfere with things like - // cursors. - shell->screen_layout_observer()->set_show_notifications_for_testing(false); - - display::test::DisplayManagerTestApi(shell->display_manager()) - .DisableChangeDisplayUponHostResize(); - DisplayConfigurationControllerTestApi( - shell->display_configuration_controller()) - .SetDisplayAnimator(false); - app_list_test_helper_ = std::make_unique<AppListTestHelper>(); - // Create the test keyboard controller observer to respond to - // OnLoadKeyboardContentsRequested(). - test_keyboard_controller_observer_ = - std::make_unique<TestKeyboardControllerObserver>( - shell->keyboard_controller()); - new_window_delegate_ = std::make_unique<TestNewWindowDelegate>(); - // Remove the app dragging animations delay for testing purposes. - shell->overview_controller()->set_delayed_animation_task_delay_for_test( - base::TimeDelta()); + // Post shell creation config init. + if (init_params.config_type == kUnitTest) { + // Tests that change the display configuration generally don't care about + // the notifications and the popup UI can interfere with things like + // cursors. + shell->screen_layout_observer()->set_show_notifications_for_testing(false); - // Ensure tests have a wallpaper as placeholder. - shell->wallpaper_controller()->CreateEmptyWallpaperForTesting(); + // Disable display change animations in unit tests. + DisplayConfigurationControllerTestApi( + shell->display_configuration_controller()) + .SetDisplayAnimator(false); - TabletModeController::SetUseScreenshotForTest(false); + // Remove the app dragging animations delay for testing purposes. + shell->overview_controller()->set_delayed_animation_task_delay_for_test( + base::TimeDelta()); + + // Don't change the display size due to host size resize. + display::test::DisplayManagerTestApi(shell->display_manager()) + .DisableChangeDisplayUponHostResize(); + + // Create the test keyboard controller observer to respond to + // OnLoadKeyboardContentsRequested(). + test_keyboard_controller_observer_ = + std::make_unique<TestKeyboardControllerObserver>( + shell->keyboard_controller()); + // Unit test expects empty wallpaper. + shell->wallpaper_controller()->CreateEmptyWallpaperForTesting(); + } else { + shell->wallpaper_controller()->ShowDefaultWallpaperForTesting(); + } } void AshTestHelper::TearDown() { @@ -257,6 +265,8 @@ ui::test::EventGeneratorDelegate::FactoryFunction()); statistics_provider_.reset(); + + TabletModeController::SetUseScreenshotForTest(true); } PrefService* AshTestHelper::GetLocalStatePrefService() { @@ -275,26 +285,28 @@ return Shell::Get()->display_manager()->GetSecondaryDisplay(); } -void AshTestHelper::CreateShell(bool provide_local_state) { - const bool enable_pixel_output = false; - context_factories_ = - std::make_unique<ui::TestContextFactories>(enable_pixel_output); - ShellInitParams init_params; - init_params.delegate.reset(test_shell_delegate_); - init_params.context_factory = context_factories_->GetContextFactory(); - init_params.context_factory_private = - context_factories_->GetContextFactoryPrivate(); - init_params.keyboard_ui_factory = std::make_unique<TestKeyboardUIFactory>(); - +void AshTestHelper::CreateShell(bool provide_local_state, + base::Optional<ShellInitParams> init_params) { + if (init_params == base::nullopt) { + context_factories_ = std::make_unique<ui::TestContextFactories>( + /*enable_pixel_output=*/false); + init_params.emplace(ShellInitParams()); + init_params->delegate.reset(test_shell_delegate_); + init_params->context_factory = context_factories_->GetContextFactory(); + init_params->context_factory_private = + context_factories_->GetContextFactoryPrivate(); + init_params->keyboard_ui_factory = + std::make_unique<TestKeyboardUIFactory>(); + } if (provide_local_state) { auto pref_service = std::make_unique<TestingPrefServiceSimple>(); RegisterLocalStatePrefs(pref_service->registry(), true); local_state_ = std::move(pref_service); - init_params.local_state = local_state_.get(); + init_params->local_state = local_state_.get(); } - Shell::CreateInstance(std::move(init_params)); + Shell::CreateInstance(std::move(*init_params)); } } // namespace ash
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h index 57745c7..60ab6830 100644 --- a/ash/test/ash_test_helper.h +++ b/ash/test/ash_test_helper.h
@@ -12,7 +12,9 @@ #include "ash/assistant/test/test_assistant_service.h" #include "ash/session/test_session_controller_client.h" +#include "ash/shell_init_params.h" #include "base/macros.h" +#include "base/optional.h" #include "base/test/scoped_command_line.h" class PrefService; @@ -58,11 +60,26 @@ AshTestHelper(); ~AshTestHelper(); - // Creates the ash::Shell and performs associated initialization. Set - // |start_session| to true if the user should log in before the test is run. - // Set |provide_local_state| to true to inject local-state PrefService into - // the Shell before the test is run. - void SetUp(bool start_session, bool provide_local_state = true); + enum ConfigType { + // The configuration for shell executable. + kShell, + // The configuration for unit tests. + kUnitTest, + }; + + struct InitParams { + // True if the user should log in. + bool start_session = true; + // True to inject local-state PrefService into the Shell. + bool provide_local_state = true; + ConfigType config_type = kUnitTest; + }; + + // Creates the ash::Shell and performs associated initialization according + // to |init_params|. |shell_init_params| is used to initialize ash::Shell, + // or it uses test settings if omitted. + void SetUp(const InitParams& init_params, + base::Optional<ShellInitParams> shell_init_params = base::nullopt); // Destroys the ash::Shell and performs associated cleanup. void TearDown(); @@ -111,7 +128,8 @@ private: // Called when running in ash to create Shell. - void CreateShell(bool provide_local_state); + void CreateShell(bool provide_local_state, + base::Optional<ShellInitParams> init_params); std::unique_ptr<chromeos::system::ScopedFakeStatisticsProvider> statistics_provider_;
diff --git a/ash/test/ash_test_helper_unittest.cc b/ash/test/ash_test_helper_unittest.cc index 113bb9f4..65410e1 100644 --- a/ash/test/ash_test_helper_unittest.cc +++ b/ash/test/ash_test_helper_unittest.cc
@@ -21,7 +21,8 @@ void SetUp() override { testing::Test::SetUp(); ash_test_helper_ = std::make_unique<AshTestHelper>(); - ash_test_helper_->SetUp(true); + AshTestHelper::InitParams init_params; + ash_test_helper_->SetUp(std::move(init_params)); } void TearDown() override {
diff --git a/ash/wm/desks/desk.cc b/ash/wm/desks/desk.cc index 512c3a78..b37a99a7 100644 --- a/ash/wm/desks/desk.cc +++ b/ash/wm/desks/desk.cc
@@ -10,6 +10,7 @@ #include "ash/public/cpp/window_properties.h" #include "ash/shell.h" #include "ash/wm/mru_window_tracker.h" +#include "ash/wm/window_positioner.h" #include "ash/wm/window_state.h" #include "ash/wm/window_transient_descendant_iterator.h" #include "ash/wm/window_util.h" @@ -57,6 +58,22 @@ return has_transient_children || CanIncludeWindowInMruList(window); } +// Used to temporarily turn off the automatic window positioning while windows +// are being moved between desks. +class ScopedWindowPositionerDisabler { + public: + ScopedWindowPositionerDisabler() { + WindowPositioner::DisableAutoPositioning(true); + } + + ~ScopedWindowPositionerDisabler() { + WindowPositioner::DisableAutoPositioning(false); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedWindowPositionerDisabler); +}; + } // namespace class DeskContainerObserver : public aura::WindowObserver { @@ -225,6 +242,8 @@ DCHECK(target_desk); { + ScopedWindowPositionerDisabler window_positioner_disabler; + // Throttle notifying the observers, while we move those windows and notify // them only once when done. auto this_desk_throttled = GetScopedNotifyContentChangedDisabler(); @@ -260,6 +279,8 @@ DCHECK(this != target_desk); { + ScopedWindowPositionerDisabler window_positioner_disabler; + // Throttling here is necessary even though we're attempting to move a // single window. This is because that window might exist in a transient // window tree, which will result in actually moving multiple windows if the
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc index f2e376e..ac34dc77 100644 --- a/ash/wm/desks/desks_unittests.cc +++ b/ash/wm/desks/desks_unittests.cc
@@ -410,6 +410,36 @@ EXPECT_FALSE(desk_4->GetDeskContainerForRoot(root)->IsVisible()); } +TEST_F(DesksTest, TestWindowPositioningPaused) { + auto* controller = DesksController::Get(); + controller->NewDesk(); + + // Create two windows whose window positioning is managed. + const auto win0_bounds = gfx::Rect{10, 20, 250, 100}; + const auto win1_bounds = gfx::Rect{50, 50, 200, 200}; + auto win0 = CreateTestWindow(win0_bounds); + auto win1 = CreateTestWindow(win1_bounds); + wm::WindowState* window_state = wm::GetWindowState(win0.get()); + window_state->SetWindowPositionManaged(true); + window_state = wm::GetWindowState(win1.get()); + window_state->SetWindowPositionManaged(true); + EXPECT_EQ(win0_bounds, win0->GetBoundsInScreen()); + EXPECT_EQ(win1_bounds, win1->GetBoundsInScreen()); + + // Moving one window to the second desk should not affect the bounds of either + // windows. + Desk* desk_2 = controller->desks()[1].get(); + controller->MoveWindowFromActiveDeskTo(win1.get(), desk_2); + EXPECT_EQ(win0_bounds, win0->GetBoundsInScreen()); + EXPECT_EQ(win1_bounds, win1->GetBoundsInScreen()); + + // Removing a desk, which results in moving its windows to another desk should + // not affect the positions of those managed windows. + controller->RemoveDesk(desk_2); + EXPECT_EQ(win0_bounds, win0->GetBoundsInScreen()); + EXPECT_EQ(win1_bounds, win1->GetBoundsInScreen()); +} + // This test makes sure we have coverage for that desk switch animation when run // with multiple displays. TEST_F(DesksTest, DeskActivationDualDisplay) {
diff --git a/ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.cc b/ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.cc deleted file mode 100644 index d01c9917..0000000 --- a/ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.cc +++ /dev/null
@@ -1,54 +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 "ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.h" -#include "ash/shell.h" -#include "ash/wm/splitview/split_view_controller.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_util.h" - -namespace ash { - -namespace { - -// returns true if window |upper| is stacked above window |lower| in the window -// stacking order. -bool IsWindowAbove(aura::Window* upper, aura::Window* lower) { - if (!upper || !lower || upper == lower || upper->parent() != lower->parent()) - return false; - - const aura::Window::Windows windows = upper->parent()->children(); - auto upper_i = std::find(windows.begin(), windows.end(), upper); - auto lower_i = std::find(windows.begin(), windows.end(), lower); - return upper_i > lower_i; -} - -} // namespace - -TabletModeBackdropDelegateImpl::TabletModeBackdropDelegateImpl() = default; - -TabletModeBackdropDelegateImpl::~TabletModeBackdropDelegateImpl() = default; - -bool TabletModeBackdropDelegateImpl::HasBackdrop(aura::Window* window) { - // Don't show the backdrop in tablet mode for PIP windows. - if (wm::GetWindowState(window)->IsPip()) - return false; - - SplitViewController* split_view_controller = - Shell::Get()->split_view_controller(); - if (!split_view_controller->InSplitViewMode()) - return true; - - // If the split view mode is active, we should place the backdrop below the - // snapped window whose window stacking order is lower. - aura::Window* left_window = split_view_controller->left_window(); - aura::Window* right_window = split_view_controller->right_window(); - if (window == left_window && IsWindowAbove(window, right_window)) - return false; - if (window == right_window && IsWindowAbove(window, left_window)) - return false; - return true; -} - -} // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.h b/ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.h deleted file mode 100644 index db8e0b9..0000000 --- a/ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.h +++ /dev/null
@@ -1,32 +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 ASH_WM_TABLET_MODE_TABLET_MODE_BACKDROP_DELEGATE_IMPL_H_ -#define ASH_WM_TABLET_MODE_TABLET_MODE_BACKDROP_DELEGATE_IMPL_H_ - -#include "ash/wm/workspace/backdrop_delegate.h" - -#include "ash/ash_export.h" -#include "base/macros.h" - -namespace ash { - -// A backdrop delegate for tablet mode, which always creates a backdrop. -// This is also used in the WorkspaceLayoutManagerBackdropTest, hence -// is public. -class ASH_EXPORT TabletModeBackdropDelegateImpl : public BackdropDelegate { - public: - TabletModeBackdropDelegateImpl(); - ~TabletModeBackdropDelegateImpl() override; - - protected: - bool HasBackdrop(aura::Window* window) override; - - private: - DISALLOW_COPY_AND_ASSIGN(TabletModeBackdropDelegateImpl); -}; - -} // namespace ash - -#endif // ASH_WM_TABLET_MODE_TABLET_MODE_BACKDROP_DELEGATE_IMPL_H_
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc index 316a269..423ce7a 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -23,11 +23,12 @@ #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_utils.h" #include "ash/wm/tablet_mode/scoped_skip_user_session_blocked_check.h" -#include "ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.h" #include "ash/wm/tablet_mode/tablet_mode_event_handler.h" #include "ash/wm/tablet_mode/tablet_mode_window_state.h" #include "ash/wm/window_state.h" #include "ash/wm/wm_event.h" +#include "ash/wm/workspace/backdrop_controller.h" +#include "ash/wm/workspace/workspace_layout_manager.h" #include "ash/wm/workspace_controller.h" #include "base/command_line.h" #include "base/stl_util.h" @@ -161,6 +162,18 @@ } } +void UpdateDeskContainersBackdrops() { + for (auto* root : Shell::GetAllRootWindows()) { + for (auto* desk_container : desks_util::GetDesksContainers(root)) { + WorkspaceController* controller = GetWorkspaceController(desk_container); + WorkspaceLayoutManager* layout_manager = controller->layout_manager(); + BackdropController* backdrop_controller = + layout_manager->backdrop_controller(); + backdrop_controller->UpdateBackdrop(); + } + } +} + } // namespace // Class which tells tablet mode controller to observe a given window for UMA @@ -240,7 +253,6 @@ ArrangeWindowsForTabletMode(); } AddWindowCreationObservers(); - EnableBackdropBehindTopWindowOnEachDisplay(true); display::Screen::GetScreen()->AddObserver(this); Shell::Get()->AddShellObserver(this); Shell::Get()->session_controller()->AddObserver(this); @@ -293,7 +305,6 @@ Shell::Get()->session_controller()->RemoveObserver(this); Shell::Get()->overview_controller()->RemoveObserver(this); display::Screen::GetScreen()->RemoveObserver(this); - EnableBackdropBehindTopWindowOnEachDisplay(false); RemoveWindowCreationObservers(); ScopedObserveWindowAnimation scoped_observe(GetTopWindow(), this, @@ -717,30 +728,13 @@ } void TabletModeWindowManager::DisplayConfigurationChanged() { - EnableBackdropBehindTopWindowOnEachDisplay(false); RemoveWindowCreationObservers(); AddWindowCreationObservers(); - EnableBackdropBehindTopWindowOnEachDisplay(true); + UpdateDeskContainersBackdrops(); } bool TabletModeWindowManager::IsContainerWindow(aura::Window* window) { return base::Contains(observed_container_windows_, window); } -void TabletModeWindowManager::EnableBackdropBehindTopWindowOnEachDisplay( - bool enable) { - // Inform the WorkspaceLayoutManager that we want to show a backdrop behind - // the topmost window of its container. - for (auto* root : Shell::GetAllRootWindows()) { - for (auto* desk_container : desks_util::GetDesksContainers(root)) { - WorkspaceController* controller = GetWorkspaceController(desk_container); - DCHECK(controller); - - controller->SetBackdropDelegate( - enable ? std::make_unique<TabletModeBackdropDelegateImpl>() - : nullptr); - } - } -} - } // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.h b/ash/wm/tablet_mode/tablet_mode_window_manager.h index ddd75d6..ce242d2 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_manager.h +++ b/ash/wm/tablet_mode/tablet_mode_window_manager.h
@@ -154,9 +154,6 @@ // Returns true when the |window| is a container window. bool IsContainerWindow(aura::Window* window); - // Add a backdrop behind the currently active window on each desktop. - void EnableBackdropBehindTopWindowOnEachDisplay(bool enable); - // Every window which got touched by our window manager gets added here. WindowToState window_state_map_;
diff --git a/ash/wm/workspace/backdrop_controller.cc b/ash/wm/workspace/backdrop_controller.cc index 1ab3c93..b96c3c3 100644 --- a/ash/wm/workspace/backdrop_controller.cc +++ b/ash/wm/workspace/backdrop_controller.cc
@@ -23,7 +23,6 @@ #include "ash/wm/window_animations.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" -#include "ash/wm/workspace/backdrop_delegate.h" #include "base/auto_reset.h" #include "chromeos/audio/chromeos_sounds.h" #include "ui/aura/client/aura_constants.h" @@ -73,23 +72,64 @@ return overview_controller && overview_controller->InOverviewSession(); } +// Returns the bottom-most snapped window in the given |desk_container|, and +// nullptr if no such window was found. +aura::Window* GetBottomMostSnappedWindowForDeskContainer( + aura::Window* desk_container) { + DCHECK(desks_util::IsDeskContainer(desk_container)); + DCHECK(Shell::Get()->tablet_mode_controller()->InTabletMode()); + + // For the active desk, only use the windows snapped in SplitViewController if + // SplitView mode is active. + SplitViewController* split_view_controller = + Shell::Get()->split_view_controller(); + if (desks_util::IsActiveDeskContainer(desk_container) && + split_view_controller->InSplitViewMode()) { + aura::Window* left_window = split_view_controller->left_window(); + aura::Window* right_window = split_view_controller->right_window(); + for (auto* child : desk_container->children()) { + if (child == left_window || child == right_window) + return child; + } + + return nullptr; + } + + // For the inactive desks, we can't use the SplitViewController, since it only + // tracks left/right snapped windows in the active desk only. + // TODO(afakhry|xdai): SplitViewController should be changed to track snapped + // windows per desk per display. + for (auto* child : desk_container->children()) { + if (wm::GetWindowState(child)->IsSnapped()) + return child; + } + + return nullptr; +} + } // namespace BackdropController::BackdropController(aura::Window* container) : container_(container) { DCHECK(container_); - Shell::Get()->AddShellObserver(this); - Shell::Get()->overview_controller()->AddObserver(this); - Shell::Get()->accessibility_controller()->AddObserver(this); - Shell::Get()->wallpaper_controller()->AddObserver(this); + auto* shell = Shell::Get(); + shell->AddShellObserver(this); + shell->overview_controller()->AddObserver(this); + shell->accessibility_controller()->AddObserver(this); + shell->wallpaper_controller()->AddObserver(this); + shell->tablet_mode_controller()->AddObserver(this); } BackdropController::~BackdropController() { - Shell::Get()->accessibility_controller()->RemoveObserver(this); - Shell::Get()->wallpaper_controller()->RemoveObserver(this); - if (Shell::Get()->overview_controller()) - Shell::Get()->overview_controller()->RemoveObserver(this); - Shell::Get()->RemoveShellObserver(this); + auto* shell = Shell::Get(); + // Shell destroys the TabletModeController before destroying all root windows. + if (shell->tablet_mode_controller()) + shell->tablet_mode_controller()->RemoveObserver(this); + shell->accessibility_controller()->RemoveObserver(this); + shell->wallpaper_controller()->RemoveObserver(this); + if (shell->overview_controller()) + shell->overview_controller()->RemoveObserver(this); + shell->RemoveShellObserver(this); // TODO(oshima): animations won't work right with mus: // http://crbug.com/548396. Hide(/*destroy=*/true); @@ -128,12 +168,6 @@ UpdateBackdropInternal(); } -void BackdropController::SetBackdropDelegate( - std::unique_ptr<BackdropDelegate> delegate) { - delegate_ = std::move(delegate); - UpdateBackdrop(); -} - void BackdropController::UpdateBackdrop() { // Skip updating while overview mode is active, since the backdrop is hidden. if (pause_update_ || InOverviewSession()) @@ -207,7 +241,9 @@ void BackdropController::OnSplitViewStateChanged(SplitViewState previous_state, SplitViewState state) { - UpdateBackdrop(); + // Force the update of the backdrop, even if overview is active, so that the + // backdrop shows up properly in the mini_views. + UpdateBackdropInternal(); } void BackdropController::OnSplitViewDividerPositionChanged() { @@ -223,6 +259,14 @@ UpdateBackdrop(); } +void BackdropController::OnTabletModeStarted() { + UpdateBackdrop(); +} + +void BackdropController::OnTabletModeEnded() { + UpdateBackdrop(); +} + void BackdropController::UpdateBackdropInternal() { // Skip the recursive updates. if (pause_update_) @@ -325,7 +369,25 @@ return true; } - return delegate_ ? delegate_->HasBackdrop(window) : false; + if (!desks_util::IsDeskContainer(container_)) + return false; + + if (!Shell::Get()->tablet_mode_controller()->InTabletMode()) + return false; + + // Don't show the backdrop in tablet mode for PIP windows. + auto* state = wm::GetWindowState(window); + if (state->IsPip()) + return false; + + if (!state->IsSnapped()) + return true; + + auto* bottom_most_snapped_window = + GetBottomMostSnappedWindowForDeskContainer(container_); + if (!bottom_most_snapped_window) + return true; + return window == bottom_most_snapped_window; } void BackdropController::Show() { @@ -370,6 +432,8 @@ } bool BackdropController::BackdropShouldFullscreen() { + // TODO(afakhry): Define the correct behavior and revise this in a follow-up + // CL. aura::Window* window = GetTopmostWindowWithBackdrop(); SplitViewController* split_view_controller = Shell::Get()->split_view_controller();
diff --git a/ash/wm/workspace/backdrop_controller.h b/ash/wm/workspace/backdrop_controller.h index ab571df..14155f18 100644 --- a/ash/wm/workspace/backdrop_controller.h +++ b/ash/wm/workspace/backdrop_controller.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_WM_WORKSPACE_WORKSPACE_BACKDROP_DELEGATE_IMPL_H_ -#define ASH_WM_WORKSPACE_WORKSPACE_BACKDROP_DELEGATE_IMPL_H_ +#ifndef ASH_WM_WORKSPACE_BACKDROP_CONTROLLER_H_ +#define ASH_WM_WORKSPACE_BACKDROP_CONTROLLER_H_ #include <memory> @@ -13,6 +13,7 @@ #include "ash/public/cpp/wallpaper_controller_observer.h" #include "ash/shell_observer.h" #include "ash/wm/overview/overview_observer.h" +#include "ash/wm/tablet_mode/tablet_mode_observer.h" #include "base/macros.h" #include "ui/gfx/geometry/rect.h" @@ -30,20 +31,21 @@ namespace ash { -class BackdropDelegate; - // A backdrop which gets created for a container |window| and which gets // stacked behind the top level, activatable window that meets the following // criteria. // // 1) Has a aura::client::kHasBackdrop property = true. -// 2) BackdropDelegate::HasBackdrop(aura::Window* window) returns true. -// 3) Active ARC window when the spoken feedback is enabled. +// 2) Active ARC window when the spoken feedback is enabled. +// 3) In tablet mode: +// - Bottom-most snapped window in splitview, +// - Top-most activatable window if splitview is inactive. class ASH_EXPORT BackdropController : public AccessibilityObserver, public ShellObserver, public OverviewObserver, public SplitViewObserver, - public WallpaperControllerObserver { + public WallpaperControllerObserver, + public TabletModeObserver { public: explicit BackdropController(aura::Window* container); ~BackdropController() override; @@ -59,8 +61,6 @@ // backdrop even if overview mode is active. void OnDeskContentChanged(); - void SetBackdropDelegate(std::unique_ptr<BackdropDelegate> delegate); - // Update the visibility of, and restack the backdrop relative to // the other windows in the container. void UpdateBackdrop(); @@ -90,6 +90,10 @@ // WallpaperControllerObserver: void OnWallpaperPreviewStarted() override; + // TabletModeObserver: + void OnTabletModeStarted() override; + void OnTabletModeEnded() override; + private: friend class WorkspaceControllerTestApi; @@ -134,8 +138,6 @@ // The container of the window that should have a backdrop. aura::Window* container_; - std::unique_ptr<BackdropDelegate> delegate_; - // Event hanlder used to implement actions for accessibility. std::unique_ptr<ui::EventHandler> backdrop_event_handler_; ui::EventHandler* original_event_handler_ = nullptr; @@ -150,4 +152,4 @@ } // namespace ash -#endif // ASH_WM_WORKSPACE_WORKSPACE_BACKDROP_DELEGATE_IMPL_H_ +#endif // ASH_WM_WORKSPACE_BACKDROP_CONTROLLER_H_
diff --git a/ash/wm/workspace/backdrop_delegate.h b/ash/wm/workspace/backdrop_delegate.h deleted file mode 100644 index bbf3ddf..0000000 --- a/ash/wm/workspace/backdrop_delegate.h +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2014 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 ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_BACKDROP_DELEGATE_H_ -#define ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_BACKDROP_DELEGATE_H_ - -#include "ash/ash_export.h" - -namespace aura { -class Window; -} - -namespace ash { - -// A delegate which can be set to create and control a backdrop which gets -// placed below the top level window. -class ASH_EXPORT BackdropDelegate { - public: - virtual ~BackdropDelegate() {} - - // Returns true if |window| should have a backdrop. - virtual bool HasBackdrop(aura::Window* window) = 0; -}; - -} // namespace ash - -#endif // ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_BACKDROP_DELEGATE_H_
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc index 8d9c7c7..8ed01ff 100644 --- a/ash/wm/workspace/workspace_layout_manager.cc +++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -28,7 +28,6 @@ #include "ash/wm/window_util.h" #include "ash/wm/wm_event.h" #include "ash/wm/workspace/backdrop_controller.h" -#include "ash/wm/workspace/backdrop_delegate.h" #include "base/command_line.h" #include "ui/aura/client/aura_constants.h" #include "ui/base/ui_base_switches.h" @@ -134,11 +133,6 @@ keyboard::KeyboardUIController::Get()->RemoveObserver(this); } -void WorkspaceLayoutManager::SetBackdropDelegate( - std::unique_ptr<BackdropDelegate> delegate) { - backdrop_controller_->SetBackdropDelegate(std::move(delegate)); -} - ////////////////////////////////////////////////////////////////////////////// // WorkspaceLayoutManager, aura::LayoutManager implementation:
diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h index 540a6b2..e8498ab 100644 --- a/ash/wm/workspace/workspace_layout_manager.h +++ b/ash/wm/workspace/workspace_layout_manager.h
@@ -24,7 +24,6 @@ namespace ash { class RootWindowController; -class BackdropDelegate; class BackdropController; namespace wm { @@ -45,11 +44,6 @@ explicit WorkspaceLayoutManager(aura::Window* window); ~WorkspaceLayoutManager() override; - // A delegate which can be set to add a backdrop behind the top most visible - // window. With the call the ownership of the delegate will be transferred to - // the WorkspaceLayoutManager. - void SetBackdropDelegate(std::unique_ptr<BackdropDelegate> delegate); - BackdropController* backdrop_controller() { return backdrop_controller_.get(); }
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc index 0d34111..ea208b0a 100644 --- a/ash/wm/workspace/workspace_layout_manager_unittest.cc +++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -39,14 +39,12 @@ #include "ash/wm/fullscreen_window_finder.h" #include "ash/wm/overview/overview_controller.h" #include "ash/wm/splitview/split_view_controller.h" -#include "ash/wm/tablet_mode/tablet_mode_backdrop_delegate_impl.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_properties.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ash/wm/wm_event.h" #include "ash/wm/workspace/backdrop_controller.h" -#include "ash/wm/workspace/backdrop_delegate.h" #include "ash/wm/workspace/workspace_window_resizer.h" #include "ash/wm/workspace_controller_test_api.h" #include "base/bind_helpers.h" @@ -1108,15 +1106,10 @@ desks_util::GetActiveDeskContainerId()); } - // Turn the top window back drop on / off. - void ShowTopWindowBackdropForContainer(aura::Window* container, bool show) { - std::unique_ptr<BackdropDelegate> backdrop; - if (show) - backdrop = std::make_unique<TabletModeBackdropDelegateImpl>(); - GetWorkspaceLayoutManager(container)->SetBackdropDelegate( - std::move(backdrop)); - // Closing and / or opening can be a delayed operation. - base::RunLoop().RunUntilIdle(); + // Turn tablet mode on / off. + void SetTabletModeEnabled(bool enabled) { + Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enabled); + ASSERT_EQ(enabled, Shell::Get()->tablet_mode_controller()->InTabletMode()); } aura::Window* CreateTestWindowInParent(aura::Window* root_window) { @@ -1172,13 +1165,13 @@ // Check that creating the BackDrop without destroying it does not lead into // a crash. TEST_F(WorkspaceLayoutManagerBackdropTest, BackdropCrashTest) { - ShowTopWindowBackdropForContainer(default_container(), true); + SetTabletModeEnabled(true); } // Verify basic assumptions about the backdrop. TEST_F(WorkspaceLayoutManagerBackdropTest, BasicBackdropTests) { // The background widget will be created when there is a window. - ShowTopWindowBackdropForContainer(default_container(), true); + SetTabletModeEnabled(true); ASSERT_EQ(0u, default_container()->children().size()); { @@ -1222,9 +1215,9 @@ EXPECT_EQ("C,B,A", GetWindowOrderAsString(backdrop, window1.get(), window2.get(), window3.get())); - // Turn on the backdrop mode and check that the window shows up where it + // Enter tablet mode and check that the backdrop window shows up where it // should be (second highest number). - ShowTopWindowBackdropForContainer(default_container(), true); + SetTabletModeEnabled(true); backdrop = default_container()->children()[2]; EXPECT_EQ("C,X,B,A", GetWindowOrderAsString(backdrop, window1.get(), window2.get(), window3.get())); @@ -1253,7 +1246,7 @@ ShelfVisibilityDoesNotChangesBounds) { Shelf* shelf = GetPrimaryShelf(); ShelfLayoutManager* shelf_layout_manager = shelf->shelf_layout_manager(); - ShowTopWindowBackdropForContainer(default_container(), true); + SetTabletModeEnabled(true); base::RunLoop().RunUntilIdle(); const gfx::Size fullscreen_size = GetPrimaryDisplay().size(); @@ -1376,9 +1369,8 @@ EXPECT_EQ(window3.get(), children[3]); } - // Enabling the backdrop delegate for tablet mode will put the - // backdrop on the top most window. - ShowTopWindowBackdropForContainer(default_container(), true); + // Enabling tablet mode will put the backdrop on the top most window. + SetTabletModeEnabled(true); { aura::Window::Windows children = window1->parent()->children(); EXPECT_EQ(4U, children.size()); @@ -1408,8 +1400,8 @@ EXPECT_EQ(window3.get(), children[3]); } - // Removing the delegate will move the backdrop back to window1. - ShowTopWindowBackdropForContainer(default_container(), false); + // Exiting tablet mode will move the backdrop back to window1. + SetTabletModeEnabled(false); { aura::Window::Windows children = window1->parent()->children(); EXPECT_EQ(4U, children.size()); @@ -1419,11 +1411,9 @@ EXPECT_EQ(window3.get(), children[3]); } - // Re-enable the backdrop delegate for tablet mode. Clearing the property is a - // no-op when the delegate is enabled. - ShowTopWindowBackdropForContainer(default_container(), true); + // Re-enter tablet mode. Clearing the property is a no-op in this case. + SetTabletModeEnabled(true); window3->ClearProperty(kBackdropWindowMode); - ShowTopWindowBackdropForContainer(default_container(), true); { aura::Window::Windows children = window1->parent()->children(); EXPECT_EQ(4U, children.size()); @@ -1459,9 +1449,9 @@ CreateTestWindow(gfx::Rect(0, 0, 100, 100))); wm::GetWindowState(wallpaper_picker_window.get())->Activate(); - // Enable the backdrop delegate for tablet mode. The backdrop is shown behind - // the wallpaper picker window. - ShowTopWindowBackdropForContainer(default_container(), true); + // Enter tablet mode. The backdrop is shown behind the wallpaper picker + // window. + SetTabletModeEnabled(true); aura::Window* backdrop = test_helper.GetBackdropWindow(); { aura::Window::Windows children = @@ -1545,7 +1535,7 @@ EXPECT_FALSE(test_helper.GetBackdropWindow()); // Turn the top window backdrop on. - ShowTopWindowBackdropForContainer(default_container(), true); + SetTabletModeEnabled(true); EXPECT_TRUE(test_helper.GetBackdropWindow()); // Enter overview mode. @@ -1787,7 +1777,7 @@ // Test that backdrop works in split view mode. TEST_F(WorkspaceLayoutManagerBackdropTest, BackdropForSplitScreenTest) { - ShowTopWindowBackdropForContainer(default_container(), true); + SetTabletModeEnabled(true); Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true); class SplitViewTestWindowDelegate : public aura::test::TestWindowDelegate { @@ -2010,10 +2000,11 @@ CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4))); always_on_top_window->Show(); always_on_top_window->SetProperty(aura::client::kAlwaysOnTopKey, true); + always_on_top_window->SetProperty(kBackdropWindowMode, + BackdropWindowMode::kEnabled); aura::Window* always_on_top_container = always_on_top_controller->GetContainer(always_on_top_window.get()); - ShowTopWindowBackdropForContainer(always_on_top_container, true); // AlwaysOnTopContainer has |always_on_top_window| and a backdrop window // at this moment. ASSERT_EQ(always_on_top_container->children().size(), 2U);
diff --git a/ash/wm/workspace_controller.cc b/ash/wm/workspace_controller.cc index 8a7820a..d5b4027 100644 --- a/ash/wm/workspace_controller.cc +++ b/ash/wm/workspace_controller.cc
@@ -17,7 +17,6 @@ #include "ash/wm/window_state.h" #include "ash/wm/wm_window_animations.h" #include "ash/wm/workspace/backdrop_controller.h" -#include "ash/wm/workspace/backdrop_delegate.h" #include "ash/wm/workspace/workspace_event_handler.h" #include "ash/wm/workspace/workspace_layout_manager.h" #include "ui/aura/window.h" @@ -126,11 +125,6 @@ } } -void WorkspaceController::SetBackdropDelegate( - std::unique_ptr<BackdropDelegate> delegate) { - layout_manager_->SetBackdropDelegate(std::move(delegate)); -} - void WorkspaceController::OnWindowDestroying(aura::Window* window) { DCHECK_EQ(window, viewport_); viewport_->RemoveObserver(this);
diff --git a/ash/wm/workspace_controller.h b/ash/wm/workspace_controller.h index 0b00f9e..aab5942 100644 --- a/ash/wm/workspace_controller.h +++ b/ash/wm/workspace_controller.h
@@ -15,7 +15,6 @@ namespace ash { -class BackdropDelegate; class WorkspaceEventHandler; class WorkspaceLayoutManager; @@ -33,10 +32,6 @@ // Starts the animation that occurs on first login. void DoInitialAnimation(); - // Add a delegate which adds a backdrop behind the top window of the default - // workspace. - void SetBackdropDelegate(std::unique_ptr<BackdropDelegate> delegate); - WorkspaceLayoutManager* layout_manager() { return layout_manager_; } private:
diff --git a/base/trace_event/memory_infra_background_whitelist.cc b/base/trace_event/memory_infra_background_whitelist.cc index ed5ff3b7..c52fb802 100644 --- a/base/trace_event/memory_infra_background_whitelist.cc +++ b/base/trace_event/memory_infra_background_whitelist.cc
@@ -355,6 +355,7 @@ "sync/0x?/model_type/USER_CONSENT", "sync/0x?/model_type/USER_EVENT", "sync/0x?/model_type/WALLET_METADATA", + "sync/0x?/model_type/WEB_APP", "sync/0x?/model_type/WIFI_CONFIGURATION", "sync/0x?/model_type/WIFI_CREDENTIAL", "tab_restore/service_helper_0x?/entries",
diff --git a/build/check_gn_headers_whitelist.txt b/build/check_gn_headers_whitelist.txt index d6f01d6..0d8df0a 100644 --- a/build/check_gn_headers_whitelist.txt +++ b/build/check_gn_headers_whitelist.txt
@@ -115,7 +115,6 @@ components/wifi/wifi_export.h components/wifi/wifi_service.h content/browser/background_fetch/background_fetch_constants.h -content/browser/service_worker/service_worker_response_type.h content/common/mac/attributed_string_coder.h content/public/browser/context_factory.h content/public/browser/media_observer.h
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 417e8e38..e690a66 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8908406653168684048 \ No newline at end of file +8908346996268693152 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index a8058b5..cd33a36 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8908409860290660320 \ No newline at end of file +8908346972979601936 \ No newline at end of file
diff --git a/build/toolchain/OWNERS b/build/toolchain/OWNERS index b329d48..0a8dcda5 100644 --- a/build/toolchain/OWNERS +++ b/build/toolchain/OWNERS
@@ -6,3 +6,4 @@ # Code Coverage. per-file *code_coverage*=mmoroz@chromium.org +per-file *code_coverage*=liaoyuke@chromium.org
diff --git a/cc/DEPS b/cc/DEPS index 0186be31..8d3576c 100644 --- a/cc/DEPS +++ b/cc/DEPS
@@ -22,6 +22,7 @@ "+gpu/command_buffer/common/sync_token.h", "+gpu/command_buffer/common/texture_in_use_response.h", "+gpu/config/gpu_feature_info.h", + "+gpu/config/gpu_finch_features.h", "+gpu/vulkan", "+media", "+mojo/public/cpp/system/buffer.h", @@ -58,6 +59,8 @@ ".*_(unit|pixel|perf)test.*\.cc": [ "+components/viz/service/display", "+components/viz/test", + "+gpu/command_buffer/common/command_buffer_id.h", + "+gpu/command_buffer/common/constants.h", ], "oop_pixeltest\.cc" : [ "+gpu/command_buffer/client",
diff --git a/cc/paint/image_transfer_cache_entry.cc b/cc/paint/image_transfer_cache_entry.cc index c0fdd92..e6d52001 100644 --- a/cc/paint/image_transfer_cache_entry.cc +++ b/cc/paint/image_transfer_cache_entry.cc
@@ -122,7 +122,7 @@ const SkPixmap* pixmap, const SkColorSpace* target_color_space, bool needs_mips) - : id_(s_next_id_.GetNext()), + : id_(GetNextId()), pixmap_(pixmap), target_color_space_(target_color_space), needs_mips_(needs_mips) {
diff --git a/cc/paint/image_transfer_cache_entry.h b/cc/paint/image_transfer_cache_entry.h index 6f8de73..8421565 100644 --- a/cc/paint/image_transfer_cache_entry.h +++ b/cc/paint/image_transfer_cache_entry.h
@@ -42,6 +42,8 @@ uint32_t SerializedSize() const final; bool Serialize(base::span<uint8_t> data) const final; + static uint32_t GetNextId() { return s_next_id_.GetNext(); } + private: uint32_t id_; const SkPixmap* const pixmap_;
diff --git a/cc/test/fake_paint_image_generator.cc b/cc/test/fake_paint_image_generator.cc index f26443e5..728a58c 100644 --- a/cc/test/fake_paint_image_generator.cc +++ b/cc/test/fake_paint_image_generator.cc
@@ -37,11 +37,11 @@ FakePaintImageGenerator::~FakePaintImageGenerator() = default; bool FakePaintImageGenerator::IsEligibleForAcceleratedDecoding() const { - return false; + return is_eligible_for_accelerated_decode_; } sk_sp<SkData> FakePaintImageGenerator::GetEncodedData() const { - return nullptr; + return SkData::MakeEmpty(); } bool FakePaintImageGenerator::GetPixels(const SkImageInfo& info,
diff --git a/cc/test/fake_paint_image_generator.h b/cc/test/fake_paint_image_generator.h index 268c89e..003afdf 100644 --- a/cc/test/fake_paint_image_generator.h +++ b/cc/test/fake_paint_image_generator.h
@@ -60,6 +60,9 @@ } void reset_frames_decoded() { frames_decoded_count_.clear(); } void SetExpectFallbackToRGB() { expect_fallback_to_rgb_ = true; } + void SetEligibleForAcceleratedDecoding() { + is_eligible_for_accelerated_decode_ = true; + } private: std::vector<uint8_t> image_backing_memory_; @@ -73,6 +76,7 @@ // planes and after Chrome implements it, we should no longer expect RGB // fallback. bool expect_fallback_to_rgb_ = false; + bool is_eligible_for_accelerated_decode_ = false; }; } // namespace cc
diff --git a/cc/test/skia_common.cc b/cc/test/skia_common.cc index 75a009a2..5889e894 100644 --- a/cc/test/skia_common.cc +++ b/cc/test/skia_common.cc
@@ -136,7 +136,7 @@ SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), color_type, kPremul_SkAlphaType, color_space); - sk_sp<PaintImageGenerator> generator; + sk_sp<FakePaintImageGenerator> generator; if (is_yuv) { // TODO(crbug.com/915972): Remove assumption of YUV420 in tests once we // support other subsamplings. @@ -148,6 +148,7 @@ info, std::vector<FrameMetadata>{FrameMetadata()}, allocate_encoded_data); } + generator->SetEligibleForAcceleratedDecoding(); auto paint_image = PaintImageBuilder::WithDefault() .set_id(id)
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc index df36750..92a5f4c 100644 --- a/cc/tiles/gpu_image_decode_cache.cc +++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -8,7 +8,9 @@ #include "base/auto_reset.h" #include "base/bind.h" +#include "base/containers/span.h" #include "base/debug/alias.h" +#include "base/feature_list.h" #include "base/hash/hash.h" #include "base/memory/discardable_memory_allocator.h" #include "base/metrics/histogram_macros.h" @@ -26,6 +28,8 @@ #include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/client/raster_interface.h" +#include "gpu/command_buffer/common/sync_token.h" +#include "gpu/config/gpu_finch_features.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkSurface.h" @@ -33,6 +37,8 @@ #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrContext.h" #include "third_party/skia/include/gpu/GrTexture.h" +#include "ui/gfx/color_space.h" +#include "ui/gfx/geometry/size.h" #include "ui/gfx/skia_util.h" #include "ui/gl/trace_util.h" @@ -576,10 +582,12 @@ ImageUploadTaskImpl(GpuImageDecodeCache* cache, const DrawImage& draw_image, scoped_refptr<TileTask> decode_dependency, + sk_sp<SkData> encoded_data, const ImageDecodeCache::TracingInfo& tracing_info) : TileTask(false), cache_(cache), image_(draw_image), + encoded_data_(std::move(encoded_data)), tracing_info_(tracing_info) { DCHECK(!SkipImage(draw_image)); // If an image is already decoded and locked, we will not generate a @@ -595,7 +603,7 @@ void RunOnWorkerThread() override { TRACE_EVENT2("cc", "ImageUploadTaskImpl::RunOnWorkerThread", "mode", "gpu", "source_prepare_tiles_id", tracing_info_.prepare_tiles_id); - cache_->UploadImageInTask(image_); + cache_->UploadImageInTask(image_, std::move(encoded_data_)); } // Overridden from TileTask: @@ -609,6 +617,7 @@ private: GpuImageDecodeCache* cache_; DrawImage image_; + sk_sp<SkData> encoded_data_; const ImageDecodeCache::TracingInfo tracing_info_; }; @@ -657,8 +666,11 @@ return state; } -GpuImageDecodeCache::DecodedImageData::DecodedImageData(bool is_bitmap_backed) - : is_bitmap_backed_(is_bitmap_backed) {} +GpuImageDecodeCache::DecodedImageData::DecodedImageData( + bool is_bitmap_backed, + bool do_hardware_accelerated_decode) + : is_bitmap_backed_(is_bitmap_backed), + do_hardware_accelerated_decode_(do_hardware_accelerated_decode) {} GpuImageDecodeCache::DecodedImageData::~DecodedImageData() { ResetData(); } @@ -740,6 +752,14 @@ } void GpuImageDecodeCache::DecodedImageData::ReportUsageStats() const { + if (do_hardware_accelerated_decode_) { + // When doing hardware decode acceleration, we don't want to record usage + // stats for the decode data. The reason is that the decode is done in the + // GPU process and the decoded result stays there. On the renderer side, we + // don't use or lock the decoded data, so reporting this status would + // incorrectly distort the software decoding statistics. + return; + } UMA_HISTOGRAM_ENUMERATION("Renderer4.GpuImageDecodeState", static_cast<ImageUsageState>(UsageState()), IMAGE_USAGE_STATE_COUNT); @@ -842,6 +862,7 @@ int upload_scale_mip_level, bool needs_mips, bool is_bitmap_backed, + bool do_hardware_accelerated_decode, bool is_yuv_format) : paint_image_id(paint_image_id), mode(mode), @@ -852,7 +873,7 @@ needs_mips(needs_mips), is_bitmap_backed(is_bitmap_backed), is_yuv(is_yuv_format), - decode(is_bitmap_backed) {} + decode(is_bitmap_backed, do_hardware_accelerated_decode) {} GpuImageDecodeCache::ImageData::~ImageData() { // We should never delete ImageData while it is in use or before it has been @@ -979,9 +1000,17 @@ const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image); ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key); scoped_refptr<ImageData> new_data; + sk_sp<SkData> encoded_data; if (!image_data) { - // We need an ImageData, create one now. - new_data = CreateImageData(draw_image); + // We need an ImageData, create one now. Note that hardware decode + // acceleration is allowed only in the DecodeTaskType::kPartOfUploadTask + // case. This prevents the img.decode() and checkerboard images paths from + // going through hardware decode acceleration. + new_data = CreateImageData( + draw_image, + task_type == + DecodeTaskType::kPartOfUploadTask /* allow_hardware_decode */, + &encoded_data); image_data = new_data.get(); } else if (image_data->decode.decode_failure) { // We have already tried and failed to decode this image, so just return. @@ -1032,7 +1061,7 @@ task = base::MakeRefCounted<ImageUploadTaskImpl>( this, draw_image, GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type), - tracing_info); + std::move(encoded_data), tracing_info); image_data->upload.task = task; } else { task = GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type); @@ -1071,9 +1100,11 @@ base::AutoLock lock(lock_); const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image); ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key); + sk_sp<SkData> encoded_data; if (!image_data) { // We didn't find the image, create a new entry. - auto data = CreateImageData(draw_image); + auto data = CreateImageData(draw_image, true /* allow_hardware_decode */, + &encoded_data); image_data = data.get(); AddToPersistentCache(draw_image, std::move(data)); } @@ -1088,7 +1119,7 @@ // We may or may not need to decode and upload the image we've found, the // following functions early-out to if we already decoded. DecodeImageIfNecessary(draw_image, image_data, TaskType::kInRaster); - UploadImageIfNecessary(draw_image, image_data); + UploadImageIfNecessary(draw_image, image_data, std::move(encoded_data)); // Unref the image decode, but not the image. The image ref will be released // in DrawWithImageFinished. UnrefImageDecode(draw_image, cache_key); @@ -1355,7 +1386,8 @@ DecodeImageIfNecessary(draw_image, image_data, task_type); } -void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image) { +void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image, + sk_sp<SkData> encoded_data) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "GpuImageDecodeCache::UploadImage"); base::Optional<viz::RasterContextProvider::ScopedRasterContextLock> @@ -1375,7 +1407,7 @@ if (image_data->is_bitmap_backed) DecodeImageIfNecessary(draw_image, image_data, TaskType::kInRaster); - UploadImageIfNecessary(draw_image, image_data); + UploadImageIfNecessary(draw_image, image_data, std::move(encoded_data)); } void GpuImageDecodeCache::OnImageDecodeTaskCompleted( @@ -1421,8 +1453,7 @@ UnrefImageInternal(draw_image, cache_key); } -// Checks if an existing image decode exists. If not, returns a task to produce -// the requested decode. +// Checks if an image decode needs a decode task and returns it. scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef( const DrawImage& draw_image, const TracingInfo& tracing_info, @@ -1440,6 +1471,9 @@ ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key); DCHECK(image_data); + if (image_data->decode.do_hardware_accelerated_decode()) + return nullptr; + // No decode is necessary for bitmap backed images. if (image_data->decode.is_locked() || image_data->is_bitmap_backed) { // We should never be creating a decode task for a not budgeted image. @@ -1688,6 +1722,11 @@ DCHECK_GT(image_data->decode.ref_count, 0u); + if (image_data->decode.do_hardware_accelerated_decode()) { + // We get here in the case of an at-raster decode. + return; + } + if (image_data->decode.decode_failure) { // We have already tried and failed to decode this image. Don't try again. return; @@ -1802,7 +1841,8 @@ } void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, - ImageData* image_data) { + ImageData* image_data, + sk_sp<SkData> encoded_data) { CheckContextLockAcquiredIfNecessary(); lock_.AssertAcquired(); @@ -1831,11 +1871,15 @@ return; TRACE_EVENT0("cc", "GpuImageDecodeCache::UploadImage"); - DCHECK(image_data->decode.is_locked()); + if (!image_data->decode.do_hardware_accelerated_decode()) { + // These are not needed for accelerated decodes because there was no decode + // task. + DCHECK(image_data->decode.is_locked()); + image_data->decode.mark_used(); + } DCHECK_GT(image_data->decode.ref_count, 0u); DCHECK_GT(image_data->upload.ref_count, 0u); - image_data->decode.mark_used(); sk_sp<SkColorSpace> color_space = SupportsColorSpaceConversion() && draw_image.target_color_space().IsValid() @@ -1854,6 +1898,51 @@ if (image_data->mode == DecodedDataMode::kTransferCache) { DCHECK(use_transfer_cache_); + if (image_data->decode.do_hardware_accelerated_decode()) { + // The assumption is that scaling is not currently supported for + // hardware-accelerated decodes. + DCHECK_EQ(0, image_data->upload_scale_mip_level); + const gfx::Size output_size(draw_image.paint_image().width(), + draw_image.paint_image().height()); + // Try to get the encoded data if we don't have it already: this can + // happen, e.g., if we create an upload task using a pre-existing + // ImageData. In that case, we previously decided to do hardware decode + // acceleration but we didn't cache the encoded data. + if (!encoded_data) { + encoded_data = draw_image.paint_image().GetSkImage()->refEncodedData(); + DCHECK(encoded_data); + } + const uint32_t transfer_cache_id = + ClientImageTransferCacheEntry::GetNextId(); + const gpu::SyncToken decode_sync_token = + context_->RasterInterface()->ScheduleImageDecode( + base::make_span<const uint8_t>(encoded_data->bytes(), + encoded_data->size()), + output_size, transfer_cache_id, + color_space ? gfx::ColorSpace(*color_space) : gfx::ColorSpace(), + image_data->needs_mips); + + if (!decode_sync_token.HasData()) { + image_data->decode.decode_failure = true; + return; + } + + image_data->upload.SetTransferCacheId(transfer_cache_id); + + // Note that we wait for the decode sync token here for two reasons: + // + // 1) To make sure that raster work that depends on the image decode + // happens after the decode completes. + // + // 2) To protect the transfer cache entry from being unlocked on the + // service side before the decode is completed. + context_->RasterInterface()->WaitSyncTokenCHROMIUM( + decode_sync_token.GetConstData()); + + return; + } + + // Non-hardware-accelerated path. SkPixmap pixmap; if (!image_data->decode.image()->peekPixels(&pixmap)) return; @@ -2023,7 +2112,9 @@ } scoped_refptr<GpuImageDecodeCache::ImageData> -GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) { +GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image, + bool allow_hardware_decode, + sk_sp<SkData>* encoded_data) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "GpuImageDecodeCache::CreateImageData"); lock_.AssertAcquired(); @@ -2064,8 +2155,64 @@ const bool is_bitmap_backed = !draw_image.paint_image().IsLazyGenerated() && upload_scale_mip_level == 0 && !cache_color_conversion_on_cpu; + + // Figure out if we will do hardware accelerated decoding. The criteria is as + // follows: + // + // - The kVaapiJpegImageDecodeAcceleration feature is enabled. + // - The caller allows hardware decodes. + // - We are using the transfer cache (OOP-R). + // - The image does not require downscaling for uploading (see TODO below). + // - All the encoded data was received prior to any decoding work. Otherwise, + // it means that the software decoder has already started decoding the + // image, so we just let it finish. + // - The image's color space is sRGB. This is because we don't currently + // support detecting embedded color profiles. + // - The image is supported according to the profiles advertised by the GPU + // service. Checking this involves obtaining the contiguous encoded data + // which may require a copy if the data is not already contiguous. Because + // of this, we return a pointer to the contiguous data (as |encoded_data|) + // so that we can re-use it later (when requesting the image decode). + // + // TODO(crbug.com/953363): ideally, we can make the hardware decoder support + // decision without requiring contiguous data. + // + // TODO(crbug.com/953367): currently, we don't support scaling with hardware + // decode acceleration. Note that it's still okay for the image to be + // downscaled by Skia using the GPU. + // + // TODO(crbug.com/981208): |data_size| needs to be set to the size of the + // decoded data, but for accelerated decodes we won't know until the driver + // gives us the result in the GPU process. Figure out what to do. + bool do_hardware_accelerated_decode = false; + if (base::FeatureList::IsEnabled( + features::kVaapiJpegImageDecodeAcceleration) && + allow_hardware_decode && mode == DecodedDataMode::kTransferCache && + upload_scale_mip_level == 0 && + draw_image.paint_image().IsEligibleForAcceleratedDecoding() && + draw_image.paint_image().color_space() && + draw_image.paint_image().color_space()->isSRGB()) { + sk_sp<SkData> tmp_encoded_data = + draw_image.paint_image().GetSkImage() + ? draw_image.paint_image().GetSkImage()->refEncodedData() + : nullptr; + if (tmp_encoded_data && + context_->ContextSupport()->CanDecodeWithHardwareAcceleration( + base::make_span<const uint8_t>(tmp_encoded_data->bytes(), + tmp_encoded_data->size()))) { + do_hardware_accelerated_decode = true; + DCHECK(encoded_data); + *encoded_data = std::move(tmp_encoded_data); + } + } + + // If draw_image.paint_image().IsEligibleForAcceleratedDecoding() returns + // true, the image should not be backed by a bitmap. + DCHECK(!do_hardware_accelerated_decode || !is_bitmap_backed); + SkYUVASizeInfo target_yuva_size_info; - const bool is_yuv = draw_image.paint_image().IsYuv(&target_yuva_size_info) && + const bool is_yuv = !do_hardware_accelerated_decode && + draw_image.paint_image().IsYuv(&target_yuva_size_info) && mode == DecodedDataMode::kGpu; // TODO(crbug.com/910276): Change after alpha support. @@ -2092,7 +2239,7 @@ draw_image.paint_image().stable_id(), mode, data_size, draw_image.target_color_space(), CalculateDesiredFilterQuality(draw_image), upload_scale_mip_level, - needs_mips, is_bitmap_backed, is_yuv)); + needs_mips, is_bitmap_backed, do_hardware_accelerated_decode, is_yuv)); } void GpuImageDecodeCache::WillAddCacheEntry(const DrawImage& draw_image) { @@ -2414,7 +2561,8 @@ size_t GpuImageDecodeCache::GetDrawImageSizeForTesting(const DrawImage& image) { base::AutoLock lock(lock_); - scoped_refptr<ImageData> data = CreateImageData(image); + scoped_refptr<ImageData> data = CreateImageData( + image, false /* allow_hardware_decode */, nullptr /* encoded_data */); return data->size; }
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h index 81ca628..86c443b 100644 --- a/cc/tiles/gpu_image_decode_cache.h +++ b/cc/tiles/gpu_image_decode_cache.h
@@ -17,6 +17,7 @@ #include "base/trace_event/memory_dump_provider.h" #include "cc/cc_export.h" #include "cc/tiles/image_decode_cache.h" +#include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkYUVAIndex.h" #include "third_party/skia/include/gpu/gl/GrGLTypes.h" @@ -36,9 +37,9 @@ // Generally, when an image is required for raster, GpuImageDecodeCache // creates two tasks, one to decode the image, and one to upload the image to // the GPU. These tasks are completed before the raster task which depends on -// the image. We need to seperate decode and upload tasks, as decode can occur +// the image. We need to separate decode and upload tasks, as decode can occur // simultaneously on multiple threads, while upload requires the GL context -// lock must happen on our non-concurrent raster thread. +// lock so it must happen on our non-concurrent raster thread. // // Decoded and Uploaded image data share a single cache entry. Depending on how // far we've progressed, this cache entry may contain CPU-side decoded data, @@ -97,6 +98,35 @@ // keeps an ImageData alive while it is present in either the // |persistent_cache_| or |in_use_cache_|. // +// HARDWARE ACCELERATED DECODES: +// +// In Chrome OS, we have the ability to use specialized hardware to decode +// certain images. Because this requires interacting with drivers, it must be +// done in the GPU process. Therefore, we follow a different path than the usual +// decode -> upload tasks: +// 1) We decide whether to do hardware decode acceleration for an image before +// we create the decode/upload tasks. Under the hood, this involves parsing +// the image and checking if it's supported by the hardware decoder +// according to information advertised by the GPU process. Also, we only +// allow hardware decoding in OOP-R mode. +// 2) If we do decide to do hardware decoding, we don't create a decode task. +// Instead, we create only an upload task and store enough state to +// indicate that the image will go through this hardware accelerated path. +// The reason that we use the upload task is that we need to hold the +// context lock in order to schedule the image decode. +// 3) When the upload task runs, we send a request to the GPU process to start +// the image decode. This is an IPC message that does not require us to +// wait for the response. Instead, we get a sync token that is signalled +// when the decode completes. We insert a wait for this sync token right +// after sending the decode request. +// +// We also handle the more unusual case where images are decoded at raster time. +// The process is similar: we skip the software decode and then request the +// hardware decode in the same way as step (3) above. +// +// Note that the decoded data never makes it back to the renderer. It stays in +// the GPU process. The sync token ensures that any raster work that needs the +// image happens after the decode completes. class CC_EXPORT GpuImageDecodeCache : public ImageDecodeCache, public base::trace_event::MemoryDumpProvider { @@ -144,7 +174,7 @@ // Called by Decode / Upload tasks. void DecodeImageInTask(const DrawImage& image, TaskType task_type); - void UploadImageInTask(const DrawImage& image); + void UploadImageInTask(const DrawImage& image, sk_sp<SkData> encoded_data); // Called by Decode / Upload tasks when tasks are finished. void OnImageDecodeTaskCompleted(const DrawImage& image, @@ -216,7 +246,8 @@ // Stores the CPU-side decoded bits of an image and supporting fields. struct DecodedImageData : public ImageDataBase { - explicit DecodedImageData(bool is_bitmap_backed); + explicit DecodedImageData(bool is_bitmap_backed, + bool do_hardware_accelerated_decode); ~DecodedImageData(); bool Lock(); @@ -255,6 +286,10 @@ bool is_yuv() const { return image_yuv_planes_.has_value(); } + bool do_hardware_accelerated_decode() const { + return do_hardware_accelerated_decode_; + } + // Test-only functions. sk_sp<SkImage> ImageForTesting() const { return image_; } @@ -278,6 +313,12 @@ std::unique_ptr<base::DiscardableMemory> data_; sk_sp<SkImage> image_; // RGBX (or null in YUV decode path) base::Optional<YUVSkImages> image_yuv_planes_; + + // |do_hardware_accelerated_decode_| keeps track of images that should go + // through hardware decode acceleration. Currently, this path is intended + // only for Chrome OS and only for some JPEG images (see + // https://crbug.com/868400). + bool do_hardware_accelerated_decode_; }; // Stores the GPU-side image and supporting fields. @@ -447,6 +488,7 @@ int upload_scale_mip_level, bool needs_mips, bool is_bitmap_backed, + bool do_hardware_accelerated_decode, bool is_yuv_format); bool IsGpuOrTransferCache() const; @@ -557,7 +599,9 @@ sk_sp<SkColorSpace> decoded_color_space) const; scoped_refptr<GpuImageDecodeCache::ImageData> CreateImageData( - const DrawImage& image); + const DrawImage& image, + bool allow_hardware_decode, + sk_sp<SkData>* encoded_data); void WillAddCacheEntry(const DrawImage& draw_image); SkImageInfo CreateImageInfoForDrawImage(const DrawImage& draw_image, int upload_scale_mip_level) const; @@ -591,7 +635,8 @@ // Requires that the |context_| lock be held when calling. void UploadImageIfNecessary(const DrawImage& draw_image, - ImageData* image_data); + ImageData* image_data, + sk_sp<SkData> encoded_data); // Flush pending operations on context_->GrContext() for each element of // |yuv_images| and then clear the vector.
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc index 6431bdb9..3e181f6 100644 --- a/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/test/scoped_feature_list.h" #include "cc/paint/draw_image.h" #include "cc/paint/image_transfer_cache_entry.h" #include "cc/paint/paint_image_builder.h" @@ -15,12 +16,20 @@ #include "cc/test/transfer_cache_test_helper.h" #include "components/viz/test/test_context_provider.h" #include "components/viz/test/test_gles2_interface.h" +#include "gpu/command_buffer/client/raster_implementation_gles.h" +#include "gpu/command_buffer/common/command_buffer_id.h" +#include "gpu/command_buffer/common/constants.h" +#include "gpu/config/gpu_finch_features.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkImageGenerator.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrContext.h" +using testing::_; +using testing::StrictMock; + namespace cc { namespace { @@ -101,13 +110,15 @@ public: explicit FakeGPUImageDecodeTestGLES2Interface( FakeDiscardableManager* discardable_manager, - TransferCacheTestHelper* transfer_cache_helper) + TransferCacheTestHelper* transfer_cache_helper, + bool advertise_accelerated_decoding) : extension_string_( "GL_EXT_texture_format_BGRA8888 GL_OES_rgb8_rgba8 " "GL_OES_texture_npot GL_EXT_texture_rg " "GL_OES_texture_half_float GL_OES_texture_half_float_linear"), discardable_manager_(discardable_manager), - transfer_cache_helper_(transfer_cache_helper) {} + transfer_cache_helper_(transfer_cache_helper), + advertise_accelerated_decoding_(advertise_accelerated_decoding) {} ~FakeGPUImageDecodeTestGLES2Interface() override { // All textures / framebuffers / renderbuffers should be cleaned up. @@ -161,6 +172,11 @@ transfer_cache_helper_->DeleteEntryDirect(MakeEntryKey(type, id)); } + bool CanDecodeWithHardwareAcceleration( + base::span<const uint8_t> encoded_data) const override { + return advertise_accelerated_decoding_; + } + std::pair<TransferCacheEntryType, uint32_t> MakeEntryKey(uint32_t type, uint32_t id) { DCHECK_LE(type, static_cast<uint32_t>(TransferCacheEntryType::kLast)); @@ -213,28 +229,73 @@ const std::string extension_string_; FakeDiscardableManager* discardable_manager_; TransferCacheTestHelper* transfer_cache_helper_; + bool advertise_accelerated_decoding_ = false; size_t mapped_entry_size_ = 0; std::unique_ptr<uint8_t[]> mapped_entry_; }; +class MockRasterImplementation : public gpu::raster::RasterImplementationGLES { + public: + explicit MockRasterImplementation(gpu::gles2::GLES2Interface* gl) + : RasterImplementationGLES(gl) {} + ~MockRasterImplementation() override = default; + + gpu::SyncToken ScheduleImageDecode(base::span<const uint8_t> encoded_data, + const gfx::Size& output_size, + uint32_t transfer_cache_entry_id, + const gfx::ColorSpace& target_color_space, + bool needs_mips) override { + DoScheduleImageDecode(output_size, transfer_cache_entry_id, + target_color_space, needs_mips); + if (!next_accelerated_decode_fails_) { + return gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(1u), + next_release_count_++); + } + return gpu::SyncToken(); + } + + void SetAcceleratedDecodingFailed() { next_accelerated_decode_fails_ = true; } + + MOCK_METHOD4(DoScheduleImageDecode, + void(const gfx::Size& /* output_size */, + uint32_t /* transfer_cache_entry_id */, + const gfx::ColorSpace& /* target_color_space */, + bool /* needs_mips */)); + + private: + bool next_accelerated_decode_fails_ = false; + uint64_t next_release_count_ = 1u; +}; + class GPUImageDecodeTestMockContextProvider : public viz::TestContextProvider { public: static scoped_refptr<GPUImageDecodeTestMockContextProvider> Create( FakeDiscardableManager* discardable_manager, - TransferCacheTestHelper* transfer_cache_helper) { + TransferCacheTestHelper* transfer_cache_helper, + bool advertise_accelerated_decoding) { + auto support = std::make_unique<FakeGPUImageDecodeTestGLES2Interface>( + discardable_manager, transfer_cache_helper, + advertise_accelerated_decoding); + auto gl = std::make_unique<FakeGPUImageDecodeTestGLES2Interface>( + discardable_manager, transfer_cache_helper, + false /* advertise_accelerated_decoding */); + auto raster = + std::make_unique<StrictMock<MockRasterImplementation>>(gl.get()); return new GPUImageDecodeTestMockContextProvider( - std::make_unique<FakeGPUImageDecodeTestGLES2Interface>( - discardable_manager, transfer_cache_helper), - std::make_unique<FakeGPUImageDecodeTestGLES2Interface>( - discardable_manager, transfer_cache_helper)); + std::move(support), std::move(gl), std::move(raster)); } private: ~GPUImageDecodeTestMockContextProvider() override = default; GPUImageDecodeTestMockContextProvider( std::unique_ptr<viz::TestContextSupport> support, - std::unique_ptr<viz::TestGLES2Interface> gl) - : TestContextProvider(std::move(support), std::move(gl), true) {} + std::unique_ptr<viz::TestGLES2Interface> gl, + std::unique_ptr<gpu::raster::RasterInterface> raster) + : TestContextProvider(std::move(support), + std::move(gl), + std::move(raster), + true) {} }; SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) { @@ -260,13 +321,21 @@ size_t kGpuMemoryLimitBytes = 96 * 1024 * 1024; class GpuImageDecodeCacheTest - : public ::testing::TestWithParam<std::tuple<SkColorType, - bool /* use_transfer_cache */, - bool /* do_yuv_decode */>> { + : public ::testing::TestWithParam< + std::tuple<SkColorType, + bool /* use_transfer_cache */, + bool /* do_yuv_decode */, + bool /* advertise_accelerated_decoding */>> { public: void SetUp() override { + advertise_accelerated_decoding_ = std::get<3>(GetParam()); + if (advertise_accelerated_decoding_) { + feature_list_.InitAndEnableFeature( + features::kVaapiJpegImageDecodeAcceleration); + } context_provider_ = GPUImageDecodeTestMockContextProvider::Create( - &discardable_manager_, &transfer_cache_helper_); + &discardable_manager_, &transfer_cache_helper_, + advertise_accelerated_decoding_); discardable_manager_.SetGLES2Interface( context_provider_->UnboundTestContextGL()); context_provider_->BindToCurrentThread(); @@ -437,12 +506,18 @@ } protected: + base::test::ScopedFeatureList feature_list_; + + // The order of these members is important because |context_provider_| depends + // on |discardable_manager_| and |transfer_cache_helper_|. FakeDiscardableManager discardable_manager_; - scoped_refptr<GPUImageDecodeTestMockContextProvider> context_provider_; TransferCacheTestHelper transfer_cache_helper_; + scoped_refptr<GPUImageDecodeTestMockContextProvider> context_provider_; + bool use_transfer_cache_; SkColorType color_type_; bool do_yuv_decode_; + bool advertise_accelerated_decoding_; int max_texture_size_ = 0; }; @@ -3091,16 +3166,347 @@ INSTANTIATE_TEST_SUITE_P( GpuImageDecodeCacheTestsInProcessRaster, GpuImageDecodeCacheTest, - testing::Combine(testing::ValuesIn(test_color_types), - testing::ValuesIn(false_array) /* use_transfer_cache */, - testing::Bool() /* do_yuv_decode */)); + testing::Combine( + testing::ValuesIn(test_color_types), + testing::ValuesIn(false_array) /* use_transfer_cache */, + testing::Bool() /* do_yuv_decode */, + testing::ValuesIn(false_array) /* advertise_accelerated_decoding */)); INSTANTIATE_TEST_SUITE_P( GpuImageDecodeCacheTestsOOPR, GpuImageDecodeCacheTest, - testing::Combine(testing::ValuesIn(test_color_types), - testing::ValuesIn(true_array) /* use_transfer_cache */, - testing::ValuesIn(false_array) /* do_yuv_decode */)); + testing::Combine( + testing::ValuesIn(test_color_types), + testing::ValuesIn(true_array) /* use_transfer_cache */, + testing::ValuesIn(false_array) /* do_yuv_decode */, + testing::ValuesIn(false_array) /* advertise_accelerated_decoding */)); + +class GpuImageDecodeCacheWithAcceleratedDecodesTest + : public GpuImageDecodeCacheTest { + public: + PaintImage CreatePaintImageForDecodeAcceleration( + const gfx::Size& size, + sk_sp<SkColorSpace> color_space = nullptr, + bool is_eligible_for_accelerated_decoding = true) { + SkImageInfo info = + SkImageInfo::Make(size.width(), size.height(), color_type_, + kPremul_SkAlphaType, color_space); + sk_sp<FakePaintImageGenerator> generator; + if (do_yuv_decode_) { + generator = + sk_make_sp<FakePaintImageGenerator>(info, GetYUV420SizeInfo(size)); + + // TODO(crbug.com/968125): even though the paint image can be decoded to + // YUV, the cache won't follow that path because it's not yet supported in + // OOPR. Remove this expectation when it is. + generator->SetExpectFallbackToRGB(); + } else { + generator = sk_make_sp<FakePaintImageGenerator>(info); + } + if (is_eligible_for_accelerated_decoding) + generator->SetEligibleForAcceleratedDecoding(); + PaintImage image = PaintImageBuilder::WithDefault() + .set_id(PaintImage::GetNextId()) + .set_paint_image_generator(generator) + .TakePaintImage(); + return image; + } + + StrictMock<MockRasterImplementation>* raster_implementation() const { + return static_cast<StrictMock<MockRasterImplementation>*>( + context_provider_->RasterInterface()); + } +}; + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + RequestAcceleratedDecodeSuccessfully) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const bool is_decomposable = true; + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image( + image, SkIRect::MakeWH(image.width(), image.height()), quality, + CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // Accelerated decodes should not produce decode tasks. + ASSERT_TRUE(result.task->dependencies().empty()); + EXPECT_CALL(*raster_implementation(), + DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _)) + .Times(1); + TestTileTaskRunner::ProcessTask(result.task.get()); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + const DecodedDrawImage decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value()); + cache->DrawWithImageFinished(draw_image, decoded_draw_image); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + RequestAcceleratedDecodeSuccessfullyWithColorSpaceConversion) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50(); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const bool is_decomposable = true; + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image( + image, SkIRect::MakeWH(image.width(), image.height()), quality, + CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // Accelerated decodes should not produce decode tasks. + ASSERT_TRUE(result.task->dependencies().empty()); + EXPECT_CALL(*raster_implementation(), + DoScheduleImageDecode(image_size, _, + cache->SupportsColorSpaceConversion() + ? target_color_space + : gfx::ColorSpace(), + _)) + .Times(1); + TestTileTaskRunner::ProcessTask(result.task.get()); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + const DecodedDrawImage decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value()); + cache->DrawWithImageFinished(draw_image, decoded_draw_image); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + AcceleratedDecodeRequestFails) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50(); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const bool is_decomposable = true; + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image( + image, SkIRect::MakeWH(image.width(), image.height()), quality, + CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // Accelerated decodes should not produce decode tasks. + ASSERT_TRUE(result.task->dependencies().empty()); + raster_implementation()->SetAcceleratedDecodingFailed(); + EXPECT_CALL(*raster_implementation(), + DoScheduleImageDecode(image_size, _, + cache->SupportsColorSpaceConversion() + ? target_color_space + : gfx::ColorSpace(), + _)) + .Times(1); + TestTileTaskRunner::ProcessTask(result.task.get()); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + const DecodedDrawImage decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + EXPECT_FALSE(decoded_draw_image.transfer_cache_entry_id().has_value()); + cache->DrawWithImageFinished(draw_image, decoded_draw_image); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + CannotRequestAcceleratedDecodeBecauseOfStandAloneDecode) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const bool is_decomposable = true; + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // A non-accelerated standalone decode should produce only a decode task. + ASSERT_TRUE(result.task->dependencies().empty()); + TestTileTaskRunner::ProcessTask(result.task.get()); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + CannotRequestAcceleratedDecodeBecauseOfNonZeroUploadMipLevel) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const bool is_decomposable = true; + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, + CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // A non-accelerated normal decode should produce a decode dependency. + ASSERT_EQ(result.task->dependencies().size(), 1u); + ASSERT_TRUE(result.task->dependencies()[0]); + TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); + TestTileTaskRunner::ProcessTask(result.task.get()); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + CannotRequestAcceleratedDecodeBecauseOfIneligiblePaintImage) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = CreatePaintImageForDecodeAcceleration( + image_size, image_color_space, + false /* is_eligible_for_accelerated_decoding */); + const bool is_decomposable = true; + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // A non-accelerated normal decode should produce a decode dependency. + ASSERT_EQ(result.task->dependencies().size(), 1u); + ASSERT_TRUE(result.task->dependencies()[0]); + TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); + TestTileTaskRunner::ProcessTask(result.task.get()); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + CannotRequestAcceleratedDecodeBecauseOfNonSRGBColorSpace) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = + SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const bool is_decomposable = true; + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // A non-accelerated normal decode should produce a decode dependency. + ASSERT_EQ(result.task->dependencies().size(), 1u); + ASSERT_TRUE(result.task->dependencies()[0]); + TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); + TestTileTaskRunner::ProcessTask(result.task.get()); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + RequestAcceleratedDecodeSuccessfullyAfterCancellation) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const bool is_decomposable = true; + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image( + image, SkIRect::MakeWH(image.width(), image.height()), quality, + CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // Accelerated decodes should not produce decode tasks. + ASSERT_TRUE(result.task->dependencies().empty()); + + // Cancel the upload. + TestTileTaskRunner::CancelTask(result.task.get()); + TestTileTaskRunner::CompleteTask(result.task.get()); + + // Get the image again - we should have an upload task. + ImageDecodeCache::TaskResult another_result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(another_result.need_unref); + ASSERT_TRUE(another_result.task); + EXPECT_EQ(another_result.task->dependencies().size(), 0u); + EXPECT_CALL(*raster_implementation(), + DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _)) + .Times(1); + TestTileTaskRunner::ProcessTask(another_result.task.get()); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + const DecodedDrawImage decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value()); + cache->DrawWithImageFinished(draw_image, decoded_draw_image); + cache->UnrefImage(draw_image); + cache->UnrefImage(draw_image); +} + +INSTANTIATE_TEST_SUITE_P( + GpuImageDecodeCacheTestsOOPR, + GpuImageDecodeCacheWithAcceleratedDecodesTest, + testing::Combine( + testing::ValuesIn(test_color_types), + testing::ValuesIn(true_array) /* use_transfer_cache */, + testing::Bool() /* do_yuv_decode */, + testing::ValuesIn(true_array) /* advertise_accelerated_decoding */)); #undef EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE #undef EXPECT_FALSE_IF_NOT_USING_TRANSFER_CACHE
diff --git a/chrome/VERSION b/chrome/VERSION index fc2beed..451f84b 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=77 MINOR=0 -BUILD=3849 +BUILD=3850 PATCH=0
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 28c9e8e06..e65c96a 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -718,7 +718,6 @@ "java/src/org/chromium/chrome/browser/gesturenav/NavigationGlowFactory.java", "java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java", "java/src/org/chromium/chrome/browser/gesturenav/SideSlideLayout.java", - "java/src/org/chromium/chrome/browser/gesturenav/TabSwitcherActionDelegate.java", "java/src/org/chromium/chrome/browser/gesturenav/TabbedActionDelegate.java", "java/src/org/chromium/chrome/browser/gsa/ContextReporter.java", "java/src/org/chromium/chrome/browser/gsa/GSAAccountChangeListener.java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java index 60cb374..4a4b3dc 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java
@@ -124,8 +124,8 @@ } @CalledByNative - private Object addUserInfoToAccessorySheetData(Object objAccessorySheetData) { - UserInfo userInfo = new UserInfo(this::fetchFavicon); + private Object addUserInfoToAccessorySheetData(Object objAccessorySheetData, String title) { + UserInfo userInfo = new UserInfo(title, this::fetchFavicon); ((AccessorySheetData) objAccessorySheetData).getUserInfoList().add(userInfo); return userInfo; }
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java index 20fec9f..8a0d98e 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java
@@ -167,7 +167,7 @@ String addressHomeZip, String addressHomeCity, String addressHomeState, String addressHomeCountry, String phoneHomeWholeNumber, String emailAddress, AtomicBoolean clickRecorder) { - UserInfo info = new UserInfo(null); + UserInfo info = new UserInfo("", null); info.addField(new UserInfoField( nameFirst, nameFirst, "", false, item -> clickRecorder.set(true))); info.addField(new UserInfoField(
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java index add50ba..c1cfbea 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java
@@ -160,7 +160,7 @@ private UserInfo createInfo( String number, String month, String year, String name, AtomicBoolean clickRecorder) { - UserInfo info = new UserInfo(null); + UserInfo info = new UserInfo("", null); info.addField( new UserInfoField(number, number, "", false, item -> clickRecorder.set(true))); info.addField(new UserInfoField(month, month, "", false, item -> clickRecorder.set(true)));
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java index 1f3d6c1..f52134f 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetModernViewTest.java
@@ -112,7 +112,7 @@ final AtomicReference<Boolean> clicked = new AtomicReference<>(false); assertThat(mView.get().getChildCount(), is(0)); - UserInfo testInfo = new UserInfo(null); + UserInfo testInfo = new UserInfo("", null); testInfo.addField(new UserInfoField( "Name Suggestion", "Name Suggestion", "", false, item -> clicked.set(true))); testInfo.addField(new UserInfoField(
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewTest.java index ea48be0..36a4aff6 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetViewTest.java
@@ -124,7 +124,7 @@ final AtomicReference<Boolean> clicked = new AtomicReference<>(false); assertThat(mView.get().getChildCount(), is(0)); - UserInfo testInfo = new UserInfo(null); + UserInfo testInfo = new UserInfo("", null); testInfo.addField(new UserInfoField( "Name Suggestion", "Name Suggestion", "", false, item -> clicked.set(true))); testInfo.addField(new UserInfoField(
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java index 9d2b738..1e1851f 100644 --- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java +++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingControllerTest.java
@@ -203,7 +203,7 @@ void providePasswordSheet(String passwordString) { AccessorySheetData sheetData = new AccessorySheetData(AccessoryTabType.PASSWORDS, "Passwords"); - UserInfo userInfo = new UserInfo(null); + UserInfo userInfo = new UserInfo("", null); userInfo.addField( new UserInfoField("(No username)", "No username", /*id=*/"", false, null)); userInfo.addField(new UserInfoField(passwordString, "Password", /*id=*/"", true, null));
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetControllerTest.java index be346150..85ce466 100644 --- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetControllerTest.java +++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetControllerTest.java
@@ -121,7 +121,7 @@ final PropertyProvider<AccessorySheetData> testProvider = new PropertyProvider<>(); final AccessorySheetData testData = new AccessorySheetData(AccessoryTabType.ADDRESSES, "Addresses for this site"); - testData.getUserInfoList().add(new UserInfo(null)); + testData.getUserInfoList().add(new UserInfo("", null)); testData.getUserInfoList().get(0).addField( new UserInfoField("Name", "Name", "", false, null)); testData.getUserInfoList().get(0).addField( @@ -149,7 +149,7 @@ assertThat(mSheetDataPieces.get(0).getDataPiece(), is(equalTo("No addresses"))); // As soon UserInfo is available, discard the title. - testData.getUserInfoList().add(new UserInfo(null)); + testData.getUserInfoList().add(new UserInfo("", null)); testData.getUserInfoList().get(0).addField( new UserInfoField("Name", "Name", "", false, null)); testData.getUserInfoList().get(0).addField(
diff --git a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java index 1004255..b8f4fe7 100644 --- a/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java +++ b/chrome/android/features/keyboard_accessory/junit/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/PasswordAccessorySheetControllerTest.java
@@ -125,7 +125,7 @@ final PropertyProvider<AccessorySheetData> testProvider = new PropertyProvider<>(); final AccessorySheetData testData = new AccessorySheetData(AccessoryTabType.PASSWORDS, "Passwords for this site"); - testData.getUserInfoList().add(new UserInfo(null)); + testData.getUserInfoList().add(new UserInfo("", null)); testData.getUserInfoList().get(0).addField( new UserInfoField("Name", "Name", "", false, null)); testData.getUserInfoList().get(0).addField( @@ -162,7 +162,7 @@ assertThat(mSheetDataPieces.get(0).getDataPiece(), is(equalTo("No passwords for this"))); // As soon UserInfo is available, discard the title. - testData.getUserInfoList().add(new UserInfo(null)); + testData.getUserInfoList().add(new UserInfo("", null)); testData.getUserInfoList().get(0).addField( new UserInfoField("Name", "Name", "", false, null)); testData.getUserInfoList().get(0).addField( @@ -206,15 +206,15 @@ assertThat(getSuggestionsImpressions(AccessoryTabType.ALL, 0), is(1)); // If the tab is shown with X interactive item, record "X" samples. - UserInfo userInfo1 = new UserInfo(null); + UserInfo userInfo1 = new UserInfo("", null); userInfo1.addField(new UserInfoField("Interactive 1", "", "", false, (v) -> {})); userInfo1.addField(new UserInfoField("Non-Interactive 1", "", "", true, null)); accessorySheetData.getUserInfoList().add(userInfo1); - UserInfo userInfo2 = new UserInfo(null); + UserInfo userInfo2 = new UserInfo("", null); userInfo2.addField(new UserInfoField("Interactive 2", "", "", false, (v) -> {})); userInfo2.addField(new UserInfoField("Non-Interactive 2", "", "", true, null)); accessorySheetData.getUserInfoList().add(userInfo2); - UserInfo userInfo3 = new UserInfo(null); + UserInfo userInfo3 = new UserInfo("other.origin.eg", null); userInfo3.addField(new UserInfoField("Interactive 3", "", "", false, (v) -> {})); userInfo3.addField(new UserInfoField("Non-Interactive 3", "", "", true, null)); accessorySheetData.getUserInfoList().add(userInfo3);
diff --git a/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/data/KeyboardAccessoryData.java b/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/data/KeyboardAccessoryData.java index 8d76c5f..73c690ef 100644 --- a/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/data/KeyboardAccessoryData.java +++ b/chrome/android/features/keyboard_accessory/public/java/src/org/chromium/chrome/browser/keyboard_accessory/data/KeyboardAccessoryData.java
@@ -175,6 +175,7 @@ * (username + password), to be shown on the manual fallback UI. */ public final static class UserInfo { + private final String mTitle; private final List<UserInfoField> mFields = new ArrayList<>(); private final @Nullable FaviconProvider mFaviconProvider; @@ -190,7 +191,8 @@ void fetchFavicon(@Px int desiredSize, Callback<Bitmap> favicon); } - public UserInfo(@Nullable FaviconProvider faviconProvider) { + public UserInfo(String title, @Nullable FaviconProvider faviconProvider) { + mTitle = title; mFaviconProvider = faviconProvider; } @@ -203,13 +205,20 @@ } /** - * Returns the list of fields in this group. + * @return A list of {@link UserInfoField}s in this group. */ public List<UserInfoField> getFields() { return mFields; } /** + * @return A string to be used as title. May be empty but not null. + */ + public String getTitle() { + return mTitle; + } + + /** * Possibly holds a favicon provider. * @return A {@link FaviconProvider}. Optional. */
diff --git a/chrome/android/features/tab_ui/java/res/layout/grid_tab_switcher_layout.xml b/chrome/android/features/tab_ui/java/res/layout/grid_tab_switcher_layout.xml deleted file mode 100644 index 9d21981..0000000 --- a/chrome/android/features/tab_ui/java/res/layout/grid_tab_switcher_layout.xml +++ /dev/null
@@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2019 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. --> -<org.chromium.chrome.browser.gesturenav.HistoryNavigationLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:id="@+id/history_navigation" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <org.chromium.chrome.browser.tasks.tab_management.TabListRecyclerView - android:id="@+id/tab_list_view" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:clipToPadding="false" - android:paddingStart="8dp" - android:paddingEnd="8dp" - android:visibility="invisible"/> -</org.chromium.chrome.browser.gesturenav.HistoryNavigationLayout>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java index 2310a08..45e53677 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java
@@ -17,8 +17,6 @@ import org.chromium.chrome.browser.compositor.CompositorViewHolder; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; -import org.chromium.chrome.browser.gesturenav.HistoryNavigationDelegate; -import org.chromium.chrome.browser.gesturenav.HistoryNavigationLayout; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.Destroyable; import org.chromium.chrome.browser.snackbar.SnackbarManager; @@ -118,14 +116,7 @@ tabModelSelector, mMultiThumbnailCardProvider, titleProvider, true, mMediator::getCreateGroupButtonOnClickListener, gridCardOnClickListenerProvider, null, null, null, compositorViewHolder, - compositorViewHolder.getDynamicResourceLoader(), true, - R.layout.grid_tab_switcher_layout, COMPONENT_NAME); - - HistoryNavigationLayout navigation = - compositorViewHolder.findViewById(R.id.history_navigation); - - navigation.setNavigationDelegate(HistoryNavigationDelegate.createForTabSwitcher( - context, backPress, tabModelSelector::getCurrentTab)); + compositorViewHolder.getDynamicResourceLoader(), true, COMPONENT_NAME); mContainerViewChangeProcessor = PropertyModelChangeProcessor.create(containerViewModel, mTabGridCoordinator.getContainerView(), TabGridContainerViewBinder::bind); @@ -218,4 +209,12 @@ void setBitmapCallbackForTesting(Callback<Bitmap> callback) { TabListMediator.ThumbnailFetcher.sBitmapCallbackForTesting = callback; } + + /** + * @return The number of thumbnail fetching for testing. + */ + @VisibleForTesting + int getBitmapFetchCountForTesting() { + return TabListMediator.ThumbnailFetcher.sFetchCountForTesting; + } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java index 09ee3e6..9035def 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java
@@ -12,7 +12,6 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabCreatorManager; import org.chromium.chrome.browser.tabmodel.TabModelSelector; -import org.chromium.chrome.tab_ui.R; import org.chromium.ui.modelutil.PropertyModel; import java.util.List; @@ -47,7 +46,7 @@ mTabListCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context, tabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, null, null, mMediator.getTabGridDialogHandler(), null, null, compositorViewHolder, null, - false, R.layout.tab_list_recycler_view_layout, COMPONENT_NAME); + false, COMPONENT_NAME); mParentLayout = new TabGridDialogParent(context, compositorViewHolder); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java index 48bb0c8..fb18034 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java
@@ -17,7 +17,6 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupUtils; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; -import org.chromium.chrome.tab_ui.R; import org.chromium.ui.modelutil.PropertyModel; import java.util.List; @@ -46,7 +45,7 @@ mTabGridCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context, tabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, null, null, null, null, null, bottomSheetController.getBottomSheet(), null, false, - R.layout.tab_list_recycler_view_layout, COMPONENT_NAME); + COMPONENT_NAME); mMediator = new TabGridSheetMediator(mContext, bottomSheetController, this::resetWithListOfTabs, mToolbarPropertyModel, tabModelSelector,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java index 0074321..bcff5e2f 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
@@ -24,7 +24,6 @@ import org.chromium.chrome.browser.tasks.tabgroup.TabGroupModelFilter; import org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator; import org.chromium.chrome.browser.util.FeatureUtilities; -import org.chromium.chrome.tab_ui.R; import org.chromium.ui.modelutil.PropertyModel; import java.util.List; @@ -78,8 +77,7 @@ mTabStripCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.STRIP, mContext, tabModelSelector, null, null, false, null, null, null, null, null, - mTabStripToolbarCoordinator.getTabListContainerView(), null, true, - R.layout.tab_list_recycler_view_layout, COMPONENT_NAME); + mTabStripToolbarCoordinator.getTabListContainerView(), null, true, COMPONENT_NAME); if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled()) { // TODO(yuezhanggg): find a way to enable interactions between grid tab switcher and the
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java index 3103aff..99c26b5 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
@@ -8,7 +8,6 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.support.annotation.IntDef; -import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.GridLayoutManager; @@ -80,7 +79,6 @@ * @param dynamicResourceLoader The {@link DynamicResourceLoader} to register dynamic UI * resource for compositor layer animation. * @param attachToParent Whether the UI should attach to root view. - * @param layoutId ID of the layout resource. * @param componentName A unique string uses to identify different components for UMA recording. * Recommended to use the class name or make sure the string is unique * through actions.xml file. @@ -95,7 +93,7 @@ SimpleRecyclerViewMcpBase.ItemViewTypeCallback<PropertyModel> itemViewTypeCallback, TabListMediator.SelectionDelegateProvider selectionDelegateProvider, @NonNull ViewGroup parentView, @Nullable DynamicResourceLoader dynamicResourceLoader, - boolean attachToParent, @LayoutRes int layoutId, String componentName) { + boolean attachToParent, String componentName) { TabListModel tabListModel = new TabListModel(); mMode = mode; mTabModelSelector = tabModelSelector; @@ -127,11 +125,13 @@ throw new IllegalArgumentException( "Attempting to create a tab list UI with invalid mode"); } + if (!attachToParent) { mRecyclerView = (TabListRecyclerView) LayoutInflater.from(context).inflate( - layoutId, parentView, false); + R.layout.tab_list_recycler_view_layout, parentView, false); } else { - LayoutInflater.from(context).inflate(layoutId, parentView, true); + LayoutInflater.from(context).inflate( + R.layout.tab_list_recycler_view_layout, parentView, true); mRecyclerView = parentView.findViewById(R.id.tab_list_view); } @@ -230,6 +230,7 @@ void postHiding() { mRecyclerView.postHiding(); + mMediator.postHiding(); } /**
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java index b081112..f5007cc 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -29,6 +29,7 @@ import org.chromium.chrome.browser.tab.TabObserver; import org.chromium.chrome.browser.tabmodel.EmptyTabModelFilter; import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; +import org.chromium.chrome.browser.tabmodel.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabList; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelObserver; @@ -56,6 +57,7 @@ * TODO(yusufo): Move some of the logic here to a parent component to make the above true. */ class TabListMediator { + private boolean mVisible; private boolean mShownIPH; /** @@ -100,6 +102,7 @@ */ static class ThumbnailFetcher { static Callback<Bitmap> sBitmapCallbackForTesting; + static int sFetchCountForTesting; private ThumbnailProvider mThumbnailProvider; private Tab mTab; private boolean mForceUpdate; @@ -118,6 +121,7 @@ if (sBitmapCallbackForTesting != null) sBitmapCallbackForTesting.onResult(bitmap); callback.onResult(bitmap); }; + sFetchCountForTesting++; mThumbnailProvider.getTabThumbnailWithCallback( mTab, forking, mForceUpdate, mWriteToCache); } @@ -393,7 +397,8 @@ } @Override - public void didAddTab(Tab tab, int type) { + public void didAddTab(Tab tab, @TabLaunchType int type) { + if (type == TabLaunchType.FROM_RESTORE) return; onTabAdded(tab, !mActionsOnAllRelatedTabs); } @@ -656,6 +661,7 @@ * The selected border should re-appear in the final fading-in stage. */ void prepareOverview() { + assert mVisible; int count = 0; for (int i = 0; i < mModel.size(); i++) { if (mModel.get(i).get(TabProperties.IS_SELECTED)) count++; @@ -684,6 +690,7 @@ * @return Whether the {@link TabListRecyclerView} can be shown quickly. */ boolean resetWithListOfTabs(@Nullable List<Tab> tabs, boolean quickMode) { + mVisible = tabs != null; if (areTabsUnchanged(tabs)) { if (tabs == null) return true; @@ -708,6 +715,10 @@ return false; } + void postHiding() { + mVisible = false; + } + private boolean isSelectedTab(int tabId, int tabModelSelectedTabId) { SelectionDelegate<Integer> selectionDelegate = getTabSelectionDelegate(); if (selectionDelegate == null) { @@ -721,6 +732,7 @@ * @see GridTabSwitcherMediator.ResetHandler#softCleanup */ void softCleanup() { + assert !mVisible; for (int i = 0; i < mModel.size(); i++) { mModel.get(i).set(TabProperties.THUMBNAIL_FETCHER, null); } @@ -757,7 +769,7 @@ mTabListFaviconProvider.getFaviconForUrlAsync( tab.getUrl(), tab.isIncognito(), faviconCallback); boolean forceUpdate = isSelected && !quickMode; - if (mThumbnailProvider != null + if (mThumbnailProvider != null && mVisible && (mModel.get(index).get(TabProperties.THUMBNAIL_FETCHER) == null || forceUpdate || isUpdatingId)) { ThumbnailFetcher callback = new ThumbnailFetcher(mThumbnailProvider, tab, forceUpdate, @@ -870,7 +882,7 @@ mTabListFaviconProvider.getFaviconForUrlAsync( tab.getUrl(), tab.isIncognito(), faviconCallback); - if (mThumbnailProvider != null) { + if (mThumbnailProvider != null && mVisible) { ThumbnailFetcher callback = new ThumbnailFetcher(mThumbnailProvider, tab, isSelected, isSelected && !ChromeFeatureList.isEnabled(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorCoordinator.java index 7540ccb..12a7963b 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorCoordinator.java
@@ -59,7 +59,7 @@ mTabListCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context, mTabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, null, null, null, this::getItemViewType, this::getSelectionDelegate, null, null, - false, R.layout.tab_list_recycler_view_layout, COMPONENT_NAME); + false, COMPONENT_NAME); mTabSelectionEditorLayout = LayoutInflater.from(context) .inflate(R.layout.tab_selection_editor_layout, null)
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherLayoutTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherLayoutTest.java index b92c130..de7b05d 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherLayoutTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherLayoutTest.java
@@ -43,6 +43,7 @@ import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.util.ApplicationTestUtils; import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.chrome.test.util.MenuUtils; import org.chromium.chrome.test.util.browser.Features; @@ -97,6 +98,7 @@ GridTabSwitcherCoordinator coordinator = (GridTabSwitcherCoordinator) mGtsLayout.getGridTabSwitcherForTesting(); coordinator.setBitmapCallbackForTesting(mBitmapListener); + Assert.assertEquals(0, coordinator.getBitmapFetchCountForTesting()); mActivityTestRule.getActivity().getTabContentManager().setCaptureMinRequestTimeForTesting( 0); @@ -325,6 +327,98 @@ assertThumbnailsAreReleased(); } + @Test + @MediumTest + @CommandLineFlags. + Add({"force-fieldtrial-params=Study.Group:soft-cleanup-delay/0/cleanup-delay/0"}) + public void testRestoredTabsDontFetch() throws Exception { + prepareTabs(2, mUrl); + GridTabSwitcherCoordinator coordinator = + (GridTabSwitcherCoordinator) mGtsLayout.getGridTabSwitcherForTesting(); + int oldCount = coordinator.getBitmapFetchCountForTesting(); + + // Restart Chrome. + // Although we're destroying the activity, the Application will still live on since its in + // the same process as this test. + ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity()); + mActivityTestRule.startMainActivityOnBlankPage(); + Assert.assertEquals(3, mActivityTestRule.tabsCount(false)); + + Layout layout = mActivityTestRule.getActivity().getLayoutManager().getOverviewLayout(); + assertTrue(layout instanceof GridTabSwitcherLayout); + mGtsLayout = (GridTabSwitcherLayout) layout; + coordinator = (GridTabSwitcherCoordinator) mGtsLayout.getGridTabSwitcherForTesting(); + Assert.assertEquals(0, coordinator.getBitmapFetchCountForTesting() - oldCount); + } + + @Test + @MediumTest + @CommandLineFlags. + Add({"force-fieldtrial-params=Study.Group:soft-cleanup-delay/0/cleanup-delay/0"}) + public void testInvisibleTabsDontFetch() throws InterruptedException { + // Open a few new tabs. + final int count = mAllBitmaps.size(); + for (int i = 0; i < 3; i++) { + MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), + mActivityTestRule.getActivity(), org.chromium.chrome.R.id.new_tab_menu_id); + } + // Fetching might not happen instantly. + Thread.sleep(1000); + + // No fetching should happen. + Assert.assertEquals(0, mAllBitmaps.size() - count); + } + + @Test + @MediumTest + @CommandLineFlags. + Add({"force-fieldtrial-params=Study.Group:soft-cleanup-delay/10000/cleanup-delay/10000"}) + public void testInvisibleTabsDontFetchWarm() throws InterruptedException { + // Get the GTS in the warm state. + prepareTabs(2, NTP_URL); + mRepeat = 2; + testTabToGrid(NTP_URL); + + Thread.sleep(1000); + + // Open a few new tabs. + final int count = mAllBitmaps.size(); + for (int i = 0; i < 3; i++) { + MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), + mActivityTestRule.getActivity(), org.chromium.chrome.R.id.new_tab_menu_id); + } + // Fetching might not happen instantly. + Thread.sleep(1000); + + // No fetching should happen. + Assert.assertEquals(0, mAllBitmaps.size() - count); + } + + @Test + @MediumTest + @CommandLineFlags. + Add({"force-fieldtrial-params=Study.Group:soft-cleanup-delay/0/cleanup-delay/10000"}) + public void testInvisibleTabsDontFetchSoft() throws InterruptedException { + // Get the GTS in the soft cleaned up state. + prepareTabs(2, NTP_URL); + mRepeat = 2; + testTabToGrid(NTP_URL); + + Thread.sleep(1000); + + // Open a few new tabs. + final int count = mAllBitmaps.size(); + for (int i = 0; i < 3; i++) { + MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), + mActivityTestRule.getActivity(), org.chromium.chrome.R.id.new_tab_menu_id); + } + // Fetching might not happen instantly. + Thread.sleep(1000); + + // No fetching should happen. + Assert.assertEquals(0, mAllBitmaps.size() - count); + } + private void enterGTS() throws InterruptedException { Tab currentTab = mActivityTestRule.getActivity().getTabModelSelector().getCurrentTab(); // Native tabs need to be invalidated first to trigger thumbnail taking, so skip them.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java index 47e66a8..572c3126 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java
@@ -24,6 +24,8 @@ import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JCaller; +import org.chromium.base.annotations.NativeMethods; import org.chromium.chrome.R; import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer; import org.chromium.chrome.browser.profiles.Profile; @@ -246,7 +248,8 @@ // Called to report the permission dialog's results back to native code. private void finishDialog(int resultCode) { if (mNativeBluetoothScanningPermissionDialogPtr == 0) return; - nativeOnDialogFinished(mNativeBluetoothScanningPermissionDialogPtr, resultCode); + Natives jni = BluetoothScanningPermissionDialogJni.get(); + jni.onDialogFinished(this, mNativeBluetoothScanningPermissionDialogPtr, resultCode); } /** @@ -265,6 +268,9 @@ return mItemAdapter; } - @VisibleForTesting - native void nativeOnDialogFinished(long nativeBluetoothScanningPromptAndroid, int eventType); + @NativeMethods + interface Natives { + void onDialogFinished(@JCaller BluetoothScanningPermissionDialog self, + long nativeBluetoothScanningPromptAndroid, int eventType); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java index 27aa683..cc87225 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
@@ -12,7 +12,6 @@ import android.os.SystemClock; import android.support.annotation.IntDef; import android.util.Pair; -import android.view.MotionEvent; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.FrameLayout; @@ -41,9 +40,6 @@ import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer; import org.chromium.chrome.browser.compositor.scene_layer.TabListSceneLayer; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; -import org.chromium.chrome.browser.gesturenav.NavigationGlowFactory; -import org.chromium.chrome.browser.gesturenav.NavigationHandler; -import org.chromium.chrome.browser.gesturenav.TabSwitcherActionDelegate; import org.chromium.chrome.browser.partnercustomizations.HomepageManager; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabList; @@ -230,10 +226,8 @@ private final GestureEventFilter mGestureEventFilter; private final TabListSceneLayer mSceneLayer; - private final boolean mNavigationEnabled; private StackLayoutGestureHandler mGestureHandler; - private NavigationHandler mNavigationHandler; private final ArrayList<Pair<CompositorAnimator, FloatProperty>> mLayoutAnimations = new ArrayList<>(); @@ -248,7 +242,6 @@ mLastOnDownTimeStamp = time; if (shouldIgnoreTouchInput()) return; - if (mNavigationHandler != null) mNavigationHandler.onDown(); mStacks.get(getTabStackIndex()).onDown(time); } @@ -261,15 +254,6 @@ public void drag(float x, float y, float dx, float dy, float tx, float ty) { if (shouldIgnoreTouchInput()) return; - if (mNavigationHandler != null) { - mNavigationHandler.onScroll(mLastOnDownX * mDpToPx, -dx * mDpToPx, -dy * mDpToPx, - x * mDpToPx, y * mDpToPx); - if (mNavigationHandler.isActive()) { - cancelDragTabs(time()); - return; - } - } - @SwipeMode int oldInputMode = mInputMode; long time = time(); @@ -353,10 +337,6 @@ private void onUpOrCancel(long time) { if (shouldIgnoreTouchInput()) return; - - if (mNavigationHandler != null && mNavigationHandler.isActive()) { - mNavigationHandler.onTouchEvent(MotionEvent.ACTION_UP); - } cancelDragTabs(time); } @@ -405,8 +385,6 @@ mStackRects = new ArrayList<RectF>(); mViewContainer = new FrameLayout(getContext()); mSceneLayer = new TabListSceneLayer(); - mNavigationEnabled = - ChromeFeatureList.isEnabled(ChromeFeatureList.OVERSCROLL_HISTORY_NAVIGATION); mDpToPx = context.getResources().getDisplayMetrics().density; } @@ -520,16 +498,6 @@ onTabClosureCancelled(LayoutManager.time(), tab.getId(), tab.isIncognito()); } }; - if (mNavigationEnabled && mNavigationHandler == null) { - Tab currentTab = mTabModelSelector.getCurrentTab(); - if (currentTab != null) { - mNavigationHandler = new NavigationHandler(mViewContainer, - new TabSwitcherActionDelegate(currentTab.getActivity()::onBackPressed, - mTabModelSelector::getCurrentTab), - NavigationGlowFactory.forSceneLayer(mViewContainer, mSceneLayer, - currentTab.getActivity().getWindowAndroid())); - } - } } /** @@ -1677,7 +1645,6 @@ @Override public void destroy() { - if (mNavigationHandler != null) mNavigationHandler.destroy(); super.destroy(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardViewHolderFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardViewHolderFactory.java index 4e79013..c257319 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardViewHolderFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/CategoryCardViewHolderFactory.java
@@ -17,7 +17,7 @@ CategoryCardViewHolderFactory.CategoryCardViewHolder> { private int mTileViewResource; - CategoryCardViewHolderFactory() { + public CategoryCardViewHolderFactory() { final int exploreSitesDenseVariation = ExploreSitesBridge.getDenseVariation(); // Set the tile view to use based on the condensed variation. if (ExploreSitesBridge.isDense(exploreSitesDenseVariation)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/CompositorNavigationGlow.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/CompositorNavigationGlow.java index a0bc146c..5cc8166 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/CompositorNavigationGlow.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/CompositorNavigationGlow.java
@@ -7,9 +7,7 @@ import android.view.ViewGroup; import org.chromium.base.annotations.JNINamespace; -import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer; import org.chromium.content_public.browser.WebContents; -import org.chromium.ui.base.WindowAndroid; /** * Implements navigation glow using compositor layer for tab switcher or rendered web contents. @@ -25,36 +23,10 @@ * for rendering glow effect. * @return NavigationGlow object for rendered pages */ - public static NavigationGlow forWebContents(ViewGroup parentView, WebContents webContents) { - CompositorNavigationGlow glow = new CompositorNavigationGlow(parentView); - glow.initWithWebContents(webContents); - return glow; - } - - /** - * @pararm parentView Parent view where the glow view gets attached to. - * @pararm sceneLayer SceneLayer whose cc layer will be used for rendering glow effect. - * @pararm window WindowAndroid object to get WindowAndroidCompositor from for animation effect. - * @return {@link NavigationGlow} object for the screen rendered with {@link SceneLayer} - */ - public static NavigationGlow forSceneLayer( - ViewGroup parentView, SceneLayer sceneLayer, WindowAndroid window) { - CompositorNavigationGlow glow = new CompositorNavigationGlow(parentView); - glow.initWithSceneLayer(sceneLayer, window); - return glow; - } - - private CompositorNavigationGlow(ViewGroup parentView) { + public CompositorNavigationGlow(ViewGroup parentView, WebContents webContents) { super(parentView); - mNativeNavigationGlow = nativeInit(parentView.getResources().getDisplayMetrics().density); - } - - private void initWithSceneLayer(SceneLayer sceneLayer, WindowAndroid window) { - nativeInitWithSceneLayer(mNativeNavigationGlow, sceneLayer, window); - } - - private void initWithWebContents(WebContents webContents) { - nativeInitWithWebContents(mNativeNavigationGlow, webContents); + mNativeNavigationGlow = + nativeInit(parentView.getResources().getDisplayMetrics().density, webContents); } @Override @@ -91,11 +63,7 @@ mNativeNavigationGlow = 0; } - private native long nativeInit(float dipScale); - private native void nativeInitWithSceneLayer( - long nativeNavigationGlow, SceneLayer sceneLayer, WindowAndroid window); - private native void nativeInitWithWebContents( - long nativeNavigationGlow, WebContents webContents); + private native long nativeInit(float dipScale, WebContents webContents); private native void nativePrepare( long nativeNavigationGlow, float startX, float startY, int width, int height); private native void nativeOnOverscroll(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationDelegate.java index 4ed99c2b..9632dfeb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationDelegate.java
@@ -6,7 +6,6 @@ import android.content.Context; -import org.chromium.base.Supplier; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.tab.Tab; @@ -65,31 +64,4 @@ public static HistoryNavigationDelegate createForNativePage(Tab tab) { return new NativePageDelegate(tab); } - - // Implementation for tab switcher. Can't go forward, and going back exits - // the switcher. Can exit Chrome if there's no current tab to go back to. - private static class TabSwitcherNavigationDelegate extends HistoryNavigationDelegate { - private final Runnable mBackPress; - private final Supplier<Tab> mCurrentTab; - - private TabSwitcherNavigationDelegate( - Context context, Runnable backPress, Supplier<Tab> currentTab) { - super(context); - mBackPress = backPress; - mCurrentTab = currentTab; - } - - @Override - public NavigationHandler.ActionDelegate createActionDelegate() { - return new TabSwitcherActionDelegate(mBackPress, mCurrentTab); - } - } - - /** - * Creates {@link HistoryNavigationDelegate} for tab switcher. - */ - public static HistoryNavigationDelegate createForTabSwitcher( - Context context, Runnable backPress, Supplier<Tab> currentTab) { - return new TabSwitcherNavigationDelegate(context, backPress, currentTab); - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationGlowFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationGlowFactory.java index d0bb5ec..c31a6e0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationGlowFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationGlowFactory.java
@@ -7,9 +7,7 @@ import android.view.ViewGroup; import org.chromium.base.Supplier; -import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer; import org.chromium.content_public.browser.WebContents; -import org.chromium.ui.base.WindowAndroid; /** * Factory class that provides {@link NavigationGlow} according to the actual surface @@ -18,25 +16,13 @@ public class NavigationGlowFactory { /** * @pararm parentView Parent view where the glow view gets attached to. - * @pararm sceneLayer SceneLayer whose cc layer will be used for rendering glow effect. - * @pararm window WindowAndroid object to get WindowAndroidCompositor from for animation effect. - * @return Supplier for {@link NavigationGlow} object for the screen rendered with {@link - * SceneLayer}. - */ - public static Supplier<NavigationGlow> forSceneLayer( - ViewGroup parentView, SceneLayer sceneLayer, WindowAndroid window) { - return () -> CompositorNavigationGlow.forSceneLayer(parentView, sceneLayer, window); - } - - /** - * @pararm parentView Parent view where the glow view gets attached to. * @pararm webContents WebContents whose native view's cc layer will be used * for rendering glow effect. * @return Supplier for {@link NavigationGlow} object for rendered pages. */ public static Supplier<NavigationGlow> forRenderedPage( ViewGroup parentView, WebContents webContents) { - return () -> CompositorNavigationGlow.forWebContents(parentView, webContents); + return () -> new CompositorNavigationGlow(parentView, webContents); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabSwitcherActionDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabSwitcherActionDelegate.java deleted file mode 100644 index a8122e7..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabSwitcherActionDelegate.java +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2019 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.gesturenav; - -import org.chromium.base.Supplier; -import org.chromium.chrome.browser.tab.Tab; - -/** - * Implementation of {@link NavigationHandler#ActionDelegate} that works for Tab switcher. - * Swipe from left exits the tab switcher and goes back to the current tab. Can exit - * Chrome app itself if there's no current tab. - */ -public class TabSwitcherActionDelegate implements NavigationHandler.ActionDelegate { - private final Supplier<Tab> mCurrentTab; - private final Runnable mBackPress; - - public TabSwitcherActionDelegate(Runnable backPress, Supplier<Tab> currentTab) { - mBackPress = backPress; - mCurrentTab = currentTab; - } - - @Override - public boolean canNavigate(boolean forward) { - return !forward; - } - - @Override - public void navigate(boolean forward) { - assert !forward : "Should be called only for back navigation"; - mBackPress.run(); - } - - @Override - public boolean willBackExitApp() { - return mCurrentTab.get() == null; - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelFilter.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelFilter.java index cfacc71..bee34dc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelFilter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelFilter.java
@@ -171,7 +171,7 @@ } @Override - public void didAddTab(Tab tab, int type) { + public void didAddTab(Tab tab, @TabLaunchType int type) { addTab(tab); for (TabModelObserver observer : mFilteredObservers) { observer.didAddTab(tab, type);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java index 6c5e472..0377dc93 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -1810,7 +1810,7 @@ if (inTabSwitcherMode) { if (mUrlFocusLayoutAnimator != null && mUrlFocusLayoutAnimator.isRunning()) { - mUrlFocusLayoutAnimator.cancel(); + mUrlFocusLayoutAnimator.end(); mUrlFocusLayoutAnimator = null; // After finishing the animation, force a re-layout of the location bar, // so that the final translation position is correct (since onMeasure updates
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java index a5a9cf8e..5d431fc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java
@@ -16,7 +16,9 @@ import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.annotations.JCaller; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.R; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -25,7 +27,6 @@ import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.ui.base.ActivityWindowAndroid; -import org.chromium.ui.base.WindowAndroid; /** * Tests for the BluetoothScanningPermissionDialog class. @@ -33,45 +34,41 @@ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) public class BluetoothScanningPermissionDialogTest { - /** - * Works like the BluetoothScanningPermissionDialog class, but records calls to native methods - * instead of calling back to C++. - */ - static class BluetoothScanningPermissionDialogWithFakeNatives - extends BluetoothScanningPermissionDialog { - int mFinishedEventType = -1; - - BluetoothScanningPermissionDialogWithFakeNatives( - WindowAndroid windowAndroid, String origin, int securityLevel) { - super(windowAndroid, origin, securityLevel, - /*nativeBluetoothScanningPermissionDialogPtr=*/42); - } - - @Override - void nativeOnDialogFinished(long nativeBluetoothScanningPromptAndroid, int eventType) { - mFinishedEventType = eventType; - } - } - - private ActivityWindowAndroid mWindowAndroid; - private BluetoothScanningPermissionDialogWithFakeNatives mPermissionDialog; - @Rule public ChromeActivityTestRule<ChromeActivity> mActivityTestRule = new ChromeActivityTestRule<>(ChromeActivity.class); + @Rule + public JniMocker mocker = new JniMocker(); + + private int mFinishedEventType = -1; + + private ActivityWindowAndroid mWindowAndroid; + private BluetoothScanningPermissionDialog mPermissionDialog; + + private class TestBluetoothScanningPermissionDialogJni + implements BluetoothScanningPermissionDialog.Natives { + @Override + public void onDialogFinished(@JCaller BluetoothScanningPermissionDialog self, + long nativeBluetoothScanningPromptAndroid, int eventType) { + mFinishedEventType = eventType; + } + } + @Before public void setUp() throws Exception { + mocker.mock(BluetoothScanningPermissionDialogJni.TEST_HOOKS, + new TestBluetoothScanningPermissionDialogJni()); mActivityTestRule.startMainActivityOnBlankPage(); mPermissionDialog = createDialog(); } - private BluetoothScanningPermissionDialogWithFakeNatives createDialog() { + private BluetoothScanningPermissionDialog createDialog() { return TestThreadUtils.runOnUiThreadBlockingNoException(() -> { mWindowAndroid = new ActivityWindowAndroid(mActivityTestRule.getActivity()); - BluetoothScanningPermissionDialogWithFakeNatives dialog = - new BluetoothScanningPermissionDialogWithFakeNatives(mWindowAndroid, - "https://origin.example.com/", ConnectionSecurityLevel.SECURE); + BluetoothScanningPermissionDialog dialog = new BluetoothScanningPermissionDialog( + mWindowAndroid, "https://origin.example.com/", ConnectionSecurityLevel.SECURE, + /*nativeBluetoothScanningPermissionDialogPtr=*/42); return dialog; }); } @@ -123,7 +120,7 @@ dialog.cancel(); - CriteriaHelper.pollUiThread(Criteria.equals(BluetoothScanningPermissionEvent.CANCELED, - () -> mPermissionDialog.mFinishedEventType)); + CriteriaHelper.pollUiThread(Criteria.equals( + BluetoothScanningPermissionEvent.CANCELED, () -> mFinishedEventType)); } }
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 524966f..a295d15 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-77.0.3847.0_rc-r1-merged.afdo.bz2 \ No newline at end of file +chromeos-chrome-amd64-77.0.3849.0_rc-r1-merged.afdo.bz2 \ No newline at end of file
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 60b8e1f..29009266 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -2857,6 +2857,12 @@ <message name="IDS_NETWORK_UI_NO_CELLULAR_ERROR_TEXT" desc="Text displayed when the cellular activation UI cannot be opened because no cellular network exists."> No cellular network exists </message> + <message name="IDS_NETWORK_UI_ADD_NEW_WIFI_LABEL" desc="Label for section dealing with showing the 'Add new Wi-Fi network' dialog."> + New Wi-Fi Network Dialog + </message> + <message name="IDS_NETWORK_UI_ADD_NEW_WIFI_BUTTON_TEXT" desc="Text for button which, when pressed, opens the 'Add new Wi-Fi network' dialog."> + Show 'Add new Wi-Fi' dialog + </message> <message name="IDS_DEVICE_LOG_LINK_TEXT" desc="Message preceeding link to chrome://device-log"> For network logs, see: <ph name="DEVICE_LOG_LINK"><a href="chrome://device-log">chrome://device-log</a></ph>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 00f4bd3..acc07aaa 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -9506,14 +9506,29 @@ <message name="IDS_NATIVE_FILE_SYSTEM_DIRECTORY_USAGE_TOOLTIP" desc="Tooltip for native file system omnibox usage indicator."> This page is allowed to read a folder on your device. </message> - <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_TEXT" desc="Text of the bubble showing what files and directories an origin can currently access"> + <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_TEXT" desc="Text of the bubble showing what files an origin can currently write to"> <ph name="ORIGIN">$1<ex>example.com</ex></ph> can save your changes directly to the following files. This site can save changes only while this tab is open. </message> - <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_DIRECTORIES_TEXT" desc="Text of the bubble showing what files and directories an origin can currently access"> - <ph name="ORIGIN">$1<ex>example.com</ex></ph> can save your changes directly to the files in the following folder. This site can save changes only while this tab is open. + <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_NO_LIFETIME_TEXT" desc="Text of the bubble showing what files an origin can currently write to"> + <ph name="ORIGIN">$1<ex>example.com</ex></ph> can save your changes directly to the following files. + </message> + <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_DIRECTORIES_TEXT" desc="Text of the bubble showing what directories an origin can currently write to"> + <ph name="ORIGIN">$1<ex>example.com</ex></ph> can save your changes directly to the files in the following folders. This site can save changes only while this tab is open. + </message> + <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_DIRECTORIES_NO_LIFETIME_TEXT" desc="Text of the bubble showing what directories an origin can currently write to"> + <ph name="ORIGIN">$1<ex>example.com</ex></ph> can save your changes directly to the files in the following folders. + </message> + <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_AND_DIRECTORIES_TEXT" desc="Text of the bubble showing what files and directories an origin can currently write to"> + <ph name="ORIGIN">$1<ex>example.com</ex></ph> can save your changes directly to the following files and folders. + </message> + <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_LIFETIME_TEXT" desc="Text explaining lifetimes of grants in the bubble showing what files and directories an origin can currently write to"> + This site can save and read changes only while the tab is open. </message> <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_READABLE_DIRECTORIES_TEXT" desc="Text of the bubble showing what files and directories an origin can currently access"> - <ph name="ORIGIN">$1<ex>example.com</ex></ph> can read all the files in the following folder. This site can see changes to the folder only while this tab is open. + <ph name="ORIGIN">$1<ex>example.com</ex></ph> can read all the files in the following folders. This site can see changes to the folder only while this tab is open. + </message> + <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_ALSO_READABLE_DIRECTORIES_TEXT" desc="Text of the bubble showing what files and directories an origin can currently access"> + This site can also read all the files in the following folders. </message> <message name="IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_FILES_TEXT" desc="Text to display a list of files in the native file system usage bubble"> {0, plural,
diff --git a/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_ALSO_READABLE_DIRECTORIES_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_ALSO_READABLE_DIRECTORIES_TEXT.png.sha1 new file mode 100644 index 0000000..27a22cd --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_ALSO_READABLE_DIRECTORIES_TEXT.png.sha1
@@ -0,0 +1 @@ +8281f3e983197754ef1f84d5cd74c19cfd384a1f \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_LIFETIME_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_LIFETIME_TEXT.png.sha1 new file mode 100644 index 0000000..27a22cd --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_LIFETIME_TEXT.png.sha1
@@ -0,0 +1 @@ +8281f3e983197754ef1f84d5cd74c19cfd384a1f \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_DIRECTORIES_NO_LIFETIME_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_DIRECTORIES_NO_LIFETIME_TEXT.png.sha1 new file mode 100644 index 0000000..11800eb --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_DIRECTORIES_NO_LIFETIME_TEXT.png.sha1
@@ -0,0 +1 @@ +18d719856329a6912245907a086caf534dd8b8e4 \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_AND_DIRECTORIES_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_AND_DIRECTORIES_TEXT.png.sha1 new file mode 100644 index 0000000..27a22cd --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_AND_DIRECTORIES_TEXT.png.sha1
@@ -0,0 +1 @@ +8281f3e983197754ef1f84d5cd74c19cfd384a1f \ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_NO_LIFETIME_TEXT.png.sha1 b/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_NO_LIFETIME_TEXT.png.sha1 new file mode 100644 index 0000000..736c6db --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_NO_LIFETIME_TEXT.png.sha1
@@ -0,0 +1 @@ +270b20d3901258d1767a7d8fe2ebd8c71e96aabe \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 41473502..f4236da 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -806,6 +806,10 @@ "metrics/ukm_background_recorder_service.h", "metrics/variations/chrome_variations_service_client.cc", "metrics/variations/chrome_variations_service_client.h", + "native_file_system/chrome_native_file_system_permission_context.cc", + "native_file_system/chrome_native_file_system_permission_context.h", + "native_file_system/native_file_system_permission_context_factory.cc", + "native_file_system/native_file_system_permission_context_factory.h", "native_window_notification_source.h", "navigation_predictor/navigation_predictor.cc", "navigation_predictor/navigation_predictor.h", @@ -3245,8 +3249,6 @@ "search/chrome_colors/chrome_colors_factory.h", "search/chrome_colors/chrome_colors_service.cc", "search/chrome_colors/chrome_colors_service.h", - "search/iframe_source.cc", - "search/iframe_source.h", "search/instant_service.cc", "search/instant_service.h", "search/instant_service_factory.cc", @@ -5004,13 +5006,6 @@ ] } - if (!is_chrome_branded && !is_android) { - sources += [ - "search/local_files_ntp_source.cc", - "search/local_files_ntp_source.h", - ] - } - if (use_cups) { configs += [ "//printing:cups" ] }
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 2b2f9eb2..f0f1b94f 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -4064,6 +4064,12 @@ FEATURE_VALUE_TYPE(features::kAnimatedAvatarButton)}, #endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) +#if defined(OS_CHROMEOS) + {"crostini-webui-installer", flag_descriptions::kCrostiniWebUIInstallerName, + flag_descriptions::kCrostiniWebUIInstallerDescription, kOsCrOS, + FEATURE_VALUE_TYPE(chromeos::features::kCrostiniWebUIInstaller)}, +#endif // OS_CHROMEOS + // NOTE: Adding a new flag requires adding a corresponding entry to enum // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/compositor/navigation_glow.cc b/chrome/browser/android/compositor/navigation_glow.cc index c12b2c6..6174092 100644 --- a/chrome/browser/android/compositor/navigation_glow.cc +++ b/chrome/browser/android/compositor/navigation_glow.cc
@@ -30,27 +30,10 @@ namespace android { -NavigationGlow::NavigationGlow(float dip_scale) +NavigationGlow::NavigationGlow(float dip_scale, + content::WebContents* web_contents) : dip_scale_(dip_scale), - glow_effect_(std::make_unique<ui::OverscrollGlow>(this)) {} - -NavigationGlow::~NavigationGlow() = default; - -void NavigationGlow::InitWithSceneLayer( - JNIEnv* env, - const JavaParamRef<jobject>& obj, - const JavaParamRef<jobject>& jscene_layer, - const JavaParamRef<jobject>& jwindow_android) { - layer_ = SceneLayer::FromJavaObject(env, jscene_layer)->layer().get(); - window_ = ui::WindowAndroid::FromJavaWindowAndroid(jwindow_android); - window_->AddObserver(this); -} - -void NavigationGlow::InitWithWebContents( - JNIEnv* env, - const JavaParamRef<jobject>& obj, - const JavaParamRef<jobject>& jweb_contents) { - auto* web_contents = content::WebContents::FromJavaWebContents(jweb_contents); + glow_effect_(std::make_unique<ui::OverscrollGlow>(this)) { DCHECK(web_contents); view_ = web_contents->GetNativeView(); view_->AddObserver(this); @@ -58,9 +41,9 @@ OnAttachedToWindow(); } +NavigationGlow::~NavigationGlow() = default; + void NavigationGlow::OnAttachedToWindow() { - if (!view_) - return; window_ = view_->GetWindowAndroid(); if (window_) { window_->AddObserver(this); @@ -112,8 +95,7 @@ void NavigationGlow::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { OnDetachedFromWindow(); - if (view_) - view_->RemoveObserver(this); + view_->RemoveObserver(this); delete this; } @@ -130,10 +112,15 @@ return std::make_unique<ui::EdgeEffect>(&resource_manager, dip_scale_); } -static jlong JNI_CompositorNavigationGlow_Init(JNIEnv* env, - const JavaParamRef<jobject>& obj, - const jfloat dip_scale) { - return reinterpret_cast<intptr_t>(new NavigationGlow(dip_scale)); +static jlong JNI_CompositorNavigationGlow_Init( + JNIEnv* env, + const JavaParamRef<jobject>& obj, + const jfloat dip_scale, + const JavaParamRef<jobject>& jweb_contents) { + auto* web_contents = content::WebContents::FromJavaWebContents(jweb_contents); + DCHECK(web_contents); + return reinterpret_cast<intptr_t>( + new NavigationGlow(dip_scale, web_contents)); } } // namespace android
diff --git a/chrome/browser/android/compositor/navigation_glow.h b/chrome/browser/android/compositor/navigation_glow.h index 048790e..2b72c6e 100644 --- a/chrome/browser/android/compositor/navigation_glow.h +++ b/chrome/browser/android/compositor/navigation_glow.h
@@ -11,6 +11,10 @@ #include "ui/android/view_android_observer.h" #include "ui/android/window_android_observer.h" +namespace content { +class WebContents; +} + namespace ui { class ViewAndroid; class WindowAndroid; @@ -23,18 +27,9 @@ public ui::WindowAndroidObserver, public ui::ViewAndroidObserver { public: - explicit NavigationGlow(float dip_scale); + explicit NavigationGlow(float dip_scale, content::WebContents* web_contents); ~NavigationGlow() override; - void InitWithSceneLayer( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - const base::android::JavaParamRef<jobject>& jscene_layer, - const base::android::JavaParamRef<jobject>& jwindow_android); - void InitWithWebContents( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - const base::android::JavaParamRef<jobject>& jweb_contents); void Prepare(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, jfloat start_x,
diff --git a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm index 34acde2..8bb8c31 100644 --- a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm +++ b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
@@ -310,9 +310,9 @@ #define MAYBE_ShowWindow DISABLED_ShowWindow #define MAYBE_RebuildShim DISABLED_RebuildShim #else -#define MAYBE_Launch Launch +#define MAYBE_Launch DISABLED_Launch // http://crbug.com/913490 #define MAYBE_HostedAppLaunch DISABLED_HostedAppLaunch -#define MAYBE_ShowWindow ShowWindow +#define MAYBE_ShowWindow DISABLED_ShowWindow // https://crbug.com/980072 // http://crbug.com/517744 HostedAppLaunch fails with open as tab for apps // http://crbug.com/509774 this test is flaky so is disabled even in the // static build.
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc index dd090c0f..67b7581d 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc +++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/apps/intent_helper/apps_navigation_throttle.h" +#include <algorithm> #include <utility> #include "base/bind.h" @@ -117,8 +118,7 @@ std::vector<IntentPickerAppInfo> apps = FindPwaForUrl(web_contents, url, {}); ShowIntentPickerBubbleForApps( - web_contents, std::move(apps), - /*show_remember_selection=*/false, + web_contents, std::move(apps), ShouldShowRememberSelection(apps), base::BindOnce(&OnIntentPickerClosed, web_contents, ui_auto_display_service, url)); } @@ -333,6 +333,25 @@ web_contents->ClosePage(); } +// static +bool AppsNavigationThrottle::ContainsOnlyPwas( + const std::vector<apps::IntentPickerAppInfo>& apps) { + return std::all_of(apps.begin(), apps.end(), + [](const apps::IntentPickerAppInfo& app_info) { + return app_info.type == apps::mojom::AppType::kWeb; + }); +} + +// static +bool AppsNavigationThrottle::ShouldShowRememberSelection( + std::vector<apps::IntentPickerAppInfo>& apps) { + // There is no support persistence for PWA so the selection should be hidden + // if only PWAs are present. + // TODO(crbug.com/826982): Provide the "Remember my choice" option when the + // app registry can support persistence for PWAs. + return !ContainsOnlyPwas(apps); +} + bool AppsNavigationThrottle::ShouldDeferNavigationForArc( content::NavigationHandle* handle) { return false; @@ -361,7 +380,7 @@ break; case PickerShowState::kPopOut: ShowIntentPickerBubbleForApps(web_contents, std::move(apps), - ShouldShowRememberSelection(), + ShouldShowRememberSelection(apps), std::move(callback)); break; default: @@ -385,10 +404,6 @@ ui_auto_display_service, url); } -bool AppsNavigationThrottle::ShouldShowRememberSelection() { - return false; -} - bool AppsNavigationThrottle::navigate_from_link() { return navigate_from_link_; }
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.h b/chrome/browser/apps/intent_helper/apps_navigation_throttle.h index 73c3dea..49aacf8 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.h +++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.h
@@ -166,6 +166,12 @@ static void CloseOrGoBack(content::WebContents* web_contents); + static bool ContainsOnlyPwas( + const std::vector<apps::IntentPickerAppInfo>& apps); + + static bool ShouldShowRememberSelection( + std::vector<apps::IntentPickerAppInfo>& apps); + // Overridden for Chrome OS to allow arc handling. virtual void MaybeRemoveComingFromArcFlag(content::WebContents* web_contents, const GURL& previous_url, @@ -190,8 +196,6 @@ IntentPickerAutoDisplayService* ui_auto_display_service, const GURL& url); - virtual bool ShouldShowRememberSelection(); - bool navigate_from_link(); // Keeps track of whether we already shown the UI or preferred app. Since
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc index 7a42e84..53ddb10 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -2139,11 +2139,11 @@ base::Time one_hour_ago = base::Time::Now() - base::TimeDelta::FromHours(1); base::Time yesterday = base::Time::Now() - base::TimeDelta::FromDays(1); registry->OnAcceptRegisterProtocolHandler( - ProtocolHandler::CreateProtocolHandler("test1", kOrigin1)); + ProtocolHandler::CreateProtocolHandler("news", kOrigin1)); registry->OnAcceptRegisterProtocolHandler( - ProtocolHandler("test2", kOrigin1, yesterday)); - EXPECT_TRUE(registry->IsHandledProtocol("test1")); - EXPECT_TRUE(registry->IsHandledProtocol("test2")); + ProtocolHandler("mailto", kOrigin1, yesterday)); + EXPECT_TRUE(registry->IsHandledProtocol("news")); + EXPECT_TRUE(registry->IsHandledProtocol("mailto")); EXPECT_EQ( 2U, registry->GetUserDefinedHandlers(base::Time(), base::Time::Max()).size()); @@ -2151,8 +2151,8 @@ BlockUntilBrowsingDataRemoved( one_hour_ago, base::Time::Max(), ChromeBrowsingDataRemoverDelegate::DATA_TYPE_CONTENT_SETTINGS, false); - EXPECT_FALSE(registry->IsHandledProtocol("test1")); - EXPECT_TRUE(registry->IsHandledProtocol("test2")); + EXPECT_FALSE(registry->IsHandledProtocol("news")); + EXPECT_TRUE(registry->IsHandledProtocol("mailto")); EXPECT_EQ( 1U, registry->GetUserDefinedHandlers(base::Time(), base::Time::Max()).size()); @@ -2160,8 +2160,8 @@ BlockUntilBrowsingDataRemoved( base::Time(), base::Time::Max(), ChromeBrowsingDataRemoverDelegate::DATA_TYPE_CONTENT_SETTINGS, false); - EXPECT_FALSE(registry->IsHandledProtocol("test1")); - EXPECT_FALSE(registry->IsHandledProtocol("test2")); + EXPECT_FALSE(registry->IsHandledProtocol("news")); + EXPECT_FALSE(registry->IsHandledProtocol("mailto")); EXPECT_EQ( 0U, registry->GetUserDefinedHandlers(base::Time(), base::Time::Max()).size());
diff --git a/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc b/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc index 8f3e90e..410e4a89 100644 --- a/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc +++ b/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc
@@ -226,11 +226,11 @@ base::Time now = base::Time::Now(); handler_registry()->OnAcceptRegisterProtocolHandler( - ProtocolHandler("test1", GURL("http://www.google.com"), now)); + ProtocolHandler("news", GURL("http://www.google.com"), now)); handler_registry()->OnAcceptRegisterProtocolHandler( - ProtocolHandler("test1", GURL("http://docs.google.com"), now)); + ProtocolHandler("news", GURL("http://docs.google.com"), now)); handler_registry()->OnAcceptRegisterProtocolHandler( - ProtocolHandler("test1", GURL("http://slides.google.com"), now)); + ProtocolHandler("news", GURL("http://slides.google.com"), now)); auto translate_prefs = ChromeTranslateClient::CreateTranslatePrefs(profile()->GetPrefs()); @@ -246,12 +246,12 @@ base::Time now = base::Time::Now(); handler_registry()->OnAcceptRegisterProtocolHandler( - ProtocolHandler("test1", GURL("http://www.google.com"), now)); + ProtocolHandler("news", GURL("http://www.google.com"), now)); handler_registry()->OnAcceptRegisterProtocolHandler( - ProtocolHandler("test2", GURL("http://maps.google.com"), + ProtocolHandler("mailto", GURL("http://maps.google.com"), now - base::TimeDelta::FromMinutes(90))); - EXPECT_TRUE(handler_registry()->IsHandledProtocol("test1")); - EXPECT_TRUE(handler_registry()->IsHandledProtocol("test2")); + EXPECT_TRUE(handler_registry()->IsHandledProtocol("news")); + EXPECT_TRUE(handler_registry()->IsHandledProtocol("mailto")); SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME); EXPECT_EQ(2, GetResult());
diff --git a/chrome/browser/chrome_content_browser_client_browsertest.cc b/chrome/browser/chrome_content_browser_client_browsertest.cc index f1da002c..29a649cb 100644 --- a/chrome/browser/chrome_content_browser_client_browsertest.cc +++ b/chrome/browser/chrome_content_browser_client_browsertest.cc
@@ -759,9 +759,9 @@ }; IN_PROC_BROWSER_TEST_F(ProtocolHandlerTest, CustomHandler) { - AddProtocolHandler("abc", "https://abc.xyz/?url=%s"); + AddProtocolHandler("news", "https://abc.xyz/?url=%s"); - ui_test_utils::NavigateToURL(browser(), GURL("abc:something")); + ui_test_utils::NavigateToURL(browser(), GURL("news:something")); base::string16 expected_title = base::ASCIIToUTF16("abc.xyz"); content::TitleWatcher title_watcher( @@ -771,10 +771,10 @@ // This is a regression test for crbug.com/969177. IN_PROC_BROWSER_TEST_F(ProtocolHandlerTest, HandlersIgnoredWhenDisabled) { - AddProtocolHandler("abc", "https://abc.xyz/?url=%s"); + AddProtocolHandler("bitcoin", "https://abc.xyz/?url=%s"); protocol_handler_registry()->Disable(); - ui_test_utils::NavigateToURL(browser(), GURL("abc:something")); + ui_test_utils::NavigateToURL(browser(), GURL("bitcoin:something")); base::string16 tab_title; ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(), &tab_title));
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc index 32b534a..13e3e27 100644 --- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc +++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc
@@ -4,7 +4,6 @@ #include "chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h" -#include <algorithm> #include <utility> #include "base/bind.h" @@ -136,7 +135,7 @@ FindPwaForUrl(web_contents, url, std::move(apps)); apps::AppsNavigationThrottle::ShowIntentPickerBubbleForApps( web_contents, std::move(apps_for_picker), - /*show_remember_selection=*/true, + ShouldShowRememberSelection(apps_for_picker), base::BindOnce(&OnIntentPickerClosed, web_contents, ui_auto_display_service, url)); } @@ -266,10 +265,6 @@ ui_auto_display_service, url); } -bool ChromeOsAppsNavigationThrottle::ShouldShowRememberSelection() { - return true; -} - void ChromeOsAppsNavigationThrottle::CloseTab() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); content::WebContents* web_contents = navigation_handle()->GetWebContents(); @@ -289,12 +284,7 @@ // until "Remember my choice" is available for desktop PWAs. // TODO(crbug.com/826982): show the intent picker when the app registry is // available to persist "Remember my choice" for PWAs. - bool only_pwa_apps = - std::all_of(apps_for_picker.begin(), apps_for_picker.end(), - [](const apps::IntentPickerAppInfo& app_info) { - return app_info.type == apps::mojom::AppType::kWeb; - }); - if (only_pwa_apps) + if (ContainsOnlyPwas(apps_for_picker)) return false; DCHECK(ui_auto_display_service_);
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h index f7f4dfef..00d51b4d 100644 --- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h +++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h
@@ -112,8 +112,6 @@ IntentPickerAutoDisplayService* ui_auto_display_service, const GURL& url) override; - bool ShouldShowRememberSelection() override; - void CloseTab(); // Whether or not the intent picker UI should be displayed without the user
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc index c1bc597..715e9ad 100644 --- a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc +++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
@@ -52,14 +52,12 @@ PrefService* local_state) { delegate_ = std::make_unique<DeviceOAuth2TokenServiceDelegate>( url_loader_factory, local_state, this); - delegate_->AddObserver(this); token_manager_ = std::make_unique<OAuth2AccessTokenManager>( this /* OAuth2AccessTokenManager::Delegate* */); delegate_->InitializeWithValidationStatusDelegate(this); } DeviceOAuth2TokenService::~DeviceOAuth2TokenService() { - delegate_->RemoveObserver(this); delegate_->ClearValidationStatusDelegate(); FlushPendingRequests(false, GoogleServiceAuthError::REQUEST_CANCELED); } @@ -133,39 +131,18 @@ return RefreshTokenIsAvailable(account_id); } -bool DeviceOAuth2TokenService::FixRequestErrorIfPossible() { - return delegate_->FixRequestErrorIfPossible(); -} - scoped_refptr<network::SharedURLLoaderFactory> DeviceOAuth2TokenService::GetURLLoaderFactory() const { return delegate_->GetURLLoaderFactory(); } -void DeviceOAuth2TokenService::OnAccessTokenInvalidated( - const CoreAccountId& account_id, - const std::string& client_id, - const std::set<std::string>& scopes, - const std::string& access_token) { - delegate_->OnAccessTokenInvalidated(account_id, client_id, scopes, - access_token); -} - -void DeviceOAuth2TokenService::OnAccessTokenFetched( - const CoreAccountId& account_id, - const GoogleServiceAuthError& error) { - // Update the auth error state so auth errors are appropriately communicated - // to the user. - delegate_->UpdateAuthError(account_id, error); -} - -void DeviceOAuth2TokenService::OnRefreshTokenAvailable( +void DeviceOAuth2TokenService::FireRefreshTokenAvailable( const CoreAccountId& account_id) { if (on_refresh_token_available_callback_) on_refresh_token_available_callback_.Run(account_id); } -void DeviceOAuth2TokenService::OnRefreshTokenRevoked( +void DeviceOAuth2TokenService::FireRefreshTokenRevoked( const CoreAccountId& account_id) { if (on_refresh_token_revoked_callback_) on_refresh_token_revoked_callback_.Run(account_id);
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.h b/chrome/browser/chromeos/settings/device_oauth2_token_service.h index 0732921..0c8b3fe 100644 --- a/chrome/browser/chromeos/settings/device_oauth2_token_service.h +++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
@@ -15,7 +15,6 @@ #include "google_apis/gaia/google_service_auth_error.h" #include "google_apis/gaia/oauth2_access_token_consumer.h" #include "google_apis/gaia/oauth2_access_token_manager.h" -#include "google_apis/gaia/oauth2_token_service_observer.h" namespace network { class SharedURLLoaderFactory; @@ -34,8 +33,7 @@ // // Note that requests must be made from the UI thread. class DeviceOAuth2TokenService - : public OAuth2TokenServiceObserver, - public OAuth2AccessTokenManager::Delegate, + : public OAuth2AccessTokenManager::Delegate, public DeviceOAuth2TokenServiceDelegate::ValidationStatusDelegate { public: typedef base::RepeatingCallback<void(const CoreAccountId& /* account_id */)> @@ -95,6 +93,9 @@ OAuth2AccessTokenManager* GetAccessTokenManager(); private: + // TODO(https://crbug.com/967598): Merge DeviceOAuth2TokenServiceDelegate + // into DeviceOAuth2TokenService. + friend class DeviceOAuth2TokenServiceDelegate; friend class DeviceOAuth2TokenServiceFactory; friend class DeviceOAuth2TokenServiceTest; struct PendingRequest; @@ -105,7 +106,6 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, OAuth2AccessTokenConsumer* consumer) override; bool HasRefreshToken(const CoreAccountId& account_id) const override; - bool FixRequestErrorIfPossible() override; scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() const override; bool HandleAccessTokenFetch( @@ -115,16 +115,9 @@ const std::string& client_id, const std::string& client_secret, const OAuth2AccessTokenManager::ScopeSet& scopes) override; - void OnAccessTokenInvalidated(const CoreAccountId& account_id, - const std::string& client_id, - const std::set<std::string>& scopes, - const std::string& access_token) override; - void OnAccessTokenFetched(const CoreAccountId& account_id, - const GoogleServiceAuthError& error) override; - // OAuth2TokenServiceObserver: - void OnRefreshTokenAvailable(const CoreAccountId& account_id) override; - void OnRefreshTokenRevoked(const CoreAccountId& account_id) override; + void FireRefreshTokenAvailable(const CoreAccountId& account_id); + void FireRefreshTokenRevoked(const CoreAccountId& account_id); // Implementation of // DeviceOAuth2TokenServiceDelegate::ValidationStatusDelegate.
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.cc index 6be3110..3d4329d 100644 --- a/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.cc +++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.cc
@@ -11,6 +11,7 @@ #include "base/bind_helpers.h" #include "base/memory/weak_ptr.h" #include "base/values.h" +#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h" #include "chrome/browser/chromeos/settings/token_encryptor.h" #include "chrome/common/pref_names.h" #include "chromeos/cryptohome/system_salt_getter.h" @@ -20,7 +21,6 @@ #include "components/prefs/pref_service.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/gaia_urls.h" -#include "google_apis/gaia/google_service_auth_error.h" #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -28,7 +28,7 @@ void DeviceOAuth2TokenServiceDelegate::OnServiceAccountIdentityChanged() { if (!GetRobotAccountId().empty() && !refresh_token_.empty()) - FireRefreshTokenAvailable(GetRobotAccountId()); + service_->FireRefreshTokenAvailable(GetRobotAccountId()); } DeviceOAuth2TokenServiceDelegate::DeviceOAuth2TokenServiceDelegate( @@ -47,6 +47,7 @@ base::Bind(&DeviceOAuth2TokenServiceDelegate:: OnServiceAccountIdentityChanged, base::Unretained(this)))), + service_(service), weak_ptr_factory_(this) { // Pull in the system salt. SystemSaltGetter::Get()->GetSystemSalt( @@ -71,7 +72,7 @@ // will be done from OnServiceAccountIdentityChanged() once the robot account // ID becomes available as well. if (!GetRobotAccountId().empty()) - FireRefreshTokenAvailable(GetRobotAccountId()); + service_->FireRefreshTokenAvailable(GetRobotAccountId()); token_save_callbacks_.push_back(result_callback); if (!waiting_for_salt) { @@ -227,7 +228,7 @@ // Announce the token. if (!GetRobotAccountId().empty()) { - FireRefreshTokenAvailable(GetRobotAccountId()); + service_->FireRefreshTokenAvailable(GetRobotAccountId()); } } @@ -324,13 +325,6 @@ void DeviceOAuth2TokenServiceDelegate::InitializeWithValidationStatusDelegate( ValidationStatusDelegate* delegate) { validation_status_delegate_ = delegate; - - // Now that |delegate| (i.e., DeviceOAuth2TokenService) has been initialized - // and is listening to this object as an observer, fire the notification that - // refresh tokens were loaded; otherwise, - // OAuth2TokenService::{GetAccounts(), RefreshTokenIsAvailable()} will short- - // circuit out to match O2TS semantics. - FireRefreshTokensLoaded(); } void DeviceOAuth2TokenServiceDelegate::ClearValidationStatusDelegate() {
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.h b/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.h index 6251482..58db8af 100644 --- a/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.h +++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.h
@@ -14,8 +14,9 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/chromeos/settings/cros_settings.h" +#include "google_apis/gaia/core_account_id.h" #include "google_apis/gaia/gaia_oauth_client.h" -#include "google_apis/gaia/oauth2_token_service_delegate.h" +#include "google_apis/gaia/google_service_auth_error.h" #include "net/url_request/url_request_context_getter.h" namespace gaia { @@ -27,14 +28,15 @@ } class PrefService; +class OAuth2AccessTokenFetcher; +class OAuth2AccessTokenConsumer; namespace chromeos { class DeviceOAuth2TokenService; class DeviceOAuth2TokenServiceDelegate - : public OAuth2TokenServiceDelegate, - public gaia::GaiaOAuthClient::Delegate { + : public gaia::GaiaOAuthClient::Delegate { public: DeviceOAuth2TokenServiceDelegate( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, @@ -57,17 +59,13 @@ robot_account_id_for_testing_ = account_id; } - // Implementation of OAuth2TokenServiceDelegate. - bool RefreshTokenIsAvailable(const CoreAccountId& account_id) const override; - scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() - const override; - + bool RefreshTokenIsAvailable(const CoreAccountId& account_id) const; + scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() const; std::unique_ptr<OAuth2AccessTokenFetcher> CreateAccessTokenFetcher( const CoreAccountId& account_id, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - OAuth2AccessTokenConsumer* consumer) override; - - std::vector<CoreAccountId> GetAccounts() const override; + OAuth2AccessTokenConsumer* consumer); + std::vector<CoreAccountId> GetAccounts() const; // gaia::GaiaOAuthClient::Delegate implementation. void OnRefreshTokenResponse(const std::string& access_token, @@ -164,6 +162,10 @@ CoreAccountId robot_account_id_for_testing_; + // TODO(https://crbug.com/967598): Completely merge this class into + // DeviceOAuth2TokenService. + DeviceOAuth2TokenService* service_; + base::WeakPtrFactory<DeviceOAuth2TokenServiceDelegate> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(DeviceOAuth2TokenServiceDelegate);
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc index 4654e73..c8c627f 100644 --- a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc +++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
@@ -43,22 +43,6 @@ namespace chromeos { -namespace { - -class MockOAuth2TokenServiceObserver : public OAuth2TokenServiceObserver { - public: - MockOAuth2TokenServiceObserver(); - ~MockOAuth2TokenServiceObserver() override; - - MOCK_METHOD1(OnRefreshTokenAvailable, void(const CoreAccountId&)); -}; - -MockOAuth2TokenServiceObserver::MockOAuth2TokenServiceObserver() {} - -MockOAuth2TokenServiceObserver::~MockOAuth2TokenServiceObserver() {} - -} // namespace - class DeviceOAuth2TokenServiceTest : public testing::Test { public: DeviceOAuth2TokenServiceTest() @@ -462,23 +446,28 @@ TEST_F(DeviceOAuth2TokenServiceTest, DoNotAnnounceTokenWithoutAccountID) { CreateService(); - testing::StrictMock<MockOAuth2TokenServiceObserver> observer; - GetDelegate()->AddObserver(&observer); + auto callback_without_id = base::BindRepeating( + [](const CoreAccountId& account_id) { EXPECT_TRUE(false); }); + oauth2_service_->SetRefreshTokenAvailableCallback( + std::move(callback_without_id)); // Make a token available during enrollment. Verify that the token is not // announced yet. oauth2_service_->SetAndSaveRefreshToken( "test-token", DeviceOAuth2TokenService::StatusCallback()); - testing::Mock::VerifyAndClearExpectations(&observer); + + base::RunLoop run_loop; + auto callback_with_id = + base::BindRepeating([](base::RunLoop* loop, + const CoreAccountId& account_id) { loop->Quit(); }, + &run_loop); + oauth2_service_->SetRefreshTokenAvailableCallback( + std::move(callback_with_id)); // Also make the robot account ID available. Verify that the token is // announced now. - EXPECT_CALL(observer, - OnRefreshTokenAvailable(CoreAccountId("robot@example.com"))); SetRobotAccountId("robot@example.com"); - testing::Mock::VerifyAndClearExpectations(&observer); - - GetDelegate()->RemoveObserver(&observer); + run_loop.Run(); } } // namespace chromeos
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc index fda23ba..b1c4255 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry.cc
@@ -208,7 +208,8 @@ void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler( const ProtocolHandler& handler) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - RegisterProtocolHandler(handler, USER); + if (!RegisterProtocolHandler(handler, USER)) + return; SetDefault(handler); Save(); NotifyChanged(); @@ -729,23 +730,29 @@ observer.OnProtocolHandlerRegistryChanged(); } -void ProtocolHandlerRegistry::RegisterProtocolHandler( +bool ProtocolHandlerRegistry::RegisterProtocolHandler( const ProtocolHandler& handler, const HandlerSource source) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(CanSchemeBeOverridden(handler.protocol())); DCHECK(!handler.IsEmpty()); + + // Ignore invalid handlers. + if (!handler.IsValid()) + return false; + ProtocolHandlerMultiMap& map = (source == POLICY) ? policy_protocol_handlers_ : user_protocol_handlers_; ProtocolHandlerList& list = map[handler.protocol()]; if (!HandlerExists(handler, list)) list.push_back(handler); if (IsRegistered(handler)) { - return; + return true; } if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol())) delegate_->RegisterExternalHandler(handler.protocol()); InsertHandler(handler); + return true; } std::vector<const base::DictionaryValue*> @@ -781,7 +788,8 @@ p != registered_handlers.end(); ++p) { ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p); - RegisterProtocolHandler(handler, source); + if (!RegisterProtocolHandler(handler, source)) + continue; bool is_default = false; if ((*p)->GetBoolean("default", &is_default) && is_default) { SetDefault(handler);
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.h b/chrome/browser/custom_handlers/protocol_handler_registry.h index 20b6009..b10a595 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry.h +++ b/chrome/browser/custom_handlers/protocol_handler_registry.h
@@ -302,7 +302,7 @@ void NotifyChanged(); // Registers a new protocol handler. - void RegisterProtocolHandler(const ProtocolHandler& handler, + bool RegisterProtocolHandler(const ProtocolHandler& handler, const HandlerSource source); // Registers protocol handlers from the preference.
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc index 3725feac..56cf28b3d 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc
@@ -48,8 +48,7 @@ return menu; } - void AddProtocolHandler(const std::string& protocol, - const GURL& url) { + void AddProtocolHandler(const std::string& protocol, const GURL& url) { ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(protocol, url); ProtocolHandlerRegistry* registry = @@ -116,17 +115,17 @@ IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerBrowserTest, CustomHandler) { ASSERT_TRUE(embedded_test_server()->Start()); - GURL handler_url = embedded_test_server()->GetURL("/custom_handler_foo.html"); - AddProtocolHandler("foo", handler_url); + GURL handler_url = embedded_test_server()->GetURL("/custom_handler.html"); + AddProtocolHandler("news", handler_url); - ui_test_utils::NavigateToURL(browser(), GURL("foo:test")); + ui_test_utils::NavigateToURL(browser(), GURL("news:test")); ASSERT_EQ(handler_url, browser()->tab_strip_model()->GetActiveWebContents()->GetURL()); // Also check redirects. GURL redirect_url = - embedded_test_server()->GetURL("/server-redirect?foo:test"); + embedded_test_server()->GetURL("/server-redirect?news:test"); ui_test_utils::NavigateToURL(browser(), redirect_url); ASSERT_EQ(handler_url,
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc index f6fe7772..8b0bc89 100644 --- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc +++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
@@ -197,7 +197,7 @@ class ProtocolHandlerRegistryTest : public testing::Test { protected: ProtocolHandlerRegistryTest() - : test_protocol_handler_(CreateProtocolHandler("test", "test")) {} + : test_protocol_handler_(CreateProtocolHandler("news", "news")) {} FakeDelegate* delegate() const { return delegate_; } ProtocolHandlerRegistry* registry() { return registry_.get(); } @@ -268,7 +268,7 @@ CHECK(profile_->GetPrefs()); SetUpRegistry(true); test_protocol_handler_ = - CreateProtocolHandler("test", GURL("http://test.com/%s")); + CreateProtocolHandler("news", GURL("http://test.com/%s")); } void TearDown() override { TeadDownRegistry(); } @@ -283,34 +283,34 @@ }; TEST_F(ProtocolHandlerRegistryTest, AcceptProtocolHandlerHandlesProtocol) { - ASSERT_FALSE(registry()->IsHandledProtocol("test")); + ASSERT_FALSE(registry()->IsHandledProtocol("news")); registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler()); - ASSERT_TRUE(registry()->IsHandledProtocol("test")); + ASSERT_TRUE(registry()->IsHandledProtocol("news")); } TEST_F(ProtocolHandlerRegistryTest, DeniedProtocolIsntHandledUntilAccepted) { registry()->OnDenyRegisterProtocolHandler(test_protocol_handler()); - ASSERT_FALSE(registry()->IsHandledProtocol("test")); + ASSERT_FALSE(registry()->IsHandledProtocol("news")); registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler()); - ASSERT_TRUE(registry()->IsHandledProtocol("test")); + ASSERT_TRUE(registry()->IsHandledProtocol("news")); } TEST_F(ProtocolHandlerRegistryTest, ClearDefaultMakesProtocolNotHandled) { registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler()); - registry()->ClearDefault("test"); - ASSERT_FALSE(registry()->IsHandledProtocol("test")); - ASSERT_TRUE(registry()->GetHandlerFor("test").IsEmpty()); + registry()->ClearDefault("news"); + ASSERT_FALSE(registry()->IsHandledProtocol("news")); + ASSERT_TRUE(registry()->GetHandlerFor("news").IsEmpty()); } TEST_F(ProtocolHandlerRegistryTest, DisableDeregistersProtocolHandlers) { - ASSERT_FALSE(delegate()->IsExternalHandlerRegistered("test")); + ASSERT_FALSE(delegate()->IsExternalHandlerRegistered("news")); registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler()); - ASSERT_TRUE(delegate()->IsExternalHandlerRegistered("test")); + ASSERT_TRUE(delegate()->IsExternalHandlerRegistered("news")); registry()->Disable(); - ASSERT_FALSE(delegate()->IsExternalHandlerRegistered("test")); + ASSERT_FALSE(delegate()->IsExternalHandlerRegistered("news")); registry()->Enable(); - ASSERT_TRUE(delegate()->IsExternalHandlerRegistered("test")); + ASSERT_TRUE(delegate()->IsExternalHandlerRegistered("news")); } TEST_F(ProtocolHandlerRegistryTest, IgnoreProtocolHandler) { @@ -322,8 +322,8 @@ } TEST_F(ProtocolHandlerRegistryTest, IgnoreEquivalentProtocolHandler) { - ProtocolHandler ph1 = CreateProtocolHandler("test", GURL("http://test/%s")); - ProtocolHandler ph2 = CreateProtocolHandler("test", GURL("http://test/%s")); + ProtocolHandler ph1 = CreateProtocolHandler("news", GURL("http://test/%s")); + ProtocolHandler ph2 = CreateProtocolHandler("news", GURL("http://test/%s")); registry()->OnIgnoreRegisterProtocolHandler(ph1); ASSERT_TRUE(registry()->IsIgnored(ph1)); @@ -340,21 +340,21 @@ registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler()); registry()->OnIgnoreRegisterProtocolHandler(stuff_protocol_handler); - ASSERT_TRUE(registry()->IsHandledProtocol("test")); + ASSERT_TRUE(registry()->IsHandledProtocol("news")); ASSERT_TRUE(registry()->IsIgnored(stuff_protocol_handler)); delegate()->Reset(); RecreateRegistry(true); - ASSERT_TRUE(registry()->IsHandledProtocol("test")); + ASSERT_TRUE(registry()->IsHandledProtocol("news")); ASSERT_TRUE(registry()->IsIgnored(stuff_protocol_handler)); } TEST_F(ProtocolHandlerRegistryTest, Encode) { base::Time now = base::Time::Now(); - ProtocolHandler handler("test", GURL("http://example.com"), now); + ProtocolHandler handler("news", GURL("http://example.com"), now); auto value = handler.Encode(); ProtocolHandler recreated = ProtocolHandler::CreateProtocolHandler(value.get()); - EXPECT_EQ("test", recreated.protocol()); + EXPECT_EQ("news", recreated.protocol()); EXPECT_EQ(GURL("http://example.com"), recreated.url()); EXPECT_EQ(now, recreated.last_modified()); } @@ -363,9 +363,10 @@ base::Time now = base::Time::Now(); base::Time one_hour_ago = now - base::TimeDelta::FromHours(1); base::Time two_hours_ago = now - base::TimeDelta::FromHours(2); - ProtocolHandler handler1("test1", GURL("http://example.com"), two_hours_ago); - ProtocolHandler handler2("test2", GURL("http://example.com"), one_hour_ago); - ProtocolHandler handler3("test3", GURL("http://example.com"), now); + ProtocolHandler handler1("bitcoin", GURL("http://example.com"), + two_hours_ago); + ProtocolHandler handler2("geo", GURL("http://example.com"), one_hour_ago); + ProtocolHandler handler3("im", GURL("http://example.com"), now); registry()->OnAcceptRegisterProtocolHandler(handler1); registry()->OnAcceptRegisterProtocolHandler(handler2); registry()->OnAcceptRegisterProtocolHandler(handler3); @@ -385,12 +386,12 @@ base::Time one_hour_ago = now - base::TimeDelta::FromHours(1); base::Time two_hours_ago = now - base::TimeDelta::FromHours(2); GURL url("http://example.com"); - ProtocolHandler handler1("test1", url, two_hours_ago); - ProtocolHandler handler2("test2", url, one_hour_ago); - ProtocolHandler handler3("test3", url, now); - ProtocolHandler ignored1("ignored1", url, two_hours_ago); - ProtocolHandler ignored2("ignored2", url, one_hour_ago); - ProtocolHandler ignored3("ignored3", url, now); + ProtocolHandler handler1("bitcoin", url, two_hours_ago); + ProtocolHandler handler2("geo", url, one_hour_ago); + ProtocolHandler handler3("im", url, now); + ProtocolHandler ignored1("irc", url, two_hours_ago); + ProtocolHandler ignored2("ircs", url, one_hour_ago); + ProtocolHandler ignored3("magnet", url, now); registry()->OnAcceptRegisterProtocolHandler(handler1); registry()->OnAcceptRegisterProtocolHandler(handler2); registry()->OnAcceptRegisterProtocolHandler(handler3); @@ -398,27 +399,27 @@ registry()->OnIgnoreRegisterProtocolHandler(ignored2); registry()->OnIgnoreRegisterProtocolHandler(ignored3); - EXPECT_TRUE(registry()->IsHandledProtocol("test1")); - EXPECT_TRUE(registry()->IsHandledProtocol("test2")); - EXPECT_TRUE(registry()->IsHandledProtocol("test3")); + EXPECT_TRUE(registry()->IsHandledProtocol("bitcoin")); + EXPECT_TRUE(registry()->IsHandledProtocol("geo")); + EXPECT_TRUE(registry()->IsHandledProtocol("im")); EXPECT_TRUE(registry()->IsIgnored(ignored1)); EXPECT_TRUE(registry()->IsIgnored(ignored2)); EXPECT_TRUE(registry()->IsIgnored(ignored3)); // Delete handler2 and ignored2. registry()->ClearUserDefinedHandlers(one_hour_ago, now); - EXPECT_TRUE(registry()->IsHandledProtocol("test1")); - EXPECT_FALSE(registry()->IsHandledProtocol("test2")); - EXPECT_TRUE(registry()->IsHandledProtocol("test3")); + EXPECT_TRUE(registry()->IsHandledProtocol("bitcoin")); + EXPECT_FALSE(registry()->IsHandledProtocol("geo")); + EXPECT_TRUE(registry()->IsHandledProtocol("im")); EXPECT_TRUE(registry()->IsIgnored(ignored1)); EXPECT_FALSE(registry()->IsIgnored(ignored2)); EXPECT_TRUE(registry()->IsIgnored(ignored3)); // Delete all. registry()->ClearUserDefinedHandlers(base::Time(), base::Time::Max()); - EXPECT_FALSE(registry()->IsHandledProtocol("test1")); - EXPECT_FALSE(registry()->IsHandledProtocol("test2")); - EXPECT_FALSE(registry()->IsHandledProtocol("test3")); + EXPECT_FALSE(registry()->IsHandledProtocol("bitcoin")); + EXPECT_FALSE(registry()->IsHandledProtocol("geo")); + EXPECT_FALSE(registry()->IsHandledProtocol("im")); EXPECT_FALSE(registry()->IsIgnored(ignored1)); EXPECT_FALSE(registry()->IsIgnored(ignored2)); EXPECT_FALSE(registry()->IsIgnored(ignored3)); @@ -433,15 +434,15 @@ TEST_F(ProtocolHandlerRegistryTest, DisallowRegisteringExternallyHandledProtocols) { - delegate()->RegisterExternalHandler("test"); - ASSERT_FALSE(registry()->CanSchemeBeOverridden("test")); + delegate()->RegisterExternalHandler("news"); + ASSERT_FALSE(registry()->CanSchemeBeOverridden("news")); } TEST_F(ProtocolHandlerRegistryTest, RemovingHandlerMeansItCanBeAddedAgain) { registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler()); - ASSERT_TRUE(registry()->CanSchemeBeOverridden("test")); + ASSERT_TRUE(registry()->CanSchemeBeOverridden("news")); registry()->RemoveHandler(test_protocol_handler()); - ASSERT_TRUE(registry()->CanSchemeBeOverridden("test")); + ASSERT_TRUE(registry()->CanSchemeBeOverridden("news")); } TEST_F(ProtocolHandlerRegistryTest, TestStartsAsDefault) { @@ -450,31 +451,31 @@ } TEST_F(ProtocolHandlerRegistryTest, TestClearDefault) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); - ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); + ProtocolHandler ph2 = CreateProtocolHandler("news", "test2"); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph2); registry()->OnAcceptRegisterProtocolHandler(ph1); - registry()->ClearDefault("test"); + registry()->ClearDefault("news"); ASSERT_FALSE(registry()->IsDefault(ph1)); ASSERT_FALSE(registry()->IsDefault(ph2)); } TEST_F(ProtocolHandlerRegistryTest, TestGetHandlerFor) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); - ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); + ProtocolHandler ph2 = CreateProtocolHandler("news", "test2"); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph2); registry()->OnAcceptRegisterProtocolHandler(ph2); - ASSERT_EQ(ph2, registry()->GetHandlerFor("test")); - ASSERT_TRUE(registry()->IsHandledProtocol("test")); + ASSERT_EQ(ph2, registry()->GetHandlerFor("news")); + ASSERT_TRUE(registry()->IsHandledProtocol("news")); } TEST_F(ProtocolHandlerRegistryTest, TestMostRecentHandlerIsDefault) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); - ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); + ProtocolHandler ph2 = CreateProtocolHandler("news", "test2"); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph2); ASSERT_FALSE(registry()->IsDefault(ph1)); @@ -482,8 +483,8 @@ } TEST_F(ProtocolHandlerRegistryTest, TestOnAcceptRegisterProtocolHandler) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); - ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); + ProtocolHandler ph2 = CreateProtocolHandler("news", "test2"); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph2); @@ -497,8 +498,8 @@ } TEST_F(ProtocolHandlerRegistryTest, TestDefaultSaveLoad) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); - ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); + ProtocolHandler ph2 = CreateProtocolHandler("news", "test2"); registry()->OnDenyRegisterProtocolHandler(ph1); registry()->OnDenyRegisterProtocolHandler(ph2); @@ -517,13 +518,13 @@ } TEST_F(ProtocolHandlerRegistryTest, TestRemoveHandler) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->RemoveHandler(ph1); ASSERT_FALSE(registry()->IsRegistered(ph1)); - ASSERT_FALSE(registry()->IsHandledProtocol("test")); + ASSERT_FALSE(registry()->IsHandledProtocol("news")); registry()->OnIgnoreRegisterProtocolHandler(ph1); ASSERT_FALSE(registry()->IsRegistered(ph1)); @@ -535,8 +536,8 @@ } TEST_F(ProtocolHandlerRegistryTest, TestIsRegistered) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); - ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); + ProtocolHandler ph2 = CreateProtocolHandler("news", "test2"); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph2); @@ -544,8 +545,8 @@ } TEST_F(ProtocolHandlerRegistryTest, TestIsEquivalentRegistered) { - ProtocolHandler ph1 = CreateProtocolHandler("test", GURL("http://test/%s")); - ProtocolHandler ph2 = CreateProtocolHandler("test", GURL("http://test/%s")); + ProtocolHandler ph1 = CreateProtocolHandler("news", GURL("http://test/%s")); + ProtocolHandler ph2 = CreateProtocolHandler("news", GURL("http://test/%s")); registry()->OnAcceptRegisterProtocolHandler(ph1); ASSERT_TRUE(registry()->IsRegistered(ph1)); @@ -553,8 +554,8 @@ } TEST_F(ProtocolHandlerRegistryTest, TestSilentlyRegisterHandler) { - ProtocolHandler ph1 = CreateProtocolHandler("test", GURL("http://test/1/%s")); - ProtocolHandler ph2 = CreateProtocolHandler("test", GURL("http://test/2/%s")); + ProtocolHandler ph1 = CreateProtocolHandler("news", GURL("http://test/1/%s")); + ProtocolHandler ph2 = CreateProtocolHandler("news", GURL("http://test/2/%s")); ProtocolHandler ph3 = CreateProtocolHandler("ignore", GURL("http://test/%s")); ProtocolHandler ph4 = CreateProtocolHandler("ignore", GURL("http://test/%s")); @@ -581,9 +582,9 @@ } TEST_F(ProtocolHandlerRegistryTest, TestRemoveHandlerRemovesDefault) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); - ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); - ProtocolHandler ph3 = CreateProtocolHandler("test", "test3"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); + ProtocolHandler ph2 = CreateProtocolHandler("news", "test2"); + ProtocolHandler ph3 = CreateProtocolHandler("news", "test3"); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph2); @@ -595,15 +596,15 @@ } TEST_F(ProtocolHandlerRegistryTest, TestGetHandlersFor) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); - ProtocolHandler ph2 = CreateProtocolHandler("test", "test2"); - ProtocolHandler ph3 = CreateProtocolHandler("test", "test3"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); + ProtocolHandler ph2 = CreateProtocolHandler("news", "test2"); + ProtocolHandler ph3 = CreateProtocolHandler("news", "test3"); registry()->OnAcceptRegisterProtocolHandler(ph1); registry()->OnAcceptRegisterProtocolHandler(ph2); registry()->OnAcceptRegisterProtocolHandler(ph3); ProtocolHandlerRegistry::ProtocolHandlerList handlers = - registry()->GetHandlersFor("test"); + registry()->GetHandlersFor("news"); ASSERT_EQ(static_cast<size_t>(3), handlers.size()); ASSERT_EQ(ph3, handlers[0]); @@ -616,7 +617,7 @@ registry()->GetRegisteredProtocols(&protocols); ASSERT_EQ(static_cast<size_t>(0), protocols.size()); - registry()->GetHandlersFor("test"); + registry()->GetHandlersFor("news"); protocols.clear(); registry()->GetRegisteredProtocols(&protocols); @@ -624,12 +625,12 @@ } TEST_F(ProtocolHandlerRegistryTest, TestIsHandledProtocol) { - registry()->GetHandlersFor("test"); - ASSERT_FALSE(registry()->IsHandledProtocol("test")); + registry()->GetHandlersFor("news"); + ASSERT_FALSE(registry()->IsHandledProtocol("news")); } TEST_F(ProtocolHandlerRegistryTest, TestObserver) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); ProtocolHandlerChangeListener counter(registry()); registry()->OnAcceptRegisterProtocolHandler(ph1); @@ -651,43 +652,43 @@ TEST_F(ProtocolHandlerRegistryTest, TestReentrantObserver) { QueryProtocolHandlerOnChange queryer(registry()); - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); registry()->OnAcceptRegisterProtocolHandler(ph1); ASSERT_TRUE(queryer.called()); } TEST_F(ProtocolHandlerRegistryTest, TestProtocolsWithNoDefaultAreHandled) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); registry()->OnAcceptRegisterProtocolHandler(ph1); - registry()->ClearDefault("test"); + registry()->ClearDefault("news"); std::vector<std::string> handled_protocols; registry()->GetRegisteredProtocols(&handled_protocols); ASSERT_EQ(static_cast<size_t>(1), handled_protocols.size()); - ASSERT_EQ("test", handled_protocols[0]); + ASSERT_EQ("news", handled_protocols[0]); } TEST_F(ProtocolHandlerRegistryTest, TestDisablePreventsHandling) { - ProtocolHandler ph1 = CreateProtocolHandler("test", "test1"); + ProtocolHandler ph1 = CreateProtocolHandler("news", "test1"); registry()->OnAcceptRegisterProtocolHandler(ph1); - ASSERT_TRUE(registry()->IsHandledProtocol("test")); + ASSERT_TRUE(registry()->IsHandledProtocol("news")); registry()->Disable(); - ASSERT_FALSE(registry()->IsHandledProtocol("test")); + ASSERT_FALSE(registry()->IsHandledProtocol("news")); } TEST_F(ProtocolHandlerRegistryTest, TestOSRegistration) { - ProtocolHandler ph_do1 = CreateProtocolHandler("do", "test1"); - ProtocolHandler ph_do2 = CreateProtocolHandler("do", "test2"); - ProtocolHandler ph_dont = CreateProtocolHandler("dont", "test"); + ProtocolHandler ph_do1 = CreateProtocolHandler("news", "test1"); + ProtocolHandler ph_do2 = CreateProtocolHandler("news", "test2"); + ProtocolHandler ph_dont = CreateProtocolHandler("im", "test3"); - ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("do")); - ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("dont")); + ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("news")); + ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("im")); registry()->OnAcceptRegisterProtocolHandler(ph_do1); registry()->OnDenyRegisterProtocolHandler(ph_dont); base::RunLoop().RunUntilIdle(); - ASSERT_TRUE(delegate()->IsFakeRegisteredWithOS("do")); - ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("dont")); + ASSERT_TRUE(delegate()->IsFakeRegisteredWithOS("news")); + ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("im")); // This should not register with the OS, if it does the delegate // will assert for us. We don't need to wait for the message loop @@ -704,11 +705,11 @@ #endif TEST_F(ProtocolHandlerRegistryTest, MAYBE_TestOSRegistrationFailure) { - ProtocolHandler ph_do = CreateProtocolHandler("do", "test1"); - ProtocolHandler ph_dont = CreateProtocolHandler("dont", "test"); + ProtocolHandler ph_do = CreateProtocolHandler("news", "test1"); + ProtocolHandler ph_dont = CreateProtocolHandler("im", "test2"); - ASSERT_FALSE(registry()->IsHandledProtocol("do")); - ASSERT_FALSE(registry()->IsHandledProtocol("dont")); + ASSERT_FALSE(registry()->IsHandledProtocol("news")); + ASSERT_FALSE(registry()->IsHandledProtocol("im")); registry()->OnAcceptRegisterProtocolHandler(ph_do); base::RunLoop().RunUntilIdle(); @@ -717,10 +718,10 @@ registry()->OnAcceptRegisterProtocolHandler(ph_dont); base::RunLoop().RunUntilIdle(); - ASSERT_TRUE(registry()->IsHandledProtocol("do")); - ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("do").size()); - ASSERT_FALSE(registry()->IsHandledProtocol("dont")); - ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("dont").size()); + ASSERT_TRUE(registry()->IsHandledProtocol("news")); + ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("news").size()); + ASSERT_FALSE(registry()->IsHandledProtocol("im")); + ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("im").size()); } TEST_F(ProtocolHandlerRegistryTest, TestRemovingDefaultFallsBackToOldDefault) { @@ -822,17 +823,17 @@ TEST_F(ProtocolHandlerRegistryTest, TestInstallDefaultHandler) { RecreateRegistry(false); registry()->AddPredefinedHandler( - CreateProtocolHandler("test", GURL("http://test.com/%s"))); + CreateProtocolHandler("news", GURL("http://test.com/%s"))); registry()->InitProtocolSettings(); std::vector<std::string> protocols; registry()->GetRegisteredProtocols(&protocols); ASSERT_EQ(static_cast<size_t>(1), protocols.size()); - EXPECT_TRUE(registry()->IsHandledProtocol("test")); + EXPECT_TRUE(registry()->IsHandledProtocol("news")); auto handlers = registry()->GetUserDefinedHandlers(base::Time(), base::Time::Max()); EXPECT_TRUE(handlers.empty()); registry()->ClearUserDefinedHandlers(base::Time(), base::Time::Max()); - EXPECT_TRUE(registry()->IsHandledProtocol("test")); + EXPECT_TRUE(registry()->IsHandledProtocol("news")); } #define URL_p1u1 "http://p1u1.com/%s" @@ -847,16 +848,16 @@ base::ListValue handlers_registered_by_policy; handlers_registered_by_pref.Append( - GetProtocolHandlerValueWithDefault("p1", URL_p1u2, true)); + GetProtocolHandlerValueWithDefault("news", URL_p1u2, true)); handlers_registered_by_pref.Append( - GetProtocolHandlerValueWithDefault("p1", URL_p1u1, true)); + GetProtocolHandlerValueWithDefault("news", URL_p1u1, true)); handlers_registered_by_pref.Append( - GetProtocolHandlerValueWithDefault("p1", URL_p1u2, false)); + GetProtocolHandlerValueWithDefault("news", URL_p1u2, false)); handlers_registered_by_policy.Append( - GetProtocolHandlerValueWithDefault("p1", URL_p1u1, false)); + GetProtocolHandlerValueWithDefault("news", URL_p1u1, false)); handlers_registered_by_policy.Append( - GetProtocolHandlerValueWithDefault("p3", URL_p3u1, true)); + GetProtocolHandlerValueWithDefault("mailto", URL_p3u1, true)); profile()->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers, handlers_registered_by_pref); @@ -865,14 +866,14 @@ registry()->InitProtocolSettings(); // Duplicate p1u2 eliminated in memory but not yet saved in pref - ProtocolHandler p1u1 = CreateProtocolHandler("p1", GURL(URL_p1u1)); - ProtocolHandler p1u2 = CreateProtocolHandler("p1", GURL(URL_p1u2)); + ProtocolHandler p1u1 = CreateProtocolHandler("news", GURL(URL_p1u1)); + ProtocolHandler p1u2 = CreateProtocolHandler("news", GURL(URL_p1u2)); ASSERT_EQ(InPrefHandlerCount(), 3); ASSERT_EQ(InMemoryHandlerCount(), 3); ASSERT_TRUE(registry()->IsDefault(p1u1)); ASSERT_FALSE(registry()->IsDefault(p1u2)); - ProtocolHandler p2u1 = CreateProtocolHandler("p2", GURL(URL_p2u1)); + ProtocolHandler p2u1 = CreateProtocolHandler("im", GURL(URL_p2u1)); registry()->OnDenyRegisterProtocolHandler(p2u1); // Duplicate p1u2 saved in pref and a new handler added to pref and memory @@ -887,7 +888,7 @@ ASSERT_EQ(InMemoryHandlerCount(), 4); ASSERT_TRUE(registry()->IsDefault(p1u1)); - ProtocolHandler p3u1 = CreateProtocolHandler("p3", GURL(URL_p3u1)); + ProtocolHandler p3u1 = CreateProtocolHandler("mailto", GURL(URL_p3u1)); registry()->RemoveHandler(p3u1); // p3u1 not removed from memory due to policy and it was never in pref. @@ -902,7 +903,7 @@ ASSERT_EQ(InMemoryHandlerCount(), 3); ASSERT_TRUE(registry()->IsDefault(p1u1)); - ProtocolHandler p1u3 = CreateProtocolHandler("p1", GURL(URL_p1u3)); + ProtocolHandler p1u3 = CreateProtocolHandler("news", GURL(URL_p1u3)); registry()->OnAcceptRegisterProtocolHandler(p1u3); // p1u3 added to pref and memory. @@ -926,14 +927,14 @@ base::ListValue handlers_ignored_by_pref; base::ListValue handlers_ignored_by_policy; - handlers_ignored_by_pref.Append(GetProtocolHandlerValue("p1", URL_p1u1)); - handlers_ignored_by_pref.Append(GetProtocolHandlerValue("p1", URL_p1u2)); - handlers_ignored_by_pref.Append(GetProtocolHandlerValue("p1", URL_p1u2)); - handlers_ignored_by_pref.Append(GetProtocolHandlerValue("p3", URL_p3u1)); + handlers_ignored_by_pref.Append(GetProtocolHandlerValue("news", URL_p1u1)); + handlers_ignored_by_pref.Append(GetProtocolHandlerValue("news", URL_p1u2)); + handlers_ignored_by_pref.Append(GetProtocolHandlerValue("news", URL_p1u2)); + handlers_ignored_by_pref.Append(GetProtocolHandlerValue("mailto", URL_p3u1)); - handlers_ignored_by_policy.Append(GetProtocolHandlerValue("p1", URL_p1u2)); - handlers_ignored_by_policy.Append(GetProtocolHandlerValue("p1", URL_p1u3)); - handlers_ignored_by_policy.Append(GetProtocolHandlerValue("p2", URL_p2u1)); + handlers_ignored_by_policy.Append(GetProtocolHandlerValue("news", URL_p1u2)); + handlers_ignored_by_policy.Append(GetProtocolHandlerValue("news", URL_p1u3)); + handlers_ignored_by_policy.Append(GetProtocolHandlerValue("im", URL_p2u1)); profile()->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers, handlers_ignored_by_pref); @@ -945,21 +946,21 @@ ASSERT_EQ(InPrefIgnoredHandlerCount(), 4); ASSERT_EQ(InMemoryIgnoredHandlerCount(), 5); - ProtocolHandler p2u2 = CreateProtocolHandler("p2", GURL(URL_p2u2)); + ProtocolHandler p2u2 = CreateProtocolHandler("im", GURL(URL_p2u2)); registry()->OnIgnoreRegisterProtocolHandler(p2u2); // Duplicate p1u2 eliminated in pref, p2u2 added to pref and memory. ASSERT_EQ(InPrefIgnoredHandlerCount(), 4); ASSERT_EQ(InMemoryIgnoredHandlerCount(), 6); - ProtocolHandler p2u1 = CreateProtocolHandler("p2", GURL(URL_p2u1)); + ProtocolHandler p2u1 = CreateProtocolHandler("im", GURL(URL_p2u1)); registry()->RemoveIgnoredHandler(p2u1); // p2u1 installed by policy so cant be removed. ASSERT_EQ(InPrefIgnoredHandlerCount(), 4); ASSERT_EQ(InMemoryIgnoredHandlerCount(), 6); - ProtocolHandler p1u2 = CreateProtocolHandler("p1", GURL(URL_p1u2)); + ProtocolHandler p1u2 = CreateProtocolHandler("news", GURL(URL_p1u2)); registry()->RemoveIgnoredHandler(p1u2); // p1u2 installed by policy and pref so it is removed from pref and not from @@ -967,7 +968,7 @@ ASSERT_EQ(InPrefIgnoredHandlerCount(), 3); ASSERT_EQ(InMemoryIgnoredHandlerCount(), 6); - ProtocolHandler p1u1 = CreateProtocolHandler("p1", GURL(URL_p1u1)); + ProtocolHandler p1u1 = CreateProtocolHandler("news", GURL(URL_p1u1)); registry()->RemoveIgnoredHandler(p1u1); // p1u1 installed by pref so it is removed from pref and memory. @@ -1060,7 +1061,7 @@ TEST_F(ProtocolHandlerRegistryTest, TestMultiplePlaceholders) { ProtocolHandler ph = - CreateProtocolHandler("test", GURL("http://example.com/%s/url=%s")); + CreateProtocolHandler("news", GURL("http://example.com/%s/url=%s")); registry()->OnAcceptRegisterProtocolHandler(ph); GURL translated_url = ph.TranslateUrl(GURL("test:duplicated_placeholders")); @@ -1070,3 +1071,28 @@ ASSERT_EQ(translated_url, GURL("http://example.com/test%3Aduplicated_placeholders/url=%s")); } + +TEST_F(ProtocolHandlerRegistryTest, InvalidHandlers) { + // Invalid protocol. + registry()->OnAcceptRegisterProtocolHandler( + CreateProtocolHandler("foo", GURL("https://www.google.com/handler%s"))); + ASSERT_FALSE(registry()->IsHandledProtocol("foo")); + registry()->OnAcceptRegisterProtocolHandler( + CreateProtocolHandler("web", GURL("https://www.google.com/handler%s"))); + ASSERT_FALSE(registry()->IsHandledProtocol("web")); + registry()->OnAcceptRegisterProtocolHandler( + CreateProtocolHandler("web+", GURL("https://www.google.com/handler%s"))); + ASSERT_FALSE(registry()->IsHandledProtocol("web+")); + registry()->OnAcceptRegisterProtocolHandler( + CreateProtocolHandler("https", GURL("https://www.google.com/handler%s"))); + ASSERT_FALSE(registry()->IsHandledProtocol("https")); + + // Invalid handler URL. + registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler( + "news", + GURL("data:text/html,<html><body><b>hello world</b></body></html>%s"))); + ASSERT_FALSE(registry()->IsHandledProtocol("news")); + registry()->OnAcceptRegisterProtocolHandler( + CreateProtocolHandler("news", GURL("ftp://www.google.com/handler%s"))); + ASSERT_FALSE(registry()->IsHandledProtocol("news")); +}
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 8746bab3..1bd4259 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -511,6 +511,11 @@ "expiry_milestone": 77 }, { + "name": "crostini-webui-installer", + "owners": [ "lxj", "timloh", "benwells" ], + "expiry_milestone": 82 + }, + { "name": "crostini-gpu-support", "owners": [ "nverne", "benwells" ], "expiry_milestone": 78
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 286341c..0f82b5f6 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2998,6 +2998,10 @@ const char kCrostiniUsbSupportDescription[] = "Enable mounting Usb devices in Crostini."; +const char kCrostiniWebUIInstallerName[] = "Crostini WebUI Installer"; +const char kCrostiniWebUIInstallerDescription[] = + "Enable the new WebUI Crostini Installer."; + const char kCrosVmCupsProxyName[] = "Chrome OS CUPS Proxy"; const char kCrosVmCupsProxyDescription[] = "Supports printing from VMs on Chrome OS.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 8441f905..d983668 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1791,6 +1791,9 @@ extern const char kCrostiniUsbSupportName[]; extern const char kCrostiniUsbSupportDescription[]; +extern const char kCrostiniWebUIInstallerName[]; +extern const char kCrostiniWebUIInstallerDescription[]; + extern const char kCrosVmCupsProxyName[]; extern const char kCrosVmCupsProxyDescription[];
diff --git a/chrome/browser/history/top_sites_factory.cc b/chrome/browser/history/top_sites_factory.cc index a365998..c0545fa 100644 --- a/chrome/browser/history/top_sites_factory.cc +++ b/chrome/browser/history/top_sites_factory.cc
@@ -78,17 +78,30 @@ history::PrepopulatedPageList* prepopulated_pages) { #if !defined(OS_ANDROID) DCHECK(prepopulated_pages); - bool hide_web_store_icon = - profile->GetPrefs()->GetBoolean(prefs::kHideWebStoreIcon); + PrefService* pref_service = profile->GetPrefs(); + bool hide_web_store_icon = pref_service->GetBoolean(prefs::kHideWebStoreIcon); + + // The default shortcut is shown for new profiles, beginning at first run, if + // the feature is enabled. A pref is persisted so that the shortcut continues + // to be shown through browser restarts, when the profile is no longer + // considered "new". + bool is_search_shortcut_feature_enabled = + base::FeatureList::IsEnabled(features::kFirstRunDefaultSearchShortcut); + if (profile->IsNewProfile() && is_search_shortcut_feature_enabled) { + pref_service->SetBoolean(prefs::kShowFirstRunDefaultSearchShortcut, true); + } + bool show_default_search_shortcut = + is_search_shortcut_feature_enabled && + pref_service->GetBoolean(prefs::kShowFirstRunDefaultSearchShortcut); + prepopulated_pages->reserve(base::size(kRawPrepopulatedPages)); for (size_t i = 0; i < base::size(kRawPrepopulatedPages); ++i) { const RawPrepopulatedPage& page = kRawPrepopulatedPages[i]; if (hide_web_store_icon && page.url_id == IDS_WEBSTORE_URL) continue; - if (page.url_id == IDS_NTP_DEFAULT_SEARCH_URL && - !(profile->IsNewProfile() && - base::FeatureList::IsEnabled( - features::kFirstRunDefaultSearchShortcut))) { + + if (!show_default_search_shortcut && + page.url_id == IDS_NTP_DEFAULT_SEARCH_URL) { continue; }
diff --git a/chrome/browser/native_file_system/OWNERS b/chrome/browser/native_file_system/OWNERS new file mode 100644 index 0000000..7eb6aed --- /dev/null +++ b/chrome/browser/native_file_system/OWNERS
@@ -0,0 +1,6 @@ +file://content/browser/native_file_system/OWNERS + +per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS + +# TEAM: storage-dev@chromium.org +# COMPONENT: Blink>Storage>FileSystem
diff --git a/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc b/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc new file mode 100644 index 0000000..070e302 --- /dev/null +++ b/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc
@@ -0,0 +1,201 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/native_file_system/chrome_native_file_system_permission_context.h" + +#include <utility> + +#include "base/bind.h" +#include "base/task/post_task.h" +#include "chrome/browser/permissions/permission_util.h" +#include "chrome/browser/ui/browser_dialogs.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" + +namespace { + +void ShowWritePermissionPromptOnUIThread( + int process_id, + int frame_id, + const url::Origin& origin, + const base::FilePath& path, + bool is_directory, + base::OnceCallback<void(PermissionAction result)> callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + content::RenderFrameHost* rfh = + content::RenderFrameHost::FromID(process_id, frame_id); + if (!rfh || !rfh->IsCurrent()) { + // Requested from a no longer valid render frame host. + std::move(callback).Run(PermissionAction::DISMISSED); + return; + } + + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(rfh); + + if (!web_contents) { + // Requested from a worker, or a no longer existing tab. + std::move(callback).Run(PermissionAction::DISMISSED); + return; + } + + ShowNativeFileSystemPermissionDialog(origin, path, is_directory, + std::move(callback), web_contents); +} + +// Returns a callback that calls the passed in |callback| by posting a task to +// the current sequenced task runner. +base::OnceCallback<void(PermissionAction result)> +BindPermissionActionCallbackToCurrentSequence( + base::OnceCallback<void(PermissionAction result)> callback) { + return base::BindOnce( + [](scoped_refptr<base::TaskRunner> task_runner, + base::OnceCallback<void(PermissionAction result)> callback, + PermissionAction result) { + task_runner->PostTask(FROM_HERE, + base::BindOnce(std::move(callback), result)); + }, + base::SequencedTaskRunnerHandle::Get(), std::move(callback)); +} + +} // namespace + +class ChromeNativeFileSystemPermissionContext::PermissionGrantImpl + : public content::NativeFileSystemPermissionGrant { + public: + PermissionGrantImpl( + scoped_refptr<ChromeNativeFileSystemPermissionContext> context, + const url::Origin& origin, + const base::FilePath& path, + bool is_directory) + : context_(std::move(context)), + origin_(origin), + path_(path), + is_directory_(is_directory) {} + + const url::Origin& origin() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return origin_; + } + + const base::FilePath& path() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return path_; + } + + PermissionStatus GetStatus() override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return status_; + } + + void RequestPermission(int process_id, + int frame_id, + base::OnceClosure callback) override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (GetStatus() != PermissionStatus::ASK) { + std::move(callback).Run(); + return; + } + + auto result_callback = BindPermissionActionCallbackToCurrentSequence( + base::BindOnce(&PermissionGrantImpl::OnPermissionRequestComplete, this, + std::move(callback))); + + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&ShowWritePermissionPromptOnUIThread, process_id, + frame_id, origin_, path_, is_directory_, + std::move(result_callback))); + } + + protected: + ~PermissionGrantImpl() override { context_->PermissionGrantDestroyed(this); } + + private: + void OnPermissionRequestComplete(base::OnceClosure callback, + PermissionAction result) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + switch (result) { + case PermissionAction::GRANTED: + status_ = PermissionStatus::GRANTED; + break; + case PermissionAction::DENIED: + status_ = PermissionStatus::DENIED; + break; + case PermissionAction::DISMISSED: + case PermissionAction::IGNORED: + break; + case PermissionAction::REVOKED: + case PermissionAction::NUM: + NOTREACHED(); + break; + } + + std::move(callback).Run(); + } + + SEQUENCE_CHECKER(sequence_checker_); + + scoped_refptr<ChromeNativeFileSystemPermissionContext> const context_; + const url::Origin origin_; + const base::FilePath path_; + const bool is_directory_; + PermissionStatus status_ = PermissionStatus::ASK; + + DISALLOW_COPY_AND_ASSIGN(PermissionGrantImpl); +}; + +struct ChromeNativeFileSystemPermissionContext::OriginState { + // Raw pointers, owned collectively by all the handles that reference this + // grant. When last reference goes away this state is cleared as well by + // PermissionGrantDestroyed(). + // TODO(mek): Lifetime of grants might change depending on the outcome of + // the discussions surrounding lifetime of non-persistent permissions. + std::map<base::FilePath, PermissionGrantImpl*> grants; +}; + +ChromeNativeFileSystemPermissionContext:: + ChromeNativeFileSystemPermissionContext(content::BrowserContext*) { + DETACH_FROM_SEQUENCE(sequence_checker_); +} + +scoped_refptr<content::NativeFileSystemPermissionGrant> +ChromeNativeFileSystemPermissionContext::GetWritePermissionGrant( + const url::Origin& origin, + const base::FilePath& path, + bool is_directory) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // operator[] might insert a new OriginState in |origins_|, but that is + // exactly what we want. + auto& origin_state = origins_[origin]; + // TODO(mek): Do some kind of clever merging of grants, for example + // returning a parent directory's grant if that one already has write + // access. + auto*& existing_grant = origin_state.grants[path]; + if (existing_grant) + return existing_grant; + auto result = base::MakeRefCounted<PermissionGrantImpl>(this, origin, path, + is_directory); + existing_grant = result.get(); + return result; +} + +ChromeNativeFileSystemPermissionContext:: + ~ChromeNativeFileSystemPermissionContext() = default; + +void ChromeNativeFileSystemPermissionContext::ShutdownOnUIThread() {} + +void ChromeNativeFileSystemPermissionContext::PermissionGrantDestroyed( + PermissionGrantImpl* grant) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + auto it = origins_.find(grant->origin()); + DCHECK(it != origins_.end()); + it->second.grants.erase(grant->path()); + if (it->second.grants.empty()) { + // No more grants for the origin, so remove the state. + origins_.erase(it); + } +}
diff --git a/chrome/browser/native_file_system/chrome_native_file_system_permission_context.h b/chrome/browser/native_file_system/chrome_native_file_system_permission_context.h new file mode 100644 index 0000000..e4514ff --- /dev/null +++ b/chrome/browser/native_file_system/chrome_native_file_system_permission_context.h
@@ -0,0 +1,68 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NATIVE_FILE_SYSTEM_CHROME_NATIVE_FILE_SYSTEM_PERMISSION_CONTEXT_H_ +#define CHROME_BROWSER_NATIVE_FILE_SYSTEM_CHROME_NATIVE_FILE_SYSTEM_PERMISSION_CONTEXT_H_ + +#include <map> + +#include "base/sequence_checker.h" +#include "components/keyed_service/core/refcounted_keyed_service.h" +#include "content/public/browser/native_file_system_permission_context.h" +#include "third_party/blink/public/mojom/permissions/permission_status.mojom.h" + +namespace content { +class BrowserContext; +} // namespace content + +// Chrome implementation of NativeFileSystemPermissionContext. Currently +// implements a single per-origin write permission state. +// +// All methods (other than the constructor and destructor) should be called on +// the same sequence. +// +// TODO(mek): Reconsider if this class should just be UI-thread only, avoiding +// the need to make this ref-counted. +// +// This class does not inherit from ChooserContextBase because the model this +// API uses doesn't really match what ChooserContextBase has to provide. The +// limited lifetime of native file system permission grants (scoped to the +// lifetime of the handles that reference the grants), and the possible +// interactions between grants for directories and grants for children of those +// directories as well as possible interactions between read and write grants +// make it harder to squeeze this into a shape that fits with +// ChooserContextBase. +class ChromeNativeFileSystemPermissionContext + : public content::NativeFileSystemPermissionContext, + public RefcountedKeyedService { + public: + explicit ChromeNativeFileSystemPermissionContext( + content::BrowserContext* context); + + // content::NativeFileSystemPermissionContext: + scoped_refptr<content::NativeFileSystemPermissionGrant> + GetWritePermissionGrant(const url::Origin& origin, + const base::FilePath& path, + bool is_directory) override; + + // RefcountedKeyedService: + void ShutdownOnUIThread() override; + + private: + // Destructor is private because this class is refcounted. + ~ChromeNativeFileSystemPermissionContext() override; + + class PermissionGrantImpl; + void PermissionGrantDestroyed(PermissionGrantImpl* grant); + + SEQUENCE_CHECKER(sequence_checker_); + + // Permission state per origin. + struct OriginState; + std::map<url::Origin, OriginState> origins_; + + DISALLOW_COPY_AND_ASSIGN(ChromeNativeFileSystemPermissionContext); +}; + +#endif // CHROME_BROWSER_NATIVE_FILE_SYSTEM_CHROME_NATIVE_FILE_SYSTEM_PERMISSION_CONTEXT_H_
diff --git a/chrome/browser/native_file_system/native_file_system_permission_context_factory.cc b/chrome/browser/native_file_system/native_file_system_permission_context_factory.cc new file mode 100644 index 0000000..4336f58 --- /dev/null +++ b/chrome/browser/native_file_system/native_file_system_permission_context_factory.cc
@@ -0,0 +1,46 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/native_file_system/native_file_system_permission_context_factory.h" + +#include "base/no_destructor.h" +#include "chrome/browser/native_file_system/chrome_native_file_system_permission_context.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +// static +scoped_refptr<ChromeNativeFileSystemPermissionContext> +NativeFileSystemPermissionContextFactory::GetForProfile( + content::BrowserContext* profile) { + return static_cast<ChromeNativeFileSystemPermissionContext*>( + GetInstance()->GetServiceForBrowserContext(profile, true).get()); +} + +// static +NativeFileSystemPermissionContextFactory* +NativeFileSystemPermissionContextFactory::GetInstance() { + static base::NoDestructor<NativeFileSystemPermissionContextFactory> instance; + return instance.get(); +} + +NativeFileSystemPermissionContextFactory:: + NativeFileSystemPermissionContextFactory() + : RefcountedBrowserContextKeyedServiceFactory( + "NativeFileSystemPermissionContext", + BrowserContextDependencyManager::GetInstance()) {} + +NativeFileSystemPermissionContextFactory:: + ~NativeFileSystemPermissionContextFactory() = default; + +content::BrowserContext* +NativeFileSystemPermissionContextFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextOwnInstanceInIncognito(context); +} + +scoped_refptr<RefcountedKeyedService> +NativeFileSystemPermissionContextFactory::BuildServiceInstanceFor( + content::BrowserContext* profile) const { + return new ChromeNativeFileSystemPermissionContext(profile); +}
diff --git a/chrome/browser/native_file_system/native_file_system_permission_context_factory.h b/chrome/browser/native_file_system/native_file_system_permission_context_factory.h new file mode 100644 index 0000000..432ba1f --- /dev/null +++ b/chrome/browser/native_file_system/native_file_system_permission_context_factory.h
@@ -0,0 +1,38 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_PERMISSION_CONTEXT_FACTORY_H_ +#define CHROME_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_PERMISSION_CONTEXT_FACTORY_H_ + +#include "base/macros.h" +#include "base/no_destructor.h" +#include "components/keyed_service/content/refcounted_browser_context_keyed_service_factory.h" + +class ChromeNativeFileSystemPermissionContext; + +// Factory to get or create an instance of +// ChromeNativeFileSystemPermissionContext from a Profile. +class NativeFileSystemPermissionContextFactory + : public RefcountedBrowserContextKeyedServiceFactory { + public: + static scoped_refptr<ChromeNativeFileSystemPermissionContext> GetForProfile( + content::BrowserContext* profile); + static NativeFileSystemPermissionContextFactory* GetInstance(); + + private: + friend class base::NoDestructor<NativeFileSystemPermissionContextFactory>; + + NativeFileSystemPermissionContextFactory(); + ~NativeFileSystemPermissionContextFactory() override; + + // RefcountedBrowserContextKeyedServiceFactory: + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; + scoped_refptr<RefcountedKeyedService> BuildServiceInstanceFor( + content::BrowserContext* profile) const override; + + DISALLOW_COPY_AND_ASSIGN(NativeFileSystemPermissionContextFactory); +}; + +#endif // CHROME_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_PERMISSION_CONTEXT_FACTORY_H_
diff --git a/chrome/browser/password_manager/password_accessory_controller_impl.cc b/chrome/browser/password_manager/password_accessory_controller_impl.cc index 625771af..014e27a 100644 --- a/chrome/browser/password_manager/password_accessory_controller_impl.cc +++ b/chrome/browser/password_manager/password_accessory_controller_impl.cc
@@ -30,6 +30,7 @@ #include "components/favicon_base/favicon_types.h" #include "components/password_manager/content/browser/content_password_manager_driver.h" #include "components/password_manager/content/browser/content_password_manager_driver_factory.h" +#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h" #include "components/password_manager/core/browser/password_manager_driver.h" #include "components/password_manager/core/browser/password_manager_util.h" #include "components/password_manager/core/common/password_manager_features.h" @@ -49,8 +50,15 @@ namespace { autofill::UserInfo TranslateCredentials(bool current_field_is_password, + const GURL& origin_url, const CredentialPair& data) { - UserInfo user_info; + std::string user_info_origin; + // Use the origin only when it differs from the site origin. Android origins + // have a path but empty hosts. Since they are treated as first-party + // credentials, they will have an empty origin. + if (data.is_public_suffix_match) + user_info_origin = data.origin_url.host(); + UserInfo user_info(user_info_origin); base::string16 username = GetDisplayUsername(data); user_info.add_field(UserInfo::Field( @@ -243,10 +251,11 @@ for (const auto& pair : suggestions) { if (pair.is_public_suffix_match && !base::FeatureList::IsEnabled( - autofill::features::kAutofillKeyboardAccessory)) + autofill::features::kAutofillKeyboardAccessory)) { continue; // PSL origins have no representation in V1. Don't show them! - // TODO(crbug.com/976761): Mark PSL-matches with their origin. - info_to_add.push_back(TranslateCredentials(is_password_field, pair)); + } + info_to_add.push_back( + TranslateCredentials(is_password_field, origin.GetURL(), pair)); } }
diff --git a/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc b/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc index bc9f003..3bdee5d 100644 --- a/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc +++ b/chrome/browser/password_manager/password_accessory_controller_impl_unittest.cc
@@ -15,11 +15,13 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_callback.h" +#include "base/test/scoped_feature_list.h" #include "chrome/browser/autofill/mock_manual_filling_controller.h" #include "chrome/browser/password_manager/password_generation_controller.h" #include "chrome/browser/password_manager/password_generation_controller_impl.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/password_form.h" #include "components/autofill/core/common/signatures_util.h" #include "components/favicon/core/test/mock_favicon_service.h" @@ -48,11 +50,14 @@ using testing::Mock; using testing::NiceMock; using testing::Return; +using testing::SaveArg; using testing::StrictMock; using FillingSource = ManualFillingController::FillingSource; constexpr char kExampleSite[] = "https://example.com"; +constexpr char kExampleSiteMobile[] = "https://m.example.com"; constexpr char kExampleDomain[] = "example.com"; +constexpr char kExampleDomainMobile[] = "m.example.com"; constexpr int kIconSize = 75; // An example size for favicons (=> 3.5*20px). class MockPasswordGenerationController @@ -220,34 +225,35 @@ CreateEntry("Cat", "M1@u", GURL(kExampleDomain), false).first}, url::Origin::Create(GURL(kExampleSite))); - EXPECT_CALL( - mock_manual_filling_controller_, - RefreshSuggestions( - PasswordAccessorySheetDataBuilder(passwords_title_str(kExampleDomain)) - .AddUserInfo() - .AppendField(ASCIIToUTF16("Alf"), ASCIIToUTF16("Alf"), false, - true) - .AppendField(ASCIIToUTF16("PWD"), password_for_str("Alf"), true, - false) - .AddUserInfo() - .AppendField(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, - true) - .AppendField(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), - true, false) - .AddUserInfo() - .AppendField(ASCIIToUTF16("Cat"), ASCIIToUTF16("Cat"), false, - true) - .AppendField(ASCIIToUTF16("M1@u"), password_for_str("Cat"), true, - false) - .AddUserInfo() - .AppendField(ASCIIToUTF16("Zebra"), ASCIIToUTF16("Zebra"), false, - true) - .AppendField(ASCIIToUTF16("M3h"), password_for_str("Zebra"), true, - false) - .Build())); + AccessorySheetData result(AccessoryTabType::PASSWORDS, base::string16()); + EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions) + .WillOnce(SaveArg<0>(&result)); + controller()->RefreshSuggestionsForField( FocusedFieldType::kFillableUsernameField, /*is_manual_generation_available=*/false); + + EXPECT_EQ( + result, + PasswordAccessorySheetDataBuilder(passwords_title_str(kExampleDomain)) + .AddUserInfo() + .AppendField(ASCIIToUTF16("Alf"), ASCIIToUTF16("Alf"), false, true) + .AppendField(ASCIIToUTF16("PWD"), password_for_str("Alf"), true, + false) + .AddUserInfo() + .AppendField(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, true) + .AppendField(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, + false) + .AddUserInfo() + .AppendField(ASCIIToUTF16("Cat"), ASCIIToUTF16("Cat"), false, true) + .AppendField(ASCIIToUTF16("M1@u"), password_for_str("Cat"), true, + false) + .AddUserInfo() + .AppendField(ASCIIToUTF16("Zebra"), ASCIIToUTF16("Zebra"), false, + true) + .AppendField(ASCIIToUTF16("M3h"), password_for_str("Zebra"), true, + false) + .Build()); } TEST_F(PasswordAccessoryControllerTest, RepeatsSuggestionsForSameFrame) { @@ -371,6 +377,67 @@ /*is_manual_generation_available=*/false); } +TEST_F(PasswordAccessoryControllerTest, HidesEntriesForPSLMatchedOriginsInV1) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature( + autofill::features::kAutofillKeyboardAccessory); + cache()->SaveCredentialsForOrigin( + {CreateEntry("Ben", "S3cur3", GURL(kExampleSite), false).first, + CreateEntry("Alf", "R4nd0m", GURL(kExampleSiteMobile), true).first}, + url::Origin::Create(GURL(kExampleSite))); + + AccessorySheetData result(AccessoryTabType::PASSWORDS, base::string16()); + EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions) + .WillOnce(SaveArg<0>(&result)); + + controller()->RefreshSuggestionsForField( + FocusedFieldType::kFillableUsernameField, + /*is_manual_generation_available=*/false); + + EXPECT_EQ( + result, + PasswordAccessorySheetDataBuilder(passwords_title_str(kExampleDomain)) + .AddUserInfo() + .AppendField(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), + /*is_obfuscated=*/false, /*selectable=*/true) + .AppendField(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), + /*is_obfuscated=*/true, /*selectable=*/false) + .Build()); +} + +TEST_F(PasswordAccessoryControllerTest, SetsTitleForPSLMatchedOriginsInV2) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature( + autofill::features::kAutofillKeyboardAccessory); + cache()->SaveCredentialsForOrigin( + {CreateEntry("Ben", "S3cur3", GURL(kExampleSite), false).first, + CreateEntry("Alf", "R4nd0m", GURL(kExampleSiteMobile), true).first}, + url::Origin::Create(GURL(kExampleSite))); + + AccessorySheetData result(AccessoryTabType::PASSWORDS, base::string16()); + EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions) + .WillOnce(SaveArg<0>(&result)); + + controller()->RefreshSuggestionsForField( + FocusedFieldType::kFillableUsernameField, + /*is_manual_generation_available=*/false); + + EXPECT_EQ( + result, + PasswordAccessorySheetDataBuilder(passwords_title_str(kExampleDomain)) + .AddUserInfo() + .AppendField(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), + /*is_obfuscated=*/false, /*selectable=*/true) + .AppendField(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), + /*is_obfuscated=*/true, /*selectable=*/false) + .AddUserInfo(kExampleDomainMobile) + .AppendField(ASCIIToUTF16("Alf"), ASCIIToUTF16("Alf"), + /*is_obfuscated=*/false, /*selectable=*/true) + .AppendField(ASCIIToUTF16("R4nd0m"), password_for_str("Alf"), + /*is_obfuscated=*/true, /*selectable=*/false) + .Build()); +} + TEST_F(PasswordAccessoryControllerTest, UnfillableFieldClearsSuggestions) { cache()->SaveCredentialsForOrigin( {CreateEntry("Ben", "S3cur3", GURL(kExampleDomain), false).first}, @@ -440,7 +507,7 @@ TEST_F(PasswordAccessoryControllerTest, FetchFaviconForCurrentUrl) { base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback; - EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions(_)); + EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions); controller()->RefreshSuggestionsForField( FocusedFieldType::kFillableUsernameField, /*is_manual_generation_available=*/false); @@ -463,7 +530,7 @@ TEST_F(PasswordAccessoryControllerTest, RequestsFaviconsOnceForOneOrigin) { base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback; - EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions(_)); + EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions); controller()->RefreshSuggestionsForField( FocusedFieldType::kFillableUsernameField, /*is_manual_generation_available=*/false); @@ -506,7 +573,7 @@ non_empty_result.icon_url = GURL(kExampleSite); // Populate the cache by requesting a favicon. - EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions(_)); + EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions); controller()->RefreshSuggestionsForField( FocusedFieldType::kFillableUsernameField, /*is_manual_generation_available=*/false); @@ -537,7 +604,7 @@ controller()->DidNavigateMainFrame(); NavigateAndCommit(GURL(kExampleSite)); // Same origin as intially. controller()->DidNavigateMainFrame(); - EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions(_)); + EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions); controller()->RefreshSuggestionsForField( FocusedFieldType::kFillableUsernameField, /*is_manual_generation_available=*/false); @@ -560,7 +627,7 @@ TEST_F(PasswordAccessoryControllerTest, NoFaviconCallbacksWhenOriginChanges) { base::MockCallback<base::OnceCallback<void(const gfx::Image&)>> mock_callback; - EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions(_)).Times(2); + EXPECT_CALL(mock_manual_filling_controller_, RefreshSuggestions).Times(2); controller()->RefreshSuggestionsForField( FocusedFieldType::kFillableUsernameField, false);
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 99396124..395887c 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc
@@ -55,6 +55,8 @@ #include "chrome/browser/download/download_manager_utils.h" #include "chrome/browser/gcm/gcm_profile_service_factory.h" #include "chrome/browser/media/media_device_id_salt.h" +#include "chrome/browser/native_file_system/chrome_native_file_system_permission_context.h" +#include "chrome/browser/native_file_system/native_file_system_permission_context_factory.h" #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/permissions/permission_manager.h" #include "chrome/browser/permissions/permission_manager_factory.h" @@ -1354,6 +1356,11 @@ return SmsServiceFactory::GetForProfile(this)->Get(); } +content::NativeFileSystemPermissionContext* +ProfileImpl::GetNativeFileSystemPermissionContext() { + return NativeFileSystemPermissionContextFactory::GetForProfile(this).get(); +} + bool ProfileImpl::IsSameProfile(Profile* profile) { if (profile == static_cast<Profile*>(this)) return true;
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h index c93da7f..01f29579 100644 --- a/chrome/browser/profiles/profile_impl.h +++ b/chrome/browser/profiles/profile_impl.h
@@ -38,7 +38,7 @@ class LocaleChangeGuard; class Preferences; class SupervisedUserTestBase; -} +} // namespace chromeos #endif namespace base { @@ -108,6 +108,8 @@ download::InProgressDownloadManager* RetriveInProgressDownloadManager() override; content::SmsService* GetSmsService() override; + content::NativeFileSystemPermissionContext* + GetNativeFileSystemPermissionContext() override; // Profile implementation: scoped_refptr<base::SequencedTaskRunner> GetIOTaskRunner() override;
diff --git a/chrome/browser/resources/about_nacl/about_nacl.html b/chrome/browser/resources/about_nacl/about_nacl.html index a67298c4..c804549 100644 --- a/chrome/browser/resources/about_nacl/about_nacl.html +++ b/chrome/browser/resources/about_nacl/about_nacl.html
@@ -1,5 +1,5 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.html b/chrome/browser/resources/chromeos/network_ui/network_ui.html index be60a47..6303311 100644 --- a/chrome/browser/resources/chromeos/network_ui/network_ui.html +++ b/chrome/browser/resources/chromeos/network_ui/network_ui.html
@@ -37,6 +37,13 @@ <div id="cellular-error-text" hidden>$i18n{noCellularErrorText}</div> </div> + <div> + <h2>$i18n{addNewWifiLabel}</h2> + <cr-button class="action-button" id="add-new-wifi-button"> + $i18n{addNewWifiButtonText} + </cr-button> + </div> + <h2>$i18n{globalPolicyLabel}</h2> <div id="global-policy"></div>
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.js b/chrome/browser/resources/chromeos/network_ui/network_ui.js index 0e672d7..cb60f5a 100644 --- a/chrome/browser/resources/chromeos/network_ui/network_ui.js +++ b/chrome/browser/resources/chromeos/network_ui/network_ui.js
@@ -457,6 +457,13 @@ }; /** + * Requests that the "add Wi-Fi network" UI be displayed. + */ + const showAddNewWifi = function() { + chrome.send('showAddNewWifi'); + }; + + /** * Requests an update of all network info. */ const requestNetworks = function() { @@ -555,6 +562,7 @@ ]; select.addEventListener('network-item-selected', onNetworkItemSelected); $('cellular-activation-button').onclick = openCellularActivationUi; + $('add-new-wifi-button').onclick = showAddNewWifi; $('refresh').onclick = requestNetworks; init(); requestNetworks();
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/back.svg b/chrome/browser/resources/chromeos/switch_access/icons/back.svg index 6d3ce94..22d935b 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/back.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/back.svg
@@ -2,7 +2,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="#FFFFFF"> +<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="#E8EAED"> <path fill="none" d="M0 0h24v24H0V0z"/> <path d="M19 15l-6 6-1.42-1.42L15.17 16H4V4h2v10h9.17l-3.59-3.58L13 9l6 6z"/> </svg>
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/decrement.svg b/chrome/browser/resources/chromeos/switch_access/icons/decrement.svg index 1fe4eec2..0ac1823 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/decrement.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/decrement.svg
@@ -2,4 +2,4 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m14 9v2h-8v-2zm-4-7c-4.424 0-8 3.576-8 8s3.576 8 8 8 8-3.576 8-8-3.576-8-8-8zm0 14c-3.3075 0-6-2.6925-6-6s2.6925-6 6-6 6 2.6925 6 6-2.6925 6-6 6z" fill="#5f6368" fill-rule="evenodd"/></svg> +<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m14 9v2h-8v-2zm-4-7c-4.424 0-8 3.576-8 8s3.576 8 8 8 8-3.576 8-8-3.576-8-8-8zm0 14c-3.3075 0-6-2.6925-6-6s2.6925-6 6-6 6 2.6925 6 6-2.6925 6-6 6z" fill="#E8EAED" fill-rule="evenodd"/></svg>
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/increment.svg b/chrome/browser/resources/chromeos/switch_access/icons/increment.svg index 05129d68..f71fb78d 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/increment.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/increment.svg
@@ -2,4 +2,4 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m14 9v2h-3v3h-2v-3h-3v-2h3v-3h2v3zm-4-7c-4.424 0-8 3.576-8 8s3.576 8 8 8 8-3.576 8-8-3.576-8-8-8zm0 14c-3.3075 0-6-2.6925-6-6s2.6925-6 6-6 6 2.6925 6 6-2.6925 6-6 6z" fill="#5f6368" fill-rule="evenodd"/></svg> +<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m14 9v2h-3v3h-2v-3h-3v-2h3v-3h2v3zm-4-7c-4.424 0-8 3.576-8 8s3.576 8 8 8 8-3.576 8-8-3.576-8-8-8zm0 14c-3.3075 0-6-2.6925-6-6s2.6925-6 6-6 6 2.6925 6 6-2.6925 6-6 6z" fill="#E8EAED" fill-rule="evenodd"/></svg>
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/keyboard.svg b/chrome/browser/resources/chromeos/switch_access/icons/keyboard.svg index 56f56a3..0b9ef62 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/keyboard.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/keyboard.svg
@@ -2,4 +2,4 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0zm0 0h24v24H0V0z"/><path fill="white" d="M20 7v10H4V7h16m0-2H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2zm0 3h2v2h-2zM8 8h2v2H8zm0 3h2v2H8zm-3 0h2v2H5zm0-3h2v2H5zm3 6h8v2H8zm6-3h2v2h-2zm0-3h2v2h-2zm3 3h2v2h-2zm0-3h2v2h-2z"/></svg> +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0zm0 0h24v24H0V0z"/><path fill="#E8EAED" d="M20 7v10H4V7h16m0-2H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2zm0 3h2v2h-2zM8 8h2v2H8zm0 3h2v2H8zm-3 0h2v2H5zm0-3h2v2H5zm3 6h8v2H8zm6-3h2v2h-2zm0-3h2v2h-2zm3 3h2v2h-2zm0-3h2v2h-2z"/></svg>
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/options.svg b/chrome/browser/resources/chromeos/switch_access/icons/options.svg index a1111e5..ae7e005 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/options.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/options.svg
@@ -2,4 +2,4 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m14 10c0-1.104.896-2 2-2 1.105 0 2 .896 2 2 0 1.105-.895 2-2 2-1.104 0-2-.895-2-2zm-2 0c0 1.105-.895 2-2 2-1.104 0-2-.895-2-2 0-1.104.896-2 2-2 1.105 0 2 .896 2 2zm-6 0c0 1.105-.895 2-2 2-1.104 0-2-.895-2-2 0-1.104.896-2 2-2 1.105 0 2 .896 2 2z" fill="#5f6368" fill-rule="evenodd" transform="matrix(0 1 -1 0 20 0)"/></svg> +<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m14 10c0-1.104.896-2 2-2 1.105 0 2 .896 2 2 0 1.105-.895 2-2 2-1.104 0-2-.895-2-2zm-2 0c0 1.105-.895 2-2 2-1.104 0-2-.895-2-2 0-1.104.896-2 2-2 1.105 0 2 .896 2 2zm-6 0c0 1.105-.895 2-2 2-1.104 0-2-.895-2-2 0-1.104.896-2 2-2 1.105 0 2 .896 2 2z" fill="#E8EAED" fill-rule="evenodd" transform="matrix(0 1 -1 0 20 0)"/></svg>
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/scrollDownOrForward.svg b/chrome/browser/resources/chromeos/switch_access/icons/scrollDownOrForward.svg index 099c833..6a89643 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/scrollDownOrForward.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/scrollDownOrForward.svg
@@ -2,4 +2,4 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m11 9.71012132 1.872-1.95466677 1.128 1.15363636-4 4.09090909-4-4.09090909 1.128-1.15363636 1.872 1.87363481v-6.62908936h2zm3 7.28987868h-8v-2h8z" fill="#5f6368" fill-rule="evenodd"/></svg> +<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m11 9.71012132 1.872-1.95466677 1.128 1.15363636-4 4.09090909-4-4.09090909 1.128-1.15363636 1.872 1.87363481v-6.62908936h2zm3 7.28987868h-8v-2h8z" fill="#E8EAED" fill-rule="evenodd"/></svg>
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/scrollLeft.svg b/chrome/browser/resources/chromeos/switch_access/icons/scrollLeft.svg index 99c3b2c..6df8c319 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/scrollLeft.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/scrollLeft.svg
@@ -2,4 +2,4 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m10.2898787 11 1.9546668 1.872-1.1536364 1.128-4.0909091-4 4.0909091-4 1.1536364 1.128-1.8736349 1.872h6.6290894v2zm-7.2898787 3v-8h2v8z" fill="#5f6368" fill-rule="evenodd"/></svg> +<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m10.2898787 11 1.9546668 1.872-1.1536364 1.128-4.0909091-4 4.0909091-4 1.1536364 1.128-1.8736349 1.872h6.6290894v2zm-7.2898787 3v-8h2v8z" fill="#E8EAED" fill-rule="evenodd"/></svg>
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/scrollRight.svg b/chrome/browser/resources/chromeos/switch_access/icons/scrollRight.svg index 95b4116..72a01a6 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/scrollRight.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/scrollRight.svg
@@ -2,4 +2,4 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m11 9.71012132 1.872-1.95466677 1.128 1.15363636-4 4.09090909-4-4.09090909 1.128-1.15363636 1.872 1.87363481v-6.62908936h2zm3 7.28987868h-8v-2h8z" fill="#5f6368" fill-rule="evenodd" transform="matrix(0 -1 1 0 0 20)"/></svg> +<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m11 9.71012132 1.872-1.95466677 1.128 1.15363636-4 4.09090909-4-4.09090909 1.128-1.15363636 1.872 1.87363481v-6.62908936h2zm3 7.28987868h-8v-2h8z" fill="#E8EAED" fill-rule="evenodd" transform="matrix(0 -1 1 0 0 20)"/></svg>
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/scrollUpOrBackward.svg b/chrome/browser/resources/chromeos/switch_access/icons/scrollUpOrBackward.svg index 0fe61678..b6fff2ee 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/scrollUpOrBackward.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/scrollUpOrBackward.svg
@@ -2,4 +2,4 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m9 10.2898787-1.872 1.9546668-1.128-1.1536364 4-4.0909091 4 4.0909091-1.128 1.1536364-1.872-1.8736349v6.6290894h-2zm-3-7.2898787h8v2h-8z" fill="#5f6368" fill-rule="evenodd"/></svg> +<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m9 10.2898787-1.872 1.9546668-1.128-1.1536364 4-4.0909091 4 4.0909091-1.128 1.1536364-1.872-1.8736349v6.6290894h-2zm-3-7.2898787h8v2h-8z" fill="#E8EAED" fill-rule="evenodd"/></svg>
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/select.svg b/chrome/browser/resources/chromeos/switch_access/icons/select.svg index a90933e..f4a8ac1a 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/select.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/select.svg
@@ -2,4 +2,4 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m3 3h2v2h-2zm0 4h2v2h-2zm0 4h2v2h-2zm0 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm0-4h2v2h-2zm0-4h2v2h-2zm0-4h2v2h-2zm-4 0h2v2h-2zm-4 0h2v2h-2z" fill="#5f6368" fill-rule="evenodd"/></svg> +<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m3 3h2v2h-2zm0 4h2v2h-2zm0 4h2v2h-2zm0 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm0-4h2v2h-2zm0-4h2v2h-2zm0-4h2v2h-2zm-4 0h2v2h-2zm-4 0h2v2h-2z" fill="#E8EAED" fill-rule="evenodd"/></svg>
diff --git a/chrome/browser/resources/chromeos/switch_access/icons/showContextMenu.svg b/chrome/browser/resources/chromeos/switch_access/icons/showContextMenu.svg index eea6f9b..ede6b6a 100644 --- a/chrome/browser/resources/chromeos/switch_access/icons/showContextMenu.svg +++ b/chrome/browser/resources/chromeos/switch_access/icons/showContextMenu.svg
@@ -2,4 +2,4 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m5 2h10c1.1045695 0 2 .8954305 2 2v12c0 1.1045695-.8954305 2-2 2h-10c-1.1045695 0-2-.8954305-2-2v-12c0-1.1045695.8954305-2 2-2zm0 2v12h10v-12zm2 2h6v2h-6zm0 3h6v2h-6zm0 3h4v2h-4z" fill="#5f6368" fill-rule="evenodd"/></svg> +<svg height="20" viewBox="0 0 20 20" width="20" xmlns="http://www.w3.org/2000/svg"><path d="m5 2h10c1.1045695 0 2 .8954305 2 2v12c0 1.1045695-.8954305 2-2 2h-10c-1.1045695 0-2-.8954305-2-2v-12c0-1.1045695.8954305-2 2-2zm0 2v12h10v-12zm2 2h6v2h-6zm0 3h6v2h-6zm0 3h4v2h-4z" fill="#E8EAED" fill-rule="evenodd"/></svg>
diff --git a/chrome/browser/resources/domain_reliability_internals/domain_reliability_internals.html b/chrome/browser/resources/domain_reliability_internals/domain_reliability_internals.html index 7bb2a1b8..10203ebc 100644 --- a/chrome/browser/resources/domain_reliability_internals/domain_reliability_internals.html +++ b/chrome/browser/resources/domain_reliability_internals/domain_reliability_internals.html
@@ -1,5 +1,5 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.css b/chrome/browser/resources/local_ntp/custom_links_edit.css index b0edd041..a8864a26 100644 --- a/chrome/browser/resources/local_ntp/custom_links_edit.css +++ b/chrome/browser/resources/local_ntp/custom_links_edit.css
@@ -26,9 +26,8 @@ @media (prefers-color-scheme: dark) { #edit-link-dialog { - background-color: rgb(41, 42, 45); - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .3), - 0 4px 8px 3px rgba(0, 0, 0, .15); + background-color: rgb(var(--dark-mode-dialog-rgb)); + box-shadow: var(--dark-mode-shadow); } }
diff --git a/chrome/browser/resources/local_ntp/customize.css b/chrome/browser/resources/local_ntp/customize.css index 3414057..0022263 100644 --- a/chrome/browser/resources/local_ntp/customize.css +++ b/chrome/browser/resources/local_ntp/customize.css
@@ -49,7 +49,7 @@ @media (prefers-color-scheme: dark) { #edit-bg.ep-enhanced { - background-color: rgb(41, 42, 45); + background-color: rgb(var(--dark-mode-dialog-rgb)); } } @@ -142,9 +142,8 @@ @media (prefers-color-scheme: dark) { #edit-bg-dialog { - background-color: rgb(41, 42, 45); - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .3), - 0 4px 8px 3px rgba(0, 0, 0, .15); + background-color: rgb(var(--dark-mode-dialog-rgb)); + box-shadow: var(--dark-mode-shadow); } } @@ -298,10 +297,9 @@ @media (prefers-color-scheme: dark) { #bg-sel-menu { - background-color: rgb(41, 42, 45); - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .3), - 0 4px 8px 3px rgba(0, 0, 0, .15); - } + background-color: rgb(var(--dark-mode-dialog-rgb)); + box-shadow: var(--dark-mode-shadow); + } } /* The width is decided by the longest text length plus 16px margin on the
diff --git a/chrome/browser/resources/local_ntp/doodles.css b/chrome/browser/resources/local_ntp/doodles.css index e2472dd..4e797d9d 100644 --- a/chrome/browser/resources/local_ntp/doodles.css +++ b/chrome/browser/resources/local_ntp/doodles.css
@@ -242,9 +242,8 @@ @media (prefers-color-scheme: dark) { #ddlsd { - background-color: rgb(41, 42, 45); - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), - 0 4px 8px 3px rgba(0, 0, 0, 0.15); + background-color: rgb(var(--dark-mode-dialog-rgb)); + box-shadow: var(--dark-mode-shadow); } #ddlsd::backdrop {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css index fa419de6..c82d91f4 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.css +++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -817,9 +817,8 @@ @media (prefers-color-scheme: dark) { #customization-menu { - background-color: rgb(41, 42, 45); - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .3), - 0 4px 8px 3px rgba(0, 0, 0, .15); + background-color: rgb(var(--dark-mode-dialog-rgb)); + box-shadow: var(--dark-mode-shadow); color: rgb(var(--GG200-rgb)); } } @@ -1243,7 +1242,7 @@ @media (prefers-color-scheme: dark) { #backgrounds-default-icon { - background-color: rgb(41, 42, 45); + background-color: rgb(var(--dark-mode-dialog-rgb)); border-color: rgb(var(--GG700-rgb)); } @@ -1351,7 +1350,7 @@ @media (prefers-color-scheme: dark) { .sh-option-mini { - background-color: rgb(41, 42, 45); + background-color: rgb(var(--dark-mode-dialog-rgb)); border-color: rgb(var(--GG700-rgb)); } } @@ -1369,8 +1368,7 @@ @media (prefers-color-scheme: dark) { .selected .sh-option-mini { border-color: transparent; - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .3), - 0 4px 8px 3px rgba(0, 0, 0, .15); + box-shadow: var(--dark-mode-shadow); } } @@ -1542,7 +1540,7 @@ @media (prefers-color-scheme: dark) { .switch { - background-color: rgb(41, 42, 45); + background-color: rgb(var(--dark-mode-dialog-rgb)); } }
diff --git a/chrome/browser/resources/local_ntp/local_ntp_common.css b/chrome/browser/resources/local_ntp/local_ntp_common.css index cfa54671..102d85b 100644 --- a/chrome/browser/resources/local_ntp/local_ntp_common.css +++ b/chrome/browser/resources/local_ntp/local_ntp_common.css
@@ -6,6 +6,7 @@ /* Material Design colors. Keep in sync with ui/gfx/color_palette.h. */ --dark-mode-bg-rgb: 50, 54, 57; + --dark-mode-dialog-rgb: 41, 42, 45; /* Google Grey */ --GG050-rgb: 248, 249, 250; @@ -47,6 +48,9 @@ --GR500-dark-rgb: 230, 106, 94; --GR600-dark-rgb: 211, 59, 48; --GR800-dark-rgb: 180, 27, 26; + + --dark-mode-shadow: 0 1px 3px 0 rgba(0, 0, 0, .3), + 0 4px 8px 3px rgba(0, 0, 0, .15); } body * {
diff --git a/chrome/browser/resources/local_ntp/voice.css b/chrome/browser/resources/local_ntp/voice.css index fde0cac..58f3dd51 100644 --- a/chrome/browser/resources/local_ntp/voice.css +++ b/chrome/browser/resources/local_ntp/voice.css
@@ -57,7 +57,7 @@ @media (prefers-color-scheme: dark) { .overlay-dialog::backdrop { - background-color: rgb(41, 42, 45); + background-color: rgb(var(--dark-mode-dialog-rgb)); } } @@ -75,7 +75,7 @@ @media (prefers-color-scheme: dark) { .overlay, .overlay-hidden { - background-color: rgb(41, 42, 45); + background-color: rgb(var(--dark-mode-dialog-rgb)); } }
diff --git a/chrome/browser/resources/quota_internals/main.html b/chrome/browser/resources/quota_internals/main.html index a1a1b11..51eb50ca 100644 --- a/chrome/browser/resources/quota_internals/main.html +++ b/chrome/browser/resources/quota_internals/main.html
@@ -4,7 +4,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <title>Quota Internals</title> <meta charset="utf-8"> <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
diff --git a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js index 0fcdc63..3531de7 100644 --- a/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js +++ b/chrome/browser/resources/settings/google_assistant_page/google_assistant_page.js
@@ -41,7 +41,7 @@ Polymer({ is: 'settings-google-assistant-page', - behaviors: [I18nBehavior, PrefsBehavior], + behaviors: [I18nBehavior, PrefsBehavior, WebUIListenerBehavior], properties: { /** @private */ @@ -124,6 +124,15 @@ this.browserProxy_ = settings.GoogleAssistantBrowserProxyImpl.getInstance(); }, + /** @override */ + ready: function() { + this.addWebUIListener('hotwordDeviceUpdated', (hasHotword) => { + this.hotwordDspAvailable_ = hasHotword; + }); + + chrome.send('initializeGoogleAssistantPage'); + }, + /** * @param {boolean} toggleValue * @return {string}
diff --git a/chrome/browser/resources/sync_file_system_internals/main.html b/chrome/browser/resources/sync_file_system_internals/main.html index b0fe206..f0c42da 100644 --- a/chrome/browser/resources/sync_file_system_internals/main.html +++ b/chrome/browser/resources/sync_file_system_internals/main.html
@@ -4,7 +4,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <meta charset="utf-8"> <title>Sync File System Internals</title> <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/google_app_proxy.js b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/google_app_proxy.js index 4fc9f24..b4edc67 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/google_app_proxy.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/google_app_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define('nux', function() { +cr.define('welcome', function() { /** * NuxGoogleAppsSelections enum. * These values are persisted to logs and should not be renumbered or @@ -30,7 +30,7 @@ /** * Returns a promise for an array of Google apps. - * @return {!Promise<!Array<!nux.BookmarkListItem>>} + * @return {!Promise<!Array<!welcome.BookmarkListItem>>} */ getAppList() {} @@ -41,7 +41,7 @@ recordProviderSelected(providerId) {} } - /** @implements {nux.GoogleAppProxy} */ + /** @implements {welcome.GoogleAppProxy} */ class GoogleAppProxyImpl { /** @override */ cacheBookmarkIcon(appId) {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.js b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.js index 1e37e95..8452574c 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/nux_google_apps.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.exportPath('nux'); +cr.exportPath('welcome'); /** * @typedef {{ @@ -14,15 +14,15 @@ * selected: boolean, * }} */ -nux.AppItem; +welcome.AppItem; /** * @typedef {{ - * item: !nux.AppItem, + * item: !welcome.AppItem, * set: function(string, boolean):void * }} */ -nux.AppItemModel; +welcome.AppItemModel; const KEYBOARD_FOCUSED = 'keyboard-focused'; @@ -32,11 +32,11 @@ behaviors: [welcome.NavigationBehavior, I18nBehavior], properties: { - /** @type {nux.stepIndicatorModel} */ + /** @type {welcome.stepIndicatorModel} */ indicatorModel: Object, /** - * @type {!Array<!nux.AppItem>} + * @type {!Array<!welcome.AppItem>} * @private */ appList_: Array, @@ -48,19 +48,19 @@ }, }, - /** @private {nux.GoogleAppProxy} */ + /** @private {welcome.GoogleAppProxy} */ appProxy_: null, - /** @private {?nux.ModuleMetricsManager} */ + /** @private {?welcome.ModuleMetricsManager} */ metricsManager_: null, /** @private */ finalized_: false, - /** @private {nux.BookmarkProxy} */ + /** @private {welcome.BookmarkProxy} */ bookmarkProxy_: null, - /** @private {nux.BookmarkBarManager} */ + /** @private {welcome.BookmarkBarManager} */ bookmarkBarManager_: null, /** @private {boolean} */ @@ -68,11 +68,11 @@ /** @override */ ready: function() { - this.appProxy_ = nux.GoogleAppProxyImpl.getInstance(); - this.metricsManager_ = new nux.ModuleMetricsManager( - nux.GoogleAppsMetricsProxyImpl.getInstance()); - this.bookmarkProxy_ = nux.BookmarkProxyImpl.getInstance(); - this.bookmarkBarManager_ = nux.BookmarkBarManager.getInstance(); + this.appProxy_ = welcome.GoogleAppProxyImpl.getInstance(); + this.metricsManager_ = new welcome.ModuleMetricsManager( + welcome.GoogleAppsMetricsProxyImpl.getInstance()); + this.bookmarkProxy_ = welcome.BookmarkProxyImpl.getInstance(); + this.bookmarkBarManager_ = welcome.BookmarkBarManager.getInstance(); }, /** @override */ @@ -164,7 +164,7 @@ /** * Handle toggling the apps selected. - * @param {!{model: !nux.AppItemModel}} e + * @param {!{model: !welcome.AppItemModel}} e * @private */ onAppClick_: function(e) { @@ -235,7 +235,7 @@ this.appList_.forEach(app => this.updateBookmark_(app)); } else { this.appProxy_.getAppList().then(list => { - this.appList_ = /** @type(!Array<!nux.AppItem>) */ (list); + this.appList_ = /** @type(!Array<!welcome.AppItem>) */ (list); this.appList_.forEach((app, index) => { // Default select first few items. app.selected = index < 3; @@ -248,7 +248,7 @@ }, /** - * @param {!nux.AppItem} item + * @param {!welcome.AppItem} item * @private */ updateBookmark_: function(item) {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/landing_view.js b/chrome/browser/resources/welcome/onboarding_welcome/landing_view.js index aa29004..94f6d4ad 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/landing_view.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/landing_view.js
@@ -15,7 +15,7 @@ } }, - /** @private {?nux.LandingViewProxy} */ + /** @private {?welcome.LandingViewProxy} */ landingViewProxy_: null, /** @private {boolean} */ @@ -23,7 +23,7 @@ /** @override */ ready() { - this.landingViewProxy_ = nux.LandingViewProxyImpl.getInstance(); + this.landingViewProxy_ = welcome.LandingViewProxyImpl.getInstance(); }, onRouteEnter: function() {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/landing_view_proxy.js b/chrome/browser/resources/welcome/onboarding_welcome/landing_view_proxy.js index 50d9fc0..1ccfbec 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/landing_view_proxy.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/landing_view_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define('nux', function() { +cr.define('welcome', function() { const NUX_LANDING_PAGE_INTERACTION_METRIC_NAME = 'FirstRun.NewUserExperience.LandingPageInteraction'; @@ -33,7 +33,7 @@ recordExistingUser() {} } - /** @implements {nux.LandingViewProxy} */ + /** @implements {welcome.LandingViewProxy} */ class LandingViewProxyImpl { /** @override */ recordPageShown() {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/ntp_background_proxy.js b/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/ntp_background_proxy.js index d0715a1..17b8ee6 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/ntp_background_proxy.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/ntp_background_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define('nux', function() { +cr.define('welcome', function() { /** * @typedef {{ * id: number, @@ -17,7 +17,7 @@ class NtpBackgroundProxy { clearBackground() {} - /** @return {!Promise<!Array<!nux.NtpBackgroundData>>} */ + /** @return {!Promise<!Array<!welcome.NtpBackgroundData>>} */ getBackgrounds() {} /** @@ -37,7 +37,7 @@ setBackground(id) {} } - /** @implements {nux.NtpBackgroundProxy} */ + /** @implements {welcome.NtpBackgroundProxy} */ class NtpBackgroundProxyImpl { /** @override */ clearBackground() { @@ -62,7 +62,7 @@ /** @override */ recordBackgroundImageFailedToLoad() { const ntpInteractions = - nux.NtpBackgroundMetricsProxyImpl.getInstance().getInteractions(); + welcome.NtpBackgroundMetricsProxyImpl.getInstance().getInteractions(); chrome.metricsPrivate.recordEnumerationValue( 'FirstRun.NewUserExperience.NtpBackgroundInteraction', ntpInteractions.BackgroundImageFailedToLoad, @@ -78,7 +78,7 @@ /** @override */ recordBackgroundImageNeverLoaded() { const ntpInteractions = - nux.NtpBackgroundMetricsProxyImpl.getInstance().getInteractions(); + welcome.NtpBackgroundMetricsProxyImpl.getInstance().getInteractions(); chrome.metricsPrivate.recordEnumerationValue( 'FirstRun.NewUserExperience.NtpBackgroundInteraction', ntpInteractions.BackgroundImageNeverLoaded,
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/nux_ntp_background.js b/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/nux_ntp_background.js index 99e37a65..1af8a41 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/nux_ntp_background.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/ntp_background/nux_ntp_background.js
@@ -13,17 +13,17 @@ ], properties: { - /** @type {nux.stepIndicatorModel} */ + /** @type {welcome.stepIndicatorModel} */ indicatorModel: Object, - /** @private {?nux.NtpBackgroundData} */ + /** @private {?welcome.NtpBackgroundData} */ selectedBackground_: { observer: 'onSelectedBackgroundChange_', type: Object, }, }, - /** @private {?Array<!nux.NtpBackgroundData>} */ + /** @private {?Array<!welcome.NtpBackgroundData>} */ backgrounds_: null, /** @private */ @@ -32,17 +32,17 @@ /** @private {boolean} */ imageIsLoading_: false, - /** @private {?nux.ModuleMetricsManager} */ + /** @private {?welcome.ModuleMetricsManager} */ metricsManager_: null, - /** @private {?nux.NtpBackgroundProxy} */ + /** @private {?welcome.NtpBackgroundProxy} */ ntpBackgroundProxy_: null, /** @override */ ready: function() { - this.ntpBackgroundProxy_ = nux.NtpBackgroundProxyImpl.getInstance(); - this.metricsManager_ = new nux.ModuleMetricsManager( - nux.NtpBackgroundMetricsProxyImpl.getInstance()); + this.ntpBackgroundProxy_ = welcome.NtpBackgroundProxyImpl.getInstance(); + this.metricsManager_ = new welcome.ModuleMetricsManager( + welcome.NtpBackgroundMetricsProxyImpl.getInstance()); }, onRouteEnter: function() { @@ -98,7 +98,7 @@ }, /** - * @param {!nux.NtpBackgroundData} background + * @param {!welcome.NtpBackgroundData} background * @private */ isSelectedBackground_: function(background) { @@ -144,7 +144,7 @@ }, /** - * @param {!{model: !{item: !nux.NtpBackgroundData}}} e + * @param {!{model: !{item: !welcome.NtpBackgroundData}}} e * @private */ onBackgroundClick_: function(e) {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js index 6f0477b..37e69a2d 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.js
@@ -11,7 +11,7 @@ ], properties: { - /** @type {nux.stepIndicatorModel} */ + /** @type {welcome.stepIndicatorModel} */ indicatorModel: Object, // <if expr="is_win"> @@ -22,7 +22,7 @@ // </if> }, - /** @private {nux.NuxSetAsDefaultProxy} */ + /** @private {welcome.NuxSetAsDefaultProxy} */ browserProxy_: null, /** @private {boolean} */ @@ -30,7 +30,7 @@ /** @override */ ready: function() { - this.browserProxy_ = nux.NuxSetAsDefaultProxyImpl.getInstance(); + this.browserProxy_ = welcome.NuxSetAsDefaultProxyImpl.getInstance(); this.addWebUIListener( 'browser-default-state-changed', @@ -80,7 +80,7 @@ /** * Automatically navigate to the next onboarding step once default changed. - * @param {!nux.DefaultBrowserInfo} status + * @param {!welcome.DefaultBrowserInfo} status * @private */ onDefaultBrowserChange_: function(status) {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default_proxy.js b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default_proxy.js index 1fe1cec..e7668ff 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default_proxy.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define('nux', function() { +cr.define('welcome', function() { const NUX_SET_AS_DEFAULT_INTERACTION_METRIC_NAME = 'FirstRun.NewUserExperience.SetAsDefaultInteraction'; @@ -26,7 +26,7 @@ /** @interface */ class NuxSetAsDefaultProxy { - /** @return {!Promise<!nux.DefaultBrowserInfo>} */ + /** @return {!Promise<!welcome.DefaultBrowserInfo>} */ requestDefaultBrowserState() {} setAsDefault() {} recordPageShown() {} @@ -37,7 +37,7 @@ recordSuccessfullySetDefault() {} } - /** @implements {nux.NuxSetAsDefaultProxy} */ + /** @implements {welcome.NuxSetAsDefaultProxy} */ class NuxSetAsDefaultProxyImpl { /** @override */ requestDefaultBrowserState() {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/shared/bookmark_proxy.js b/chrome/browser/resources/welcome/onboarding_welcome/shared/bookmark_proxy.js index d7a4da7..42bf8060 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/shared/bookmark_proxy.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/shared/bookmark_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define('nux', function() { +cr.define('welcome', function() { /** * @typedef {{ * parentId: string, @@ -30,7 +30,7 @@ isBookmarkBarShown() {} } - /** @implements {nux.BookmarkProxy} */ + /** @implements {welcome.BookmarkProxy} */ class BookmarkProxyImpl { /** @override */ addBookmark(data, callback) { @@ -58,7 +58,7 @@ // Wrapper for bookmark proxy to keep some additional states. class BookmarkBarManager { constructor() { - /** @private {nux.BookmarkProxy} */ + /** @private {welcome.BookmarkProxy} */ this.proxy_ = BookmarkProxyImpl.getInstance(); /** @private {boolean} */
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/shared/module_metrics_proxy.js b/chrome/browser/resources/welcome/onboarding_welcome/shared/module_metrics_proxy.js index 159a187..384ae2ac 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/shared/module_metrics_proxy.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/shared/module_metrics_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define('nux', function() { +cr.define('welcome', function() { /** @interface */ class ModuleMetricsProxy { recordPageShown() {} @@ -28,7 +28,7 @@ recordNavigatedAwayThroughBrowserHistory() {} } - /** @implements {nux.ModuleMetricsProxy} */ + /** @implements {welcome.ModuleMetricsProxy} */ class ModuleMetricsProxyImpl { /** * @param {string} histogramName The histogram that will record the module @@ -125,7 +125,7 @@ } class ModuleMetricsManager { - /** @param {nux.ModuleMetricsProxy} metricsProxy */ + /** @param {welcome.ModuleMetricsProxy} metricsProxy */ constructor(metricsProxy) { this.metricsProxy_ = metricsProxy; @@ -196,7 +196,8 @@ }; }); -nux.GoogleAppsMetricsProxyImpl = class extends nux.ModuleMetricsProxyImpl { +welcome.GoogleAppsMetricsProxyImpl = + class extends welcome.ModuleMetricsProxyImpl { constructor() { /** * NuxGoogleAppsInteractions enum. @@ -227,7 +228,8 @@ } }; -nux.NtpBackgroundMetricsProxyImpl = class extends nux.ModuleMetricsProxyImpl { +welcome.NtpBackgroundMetricsProxyImpl = + class extends welcome.ModuleMetricsProxyImpl { constructor() { /** * NuxNtpBackgroundInteractions enum. @@ -259,5 +261,5 @@ } }; -cr.addSingletonGetter(nux.GoogleAppsMetricsProxyImpl); -cr.addSingletonGetter(nux.NtpBackgroundMetricsProxyImpl); +cr.addSingletonGetter(welcome.GoogleAppsMetricsProxyImpl); +cr.addSingletonGetter(welcome.NtpBackgroundMetricsProxyImpl);
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/shared/nux_types.js b/chrome/browser/resources/welcome/onboarding_welcome/shared/nux_types.js index f022277..accc5c3 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/shared/nux_types.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/shared/nux_types.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.exportPath('nux'); +cr.exportPath('welcome'); /** * @typedef {{ @@ -12,7 +12,7 @@ * url: string, * }} */ -nux.BookmarkListItem; +welcome.BookmarkListItem; /** * @typedef {{ @@ -20,7 +20,7 @@ * active: number, * }} */ -nux.stepIndicatorModel; +welcome.stepIndicatorModel; /** * TODO(hcarmona): somehow reuse from @@ -32,4 +32,4 @@ * isUnknownError: boolean, * }}; */ -nux.DefaultBrowserInfo; \ No newline at end of file +welcome.DefaultBrowserInfo;
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/shared/step_indicator.js b/chrome/browser/resources/welcome/onboarding_welcome/shared/step_indicator.js index 4a0bee3..4af45dc8 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/shared/step_indicator.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/shared/step_indicator.js
@@ -10,7 +10,7 @@ is: 'step-indicator', properties: { - /** @type {nux.stepIndicatorModel} */ + /** @type {welcome.stepIndicatorModel} */ model: Object, /** @private */ @@ -37,4 +37,4 @@ getActiveClass_: function(index) { return index == this.model.active ? 'active' : ''; }, -}); \ No newline at end of file +});
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/signin_view.js b/chrome/browser/resources/welcome/onboarding_welcome/signin_view.js index 6d8532f..15096824 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/signin_view.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/signin_view.js
@@ -13,13 +13,13 @@ /** @private {?welcome.WelcomeBrowserProxy} */ welcomeBrowserProxy_: null, - /** @private {?nux.SigninViewProxy} */ + /** @private {?welcome.SigninViewProxy} */ signinViewProxy_: null, /** @override */ ready: function() { this.welcomeBrowserProxy_ = welcome.WelcomeBrowserProxyImpl.getInstance(); - this.signinViewProxy_ = nux.SigninViewProxyImpl.getInstance(); + this.signinViewProxy_ = welcome.SigninViewProxyImpl.getInstance(); }, onRouteEnter: function() {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/signin_view_proxy.js b/chrome/browser/resources/welcome/onboarding_welcome/signin_view_proxy.js index 0d90282..0e731b9 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/signin_view_proxy.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/signin_view_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define('nux', function() { +cr.define('welcome', function() { const NUX_SIGNIN_VIEW_INTERACTION_METRIC_NAME = 'FirstRun.NewUserExperience.SignInInterstitialInteraction'; @@ -32,7 +32,7 @@ recordSignIn() {} } - /** @implements {nux.SigninViewProxy} */ + /** @implements {welcome.SigninViewProxy} */ class SigninViewProxyImpl { /** @override */ recordPageShown() {
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js b/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js index 0352988..9830c921 100644 --- a/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js +++ b/chrome/browser/resources/welcome/onboarding_welcome/welcome_app.js
@@ -111,7 +111,7 @@ /** @type {!Promise} */ const defaultBrowserPromise = - nux.NuxSetAsDefaultProxyImpl.getInstance() + welcome.NuxSetAsDefaultProxyImpl.getInstance() .requestDefaultBrowserState() .then((status) => { if (status.isDefault || !status.canBeDefault) { @@ -128,7 +128,7 @@ return Promise .all([ defaultBrowserPromise, - nux.BookmarkBarManager.getInstance().initialized, + welcome.BookmarkBarManager.getInstance().initialized, ]) .then(([canSetDefault]) => { modules = modules.filter(module => {
diff --git a/chrome/browser/search/iframe_source.cc b/chrome/browser/search/iframe_source.cc deleted file mode 100644 index 4eab320c..0000000 --- a/chrome/browser/search/iframe_source.cc +++ /dev/null
@@ -1,100 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/search/iframe_source.h" - -#include "base/memory/ref_counted_memory.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "chrome/browser/search/instant_io_context.h" -#include "chrome/common/url_constants.h" -#include "content/public/browser/navigation_entry.h" -#include "content/public/browser/web_contents.h" -#include "ui/base/resource/resource_bundle.h" -#include "url/gurl.h" - -IframeSource::IframeSource() = default; - -IframeSource::~IframeSource() = default; - -std::string IframeSource::GetMimeType(const std::string& path_and_query) { - std::string path(GURL("chrome-search://host/" + path_and_query).path()); - if (base::EndsWith(path, ".js", base::CompareCase::INSENSITIVE_ASCII)) - return "application/javascript"; - if (base::EndsWith(path, ".png", base::CompareCase::INSENSITIVE_ASCII)) - return "image/png"; - if (base::EndsWith(path, ".css", base::CompareCase::INSENSITIVE_ASCII)) - return "text/css"; - if (base::EndsWith(path, ".html", base::CompareCase::INSENSITIVE_ASCII)) - return "text/html"; - if (base::EndsWith(path, ".svg", base::CompareCase::INSENSITIVE_ASCII)) - return "image/svg+xml"; - return std::string(); -} - -bool IframeSource::AllowCaching() { - return false; -} - -bool IframeSource::ShouldServiceRequest( - const GURL& url, - content::ResourceContext* resource_context, - int render_process_id) { - return InstantIOContext::ShouldServiceRequest(url, resource_context, - render_process_id) && - url.SchemeIs(chrome::kChromeSearchScheme) && - url.host_piece() == GetSource() && ServesPath(url.path()); -} - -bool IframeSource::ShouldDenyXFrameOptions() { - return false; -} - -bool IframeSource::GetOrigin( - const content::ResourceRequestInfo::WebContentsGetter& wc_getter, - std::string* origin) const { - if (wc_getter.is_null()) - return false; - content::WebContents* contents = wc_getter.Run(); - if (!contents) - return false; - content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); - if (!entry) - return false; - - *origin = entry->GetURL().GetOrigin().spec(); - // Origin should not include a trailing slash. That is part of the path. - base::TrimString(*origin, "/", origin); - return true; -} - -void IframeSource::SendResource( - int resource_id, - const content::URLDataSource::GotDataCallback& callback, - const ui::TemplateReplacements* replacements) { - base::StringPiece resource = - ui::ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id); - std::string response = - replacements != nullptr - ? ui::ReplaceTemplateExpressions(resource, *replacements) - : resource.as_string(); - callback.Run(base::RefCountedString::TakeString(&response)); -} - -void IframeSource::SendJSWithOrigin( - int resource_id, - const content::ResourceRequestInfo::WebContentsGetter& wc_getter, - const content::URLDataSource::GotDataCallback& callback) { - std::string origin; - if (!GetOrigin(wc_getter, &origin)) { - callback.Run(nullptr); - return; - } - - base::StringPiece template_js = - ui::ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id); - std::string response(template_js.as_string()); - base::ReplaceFirstSubstringAfterOffset(&response, 0, "{{ORIGIN}}", origin); - callback.Run(base::RefCountedString::TakeString(&response)); -}
diff --git a/chrome/browser/search/iframe_source.h b/chrome/browser/search/iframe_source.h deleted file mode 100644 index fca56596..0000000 --- a/chrome/browser/search/iframe_source.h +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SEARCH_IFRAME_SOURCE_H_ -#define CHROME_BROWSER_SEARCH_IFRAME_SOURCE_H_ - -#include "base/macros.h" -#include "build/build_config.h" -#include "content/public/browser/url_data_source.h" -#include "ui/base/template_expressions.h" - -#if defined(OS_ANDROID) -#error "Instant is only used on desktop"; -#endif - -// Base class for URL data sources for chrome-search:// iframed content. -// TODO(crbug.com/947608): This has only one subclass outside of tests, -// MostVisitedIframeSource. Merge the two classes? -class IframeSource : public content::URLDataSource { - public: - IframeSource(); - ~IframeSource() override; - - protected: - // Overridden from content::URLDataSource: - std::string GetMimeType(const std::string& path_and_query) override; - bool AllowCaching() override; - bool ShouldDenyXFrameOptions() override; - bool ShouldServiceRequest(const GURL& url, - content::ResourceContext* resource_context, - int render_process_id) override; - - // Returns whether this source should serve data for a particular path. - virtual bool ServesPath(const std::string& path) const = 0; - - // Sends unmodified resource bytes. - void SendResource(int resource_id, - const content::URLDataSource::GotDataCallback& callback, - const ui::TemplateReplacements* replacements = nullptr); - - // Sends Javascript with an expected postMessage origin interpolated. - void SendJSWithOrigin( - int resource_id, - const content::ResourceRequestInfo::WebContentsGetter& wc_getter, - const content::URLDataSource::GotDataCallback& callback); - - // This is exposed for testing and should not be overridden. - // Sets |origin| to the URL of the WebContents identified by |wc_getter|. - // Returns true if successful and false if not, for example if the WebContents - // does not exist - virtual bool GetOrigin( - const content::ResourceRequestInfo::WebContentsGetter& wc_getter, - std::string* origin) const; - - DISALLOW_COPY_AND_ASSIGN(IframeSource); -}; - -#endif // CHROME_BROWSER_SEARCH_IFRAME_SOURCE_H_
diff --git a/chrome/browser/search/local_files_ntp_source.cc b/chrome/browser/search/local_files_ntp_source.cc deleted file mode 100644 index fc00f42..0000000 --- a/chrome/browser/search/local_files_ntp_source.cc +++ /dev/null
@@ -1,138 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/search/local_files_ntp_source.h" - -#include <memory> - -#if !defined(GOOGLE_CHROME_BUILD) - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/location.h" -#include "base/memory/ref_counted_memory.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/task/post_task.h" -#include "base/threading/thread_restrictions.h" -#include "build/build_config.h" -#include "chrome/common/url_constants.h" -#include "content/public/browser/url_data_source.h" -#include "third_party/re2/src/re2/re2.h" -#include "third_party/re2/src/re2/stringpiece.h" - -namespace { - -const char kBasePath[] = "chrome/browser/resources/local_ntp"; - -// Matches lines of form '<include src="foo">' and captures 'foo'. -// TODO(treib): None of the local NTP files use this. Remove it? -const char kInlineResourceRegex[] = "<include.*?src\\=[\"'](.+?)[\"'].*?>"; - -// TODO(treib): local_ntp.css contains url(...) references to images, which get -// inlined by grit's "flattenhtml" feature during regular builds. Find some way -// to make that work with local files. - -void CallbackWithLoadedResource( - const std::string& origin, - const content::URLDataSource::GotDataCallback& callback, - const std::string& content) { - std::string output = content; - if (!origin.empty()) - base::ReplaceFirstSubstringAfterOffset(&output, 0, "{{ORIGIN}}", origin); - - // Strip out the integrity placeholders. CSP is disabled in local-files mode, - // so the integrity values aren't required. - base::ReplaceFirstSubstringAfterOffset(&output, 0, "{{CONFIG_INTEGRITY}}", - std::string()); - base::ReplaceFirstSubstringAfterOffset(&output, 0, "{{LOCAL_NTP_INTEGRITY}}", - std::string()); - - callback.Run(base::RefCountedString::TakeString(&output)); -} - -// Read a file to a string and return. -std::string ReadFileAndReturn(const base::FilePath& path) { - std::string data; - // This call can fail, but it doesn't matter for our purposes. If it fails, - // we simply return an empty string. - base::ReadFileToString(path, &data); - return data; -} - -} // namespace - -namespace local_ntp { - -void FlattenLocalInclude( - const content::URLDataSource::GotDataCallback& callback, - std::string topLevelResource, - scoped_refptr<base::RefCountedMemory> inlineResource); - -// Helper method invoked by both CheckLocalIncludes and FlattenLocalInclude. -// Checks for any <include> directives; if any are found, loads the associated -// file and calls FlattenLocalInclude with the result. Otherwise, processing -// is done, and so the original callback is invoked. -void CheckLocalIncludesHelper( - const content::URLDataSource::GotDataCallback& callback, - std::string& resource) { - std::string filename; - re2::StringPiece resourceWrapper(resource); - if (re2::RE2::FindAndConsume(&resourceWrapper, kInlineResourceRegex, - &filename)) { - content::URLDataSource::GotDataCallback wrapper = - base::Bind(&FlattenLocalInclude, callback, resource); - SendLocalFileResource(filename, wrapper); - } else { - callback.Run(base::RefCountedString::TakeString(&resource)); - } -} - -// Wrapper around the above helper function for use as a callback. Processes -// local files to inline any files indicated by an <include> directive. -void CheckLocalIncludes(const content::URLDataSource::GotDataCallback& callback, - scoped_refptr<base::RefCountedMemory> resource) { - std::string resourceAsStr(resource->front_as<char>(), resource->size()); - CheckLocalIncludesHelper(callback, resourceAsStr); -} - -// Replaces the first <include> directive found with the given file contents. -// Afterwards, re-invokes CheckLocalIncludesHelper to handle any subsequent -// <include>s, including those which may have been added by the newly-inlined -// resource. -void FlattenLocalInclude( - const content::URLDataSource::GotDataCallback& callback, - std::string topLevelResource, - scoped_refptr<base::RefCountedMemory> inlineResource) { - std::string inlineAsStr(inlineResource->front_as<char>(), - inlineResource->size()); - re2::RE2::Replace(&topLevelResource, kInlineResourceRegex, inlineAsStr); - CheckLocalIncludesHelper(callback, topLevelResource); -} - -void SendLocalFileResource( - const std::string& path, - const content::URLDataSource::GotDataCallback& callback) { - SendLocalFileResourceWithOrigin(path, std::string(), callback); -} - -void SendLocalFileResourceWithOrigin( - const std::string& path, - const std::string& origin, - const content::URLDataSource::GotDataCallback& callback) { - base::FilePath fullpath; - base::PathService::Get(base::DIR_SOURCE_ROOT, &fullpath); - fullpath = fullpath.AppendASCII(kBasePath).AppendASCII(path); - content::URLDataSource::GotDataCallback wrapper = - base::Bind(&CheckLocalIncludes, callback); - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::Bind(&ReadFileAndReturn, fullpath), - base::Bind(&CallbackWithLoadedResource, origin, wrapper)); -} - -} // namespace local_ntp - -#endif // !defined(GOOGLE_CHROME_BUILD)
diff --git a/chrome/browser/search/local_files_ntp_source.h b/chrome/browser/search/local_files_ntp_source.h deleted file mode 100644 index e296597..0000000 --- a/chrome/browser/search/local_files_ntp_source.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SEARCH_LOCAL_FILES_NTP_SOURCE_H_ -#define CHROME_BROWSER_SEARCH_LOCAL_FILES_NTP_SOURCE_H_ - -#include <string> - -#include "build/build_config.h" -#include "content/public/browser/url_data_source.h" - -#if defined(OS_ANDROID) -#error "Instant is only used on desktop"; -#endif - -#if !defined(GOOGLE_CHROME_BUILD) - -namespace local_ntp { - -// Sends the content of |path| to |callback|, reading |path| as a local file. -// This function is only used for dev builds. -void SendLocalFileResource( - const std::string& path, - const content::URLDataSource::GotDataCallback& callback); - -// Sends the content of |path| to |callback|, reading |path| as a local file. -// It also replaces the first occurrence of {{ORIGIN}} with |origin|. -// This function is only used for dev builds. -void SendLocalFileResourceWithOrigin( - const std::string& path, - const std::string& origin, - const content::URLDataSource::GotDataCallback& callback); - -} // namespace local_ntp - -#endif // !defined(GOOGLE_CHROME_BUILD) -#endif // CHROME_BROWSER_SEARCH_LOCAL_FILES_NTP_SOURCE_H_
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc index a1b8659d..d8e2d30 100644 --- a/chrome/browser/search/local_ntp_source.cc +++ b/chrome/browser/search/local_ntp_source.cc
@@ -30,7 +30,6 @@ #include "chrome/browser/search/background/ntp_background_service.h" #include "chrome/browser/search/background/ntp_background_service_factory.h" #include "chrome/browser/search/instant_io_context.h" -#include "chrome/browser/search/local_files_ntp_source.h" #include "chrome/browser/search/local_ntp_js_integrity.h" #include "chrome/browser/search/ntp_features.h" #include "chrome/browser/search/one_google_bar/one_google_bar_data.h" @@ -50,7 +49,6 @@ #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_paths.h" -#include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "chrome/grit/browser_resources.h" @@ -957,19 +955,6 @@ return; } -#if !defined(GOOGLE_CHROME_BUILD) - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kLocalNtpReload)) { - if (stripped_path == "local-ntp.html" || stripped_path == "local-ntp.js" || - stripped_path == "local-ntp.css" || stripped_path == "voice.js" || - stripped_path == "voice.css") { - base::ReplaceChars(stripped_path, "-", "_", &stripped_path); - local_ntp::SendLocalFileResource(stripped_path, callback); - return; - } - } -#endif // !defined(GOOGLE_CHROME_BUILD) - if (stripped_path == kMainHtmlFilename) { if (search_config_provider_->DefaultSearchProviderIsGoogle()) { InitiatePromoAndOGBRequests(); @@ -1112,14 +1097,6 @@ std::string LocalNtpSource::GetContentSecurityPolicy() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); -#if !defined(GOOGLE_CHROME_BUILD) - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kLocalNtpReload)) { - // While live-editing the local NTP files, turn off CSP. - return "script-src * 'unsafe-inline';"; - } -#endif // !defined(GOOGLE_CHROME_BUILD) - GURL google_base_url = google_util::CommandLineGoogleBaseURL(); // Allow embedding of the most visited iframe, as well as the account
diff --git a/chrome/browser/search/most_visited_iframe_source.cc b/chrome/browser/search/most_visited_iframe_source.cc index 5aa8a9c..3b414d0 100644 --- a/chrome/browser/search/most_visited_iframe_source.cc +++ b/chrome/browser/search/most_visited_iframe_source.cc
@@ -7,12 +7,16 @@ #include "base/command_line.h" #include "base/feature_list.h" #include "base/memory/ref_counted_memory.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" #include "build/build_config.h" -#include "chrome/browser/search/local_files_ntp_source.h" +#include "chrome/browser/search/instant_io_context.h" #include "chrome/browser/search/ntp_features.h" -#include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" #include "chrome/grit/local_ntp_resources.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/web_contents.h" +#include "ui/base/resource/resource_bundle.h" #include "url/gurl.h" namespace { @@ -61,24 +65,6 @@ GURL url(chrome::kChromeSearchMostVisitedUrl + path_and_query); std::string path(url.path()); -#if !defined(GOOGLE_CHROME_BUILD) - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kLocalNtpReload)) { - std::string rel_path = "most_visited_" + path.substr(1); - if (path == kSingleJSPath) { - std::string origin; - if (!GetOrigin(wc_getter, &origin)) { - callback.Run(nullptr); - return; - } - local_ntp::SendLocalFileResourceWithOrigin(rel_path, origin, callback); - } else { - local_ntp::SendLocalFileResource(rel_path, callback); - } - return; - } -#endif - if (path == kSingleHTMLPath) { ui::TemplateReplacements replacements; bool disable_fade = base::FeatureList::IsEnabled( @@ -124,6 +110,40 @@ } } +std::string MostVisitedIframeSource::GetMimeType( + const std::string& path_and_query) { + std::string path(GURL("chrome-search://host/" + path_and_query).path()); + if (base::EndsWith(path, ".js", base::CompareCase::INSENSITIVE_ASCII)) + return "application/javascript"; + if (base::EndsWith(path, ".png", base::CompareCase::INSENSITIVE_ASCII)) + return "image/png"; + if (base::EndsWith(path, ".css", base::CompareCase::INSENSITIVE_ASCII)) + return "text/css"; + if (base::EndsWith(path, ".html", base::CompareCase::INSENSITIVE_ASCII)) + return "text/html"; + if (base::EndsWith(path, ".svg", base::CompareCase::INSENSITIVE_ASCII)) + return "image/svg+xml"; + return std::string(); +} + +bool MostVisitedIframeSource::AllowCaching() { + return false; +} + +bool MostVisitedIframeSource::ShouldServiceRequest( + const GURL& url, + content::ResourceContext* resource_context, + int render_process_id) { + return InstantIOContext::ShouldServiceRequest(url, resource_context, + render_process_id) && + url.SchemeIs(chrome::kChromeSearchScheme) && + url.host_piece() == GetSource() && ServesPath(url.path()); +} + +bool MostVisitedIframeSource::ShouldDenyXFrameOptions() { + return false; +} + bool MostVisitedIframeSource::ServesPath(const std::string& path) const { return path == kSingleHTMLPath || path == kSingleCSSPath || path == kSingleJSPath || path == kTitleHTMLPath || @@ -134,3 +154,51 @@ path == kLocalNTPCommonCSSPath || path == kAnimationsCSSPath || path == kAnimationsJSPath || path == kLocalNTPUtilsJSPath; } + +void MostVisitedIframeSource::SendResource( + int resource_id, + const content::URLDataSource::GotDataCallback& callback, + const ui::TemplateReplacements* replacements) { + base::StringPiece resource = + ui::ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id); + std::string response = + replacements != nullptr + ? ui::ReplaceTemplateExpressions(resource, *replacements) + : resource.as_string(); + callback.Run(base::RefCountedString::TakeString(&response)); +} + +void MostVisitedIframeSource::SendJSWithOrigin( + int resource_id, + const content::ResourceRequestInfo::WebContentsGetter& wc_getter, + const content::URLDataSource::GotDataCallback& callback) { + std::string origin; + if (!GetOrigin(wc_getter, &origin)) { + callback.Run(nullptr); + return; + } + + base::StringPiece template_js = + ui::ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id); + std::string response(template_js.as_string()); + base::ReplaceFirstSubstringAfterOffset(&response, 0, "{{ORIGIN}}", origin); + callback.Run(base::RefCountedString::TakeString(&response)); +} + +bool MostVisitedIframeSource::GetOrigin( + const content::ResourceRequestInfo::WebContentsGetter& wc_getter, + std::string* origin) const { + if (wc_getter.is_null()) + return false; + content::WebContents* contents = wc_getter.Run(); + if (!contents) + return false; + content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); + if (!entry) + return false; + + *origin = entry->GetURL().GetOrigin().spec(); + // Origin should not include a trailing slash. That is part of the path. + base::TrimString(*origin, "/", origin); + return true; +}
diff --git a/chrome/browser/search/most_visited_iframe_source.h b/chrome/browser/search/most_visited_iframe_source.h index b5f3f3e..e3a7db40 100644 --- a/chrome/browser/search/most_visited_iframe_source.h +++ b/chrome/browser/search/most_visited_iframe_source.h
@@ -7,7 +7,8 @@ #include "base/macros.h" #include "build/build_config.h" -#include "chrome/browser/search/iframe_source.h" +#include "content/public/browser/url_data_source.h" +#include "ui/base/template_expressions.h" #if defined(OS_ANDROID) #error "Instant is only used on desktop"; @@ -15,23 +16,48 @@ // Serves HTML for displaying suggestions using iframes, e.g. // chrome-search://most-visited/single.html -class MostVisitedIframeSource : public IframeSource { +class MostVisitedIframeSource : public content::URLDataSource { public: MostVisitedIframeSource(); ~MostVisitedIframeSource() override; - // Overridden from IframeSource. Public for testing. + // content::URLDataSource: + std::string GetSource() override; void StartDataRequest( const std::string& path_and_query, const content::ResourceRequestInfo::WebContentsGetter& wc_getter, const content::URLDataSource::GotDataCallback& callback) override; + std::string GetMimeType(const std::string& path_and_query) override; + bool AllowCaching() override; + bool ShouldDenyXFrameOptions() override; + bool ShouldServiceRequest(const GURL& url, + content::ResourceContext* resource_context, + int render_process_id) override; + + protected: + // Returns whether this source should serve data for a particular path. + virtual bool ServesPath(const std::string& path) const; + + // Sends unmodified resource bytes. + void SendResource(int resource_id, + const content::URLDataSource::GotDataCallback& callback, + const ui::TemplateReplacements* replacements = nullptr); + + // Sends Javascript with an expected postMessage origin interpolated. + void SendJSWithOrigin( + int resource_id, + const content::ResourceRequestInfo::WebContentsGetter& wc_getter, + const content::URLDataSource::GotDataCallback& callback); + + // This is exposed for testing and should not be overridden. + // Sets |origin| to the URL of the WebContents identified by |wc_getter|. + // Returns true if successful and false if not, for example if the WebContents + // does not exist + virtual bool GetOrigin( + const content::ResourceRequestInfo::WebContentsGetter& wc_getter, + std::string* origin) const; private: - // Overridden from IframeSource: - std::string GetSource() override; - - bool ServesPath(const std::string& path) const override; - DISALLOW_COPY_AND_ASSIGN(MostVisitedIframeSource); };
diff --git a/chrome/browser/search/iframe_source_unittest.cc b/chrome/browser/search/most_visited_iframe_source_unittest.cc similarity index 85% rename from chrome/browser/search/iframe_source_unittest.cc rename to chrome/browser/search/most_visited_iframe_source_unittest.cc index f3514505..ac23d5c4 100644 --- a/chrome/browser/search/iframe_source_unittest.cc +++ b/chrome/browser/search/most_visited_iframe_source_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/search/iframe_source.h" +#include "chrome/browser/search/most_visited_iframe_source.h" #include <memory> @@ -30,12 +30,12 @@ const char kInstantOrigin[] = "chrome-search://instant"; const int kInvalidRendererPID = 42; -class TestIframeSource : public IframeSource { +class TestMostVisitedIframeSource : public MostVisitedIframeSource { public: - using IframeSource::GetMimeType; - using IframeSource::ShouldServiceRequest; - using IframeSource::SendResource; - using IframeSource::SendJSWithOrigin; + using MostVisitedIframeSource::GetMimeType; + using MostVisitedIframeSource::SendJSWithOrigin; + using MostVisitedIframeSource::SendResource; + using MostVisitedIframeSource::ShouldServiceRequest; void set_origin(std::string origin) { origin_ = origin; } @@ -66,19 +66,18 @@ std::string origin_; }; -class IframeSourceTest : public testing::Test { +class MostVisitedIframeSourceTest : public testing::Test { public: // net::URLRequest wants to be executed with a message loop that has TYPE_IO. // InstantIOContext needs to be created on the UI thread and have everything // else happen on the IO thread. This setup is a hacky way to satisfy all // those constraints. - IframeSourceTest() + MostVisitedIframeSourceTest() : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), instant_io_context_(NULL), - response_(NULL) { - } + response_(NULL) {} - TestIframeSource* source() { return source_.get(); } + TestMostVisitedIframeSource* source() { return source_.get(); } std::string response_string() { if (response_.get()) { @@ -104,8 +103,8 @@ private: void SetUp() override { - source_.reset(new TestIframeSource()); - callback_ = base::Bind(&IframeSourceTest::SaveResponse, + source_ = std::make_unique<TestMostVisitedIframeSource>(); + callback_ = base::Bind(&MostVisitedIframeSourceTest::SaveResponse, base::Unretained(this)); instant_io_context_ = new InstantIOContext; InstantIOContext::SetUserDataOnIO(&resource_context_, instant_io_context_); @@ -125,13 +124,13 @@ net::TestURLRequestContext test_url_request_context_; content::MockResourceContext resource_context_; - std::unique_ptr<TestIframeSource> source_; + std::unique_ptr<TestMostVisitedIframeSource> source_; content::URLDataSource::GotDataCallback callback_; scoped_refptr<InstantIOContext> instant_io_context_; scoped_refptr<base::RefCountedMemory> response_; }; -TEST_F(IframeSourceTest, ShouldServiceRequest) { +TEST_F(MostVisitedIframeSourceTest, ShouldServiceRequest) { source()->set_origin(kNonInstantOrigin); EXPECT_FALSE(ShouldService("http://test/loader.js", kNonInstantRendererPID)); source()->set_origin(kInstantOrigin); @@ -151,7 +150,7 @@ ShouldService("chrome-search://test/valid.js", kInvalidRendererPID)); } -TEST_F(IframeSourceTest, GetMimeType) { +TEST_F(MostVisitedIframeSourceTest, GetMimeType) { // URLDataManagerBackend does not include / in path_and_query. EXPECT_EQ("text/html", source()->GetMimeType("foo.html")); EXPECT_EQ("application/javascript", source()->GetMimeType("foo.js")); @@ -160,12 +159,12 @@ EXPECT_EQ("", source()->GetMimeType("bogus")); } -TEST_F(IframeSourceTest, SendResource) { +TEST_F(MostVisitedIframeSourceTest, SendResource) { SendResource(IDR_MOST_VISITED_TITLE_HTML); EXPECT_FALSE(response_string().empty()); } -TEST_F(IframeSourceTest, SendJSWithOrigin) { +TEST_F(MostVisitedIframeSourceTest, SendJSWithOrigin) { source()->set_origin(kInstantOrigin); SendJSWithOrigin(IDR_MOST_VISITED_TITLE_JS); EXPECT_FALSE(response_string().empty());
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index 69b6b96..961cecf 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/command_line.h" +#include "base/feature_list.h" #include "base/path_service.h" #include "base/syslog_logging.h" #include "base/task/post_task.h" @@ -38,9 +39,13 @@ #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/themes/theme_syncable_service.h" #include "chrome/browser/undo/bookmark_undo_service_factory.h" +#include "chrome/browser/web_applications/web_app_provider.h" +#include "chrome/browser/web_applications/web_app_sync_bridge.h" +#include "chrome/browser/web_applications/web_app_sync_manager.h" #include "chrome/browser/web_data_service_factory.h" #include "chrome/common/buildflags.h" #include "chrome/common/channel_info.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h" @@ -338,6 +343,18 @@ profile_, syncer::APP_SETTINGS), dump_stack, profile_)); } + + // Web Apps sync is disabled by default. + if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions) && + base::FeatureList::IsEnabled(features::kDesktopPWAsUSS) && + web_app::WebAppProvider::Get(profile_)) { + if (!disabled_types.Has(syncer::WEB_APPS)) { + controllers.push_back(std::make_unique<syncer::ModelTypeController>( + syncer::WEB_APPS, + std::make_unique<syncer::ForwardingModelTypeControllerDelegate>( + GetControllerDelegateForModelType(syncer::WEB_APPS).get()))); + } + } #endif // BUILDFLAG(ENABLE_EXTENSIONS) #if !defined(OS_ANDROID) @@ -516,7 +533,19 @@ ->GetSyncBridge() ->change_processor() ->GetControllerDelegate(); - +#if BUILDFLAG(ENABLE_EXTENSIONS) + case syncer::WEB_APPS: { + DCHECK(base::FeatureList::IsEnabled( + features::kDesktopPWAsWithoutExtensions)); + DCHECK(base::FeatureList::IsEnabled(features::kDesktopPWAsUSS)); + auto* provider = web_app::WebAppProvider::Get(profile_); + DCHECK(provider); + return provider->sync_manager() + .bridge() + .change_processor() + ->GetControllerDelegate(); + } +#endif // BUILDFLAG(ENABLE_EXTENSIONS) // We don't exercise this function for certain datatypes, because their // controllers get the delegate elsewhere. case syncer::AUTOFILL:
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc index 5059e39e..ecb45aa 100644 --- a/chrome/browser/sync/profile_sync_service_factory.cc +++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -40,6 +40,7 @@ #include "chrome/browser/sync/user_event_service_factory.h" #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/undo/bookmark_undo_service_factory.h" +#include "chrome/browser/web_applications/web_app_provider_factory.h" #include "chrome/browser/web_data_service_factory.h" #include "chrome/common/buildflags.h" #include "chrome/common/channel_info.h" @@ -161,6 +162,7 @@ DependsOn( extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); DependsOn(extensions::StorageFrontend::GetFactoryInstance()); + DependsOn(web_app::WebAppProviderFactory::GetInstance()); #endif // BUILDFLAG(ENABLE_EXTENSIONS) #if defined(OS_CHROMEOS) DependsOn(chromeos::SyncedPrintersManagerFactory::GetInstance());
diff --git a/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/chrome/browser/sync/profile_sync_service_factory_unittest.cc index fd498da..2cbbd2a 100644 --- a/chrome/browser/sync/profile_sync_service_factory_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -13,6 +13,7 @@ #include "base/task/thread_pool/thread_pool.h" #include "build/build_config.h" #include "chrome/common/buildflags.h" +#include "chrome/common/chrome_features.h" #include "chrome/test/base/testing_profile.h" #include "components/browser_sync/browser_sync_switches.h" #include "components/sync/base/model_type.h" @@ -20,6 +21,7 @@ #include "components/sync/driver/sync_driver_switches.h" #include "components/sync/driver/sync_service.h" #include "content/public/test/test_browser_thread_bundle.h" +#include "extensions/buildflags/buildflags.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_CHROMEOS) @@ -42,27 +44,46 @@ // Returns the collection of default datatypes. std::vector<syncer::ModelType> DefaultDatatypes() { - static_assert(45 == syncer::ModelType::NUM_ENTRIES, + static_assert(46 == syncer::ModelType::NUM_ENTRIES, "When adding a new type, you probably want to add it here as " "well (assuming it is already enabled)."); std::vector<syncer::ModelType> datatypes; - // Desktop types. -#if !defined(OS_ANDROID) + // These preprocessor conditions and their order should be in sync with + // preprocessor conditions in ChromeSyncClient::CreateDataTypeControllers: + + // ChromeSyncClient types. + datatypes.push_back(syncer::SECURITY_EVENTS); + +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + datatypes.push_back(syncer::SUPERVISED_USER_SETTINGS); + datatypes.push_back(syncer::SUPERVISED_USER_WHITELISTS); +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) + +#if BUILDFLAG(ENABLE_EXTENSIONS) datatypes.push_back(syncer::APPS); -#if BUILDFLAG(ENABLE_APP_LIST) - datatypes.push_back(syncer::APP_LIST); -#endif - datatypes.push_back(syncer::APP_SETTINGS); -#if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_CHROMEOS) - datatypes.push_back(syncer::DICTIONARY); -#endif datatypes.push_back(syncer::EXTENSIONS); datatypes.push_back(syncer::EXTENSION_SETTINGS); - datatypes.push_back(syncer::SEARCH_ENGINES); + datatypes.push_back(syncer::APP_SETTINGS); + if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions) && + base::FeatureList::IsEnabled(features::kDesktopPWAsUSS)) { + datatypes.push_back(syncer::WEB_APPS); + } +#endif // BUILDFLAG(ENABLE_EXTENSIONS) + +#if !defined(OS_ANDROID) datatypes.push_back(syncer::THEMES); -#endif // !OS_ANDROID + datatypes.push_back(syncer::SEARCH_ENGINES); +#endif // !defined(OS_ANDROID) + +#if BUILDFLAG(ENABLE_APP_LIST) + datatypes.push_back(syncer::APP_LIST); +#endif // BUILDFLAG(ENABLE_APP_LIST) + +#if defined(OS_LINUX) || defined(OS_WIN) + datatypes.push_back(syncer::DICTIONARY); +#endif #if defined(OS_CHROMEOS) if (arc::IsArcAllowedForProfile(profile())) @@ -88,9 +109,6 @@ datatypes.push_back(syncer::PRIORITY_PREFERENCES); datatypes.push_back(syncer::SESSIONS); datatypes.push_back(syncer::PROXY_TABS); - datatypes.push_back(syncer::SECURITY_EVENTS); - datatypes.push_back(syncer::SUPERVISED_USER_SETTINGS); - datatypes.push_back(syncer::SUPERVISED_USER_WHITELISTS); datatypes.push_back(syncer::TYPED_URLS); datatypes.push_back(syncer::USER_EVENTS); datatypes.push_back(syncer::USER_CONSENTS);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index dbaae23..98c5e5c 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1216,6 +1216,8 @@ "webui/management_ui.h", "webui/management_ui_handler.cc", "webui/management_ui_handler.h", + "webui/management_ui_handler_chromeos.cc", + "webui/management_ui_handler_chromeos.h", "webui/media_router/media_router_internals_ui.cc", "webui/media_router/media_router_internals_ui.h", "webui/media_router/media_router_internals_webui_message_handler.cc", @@ -2818,6 +2820,8 @@ "views/native_file_system/native_file_system_access_icon_view.h", "views/native_file_system/native_file_system_permission_view.cc", "views/native_file_system/native_file_system_permission_view.h", + "views/native_file_system/native_file_system_ui_helpers.cc", + "views/native_file_system/native_file_system_ui_helpers.h", "views/native_file_system/native_file_system_usage_bubble_view.cc", "views/native_file_system/native_file_system_usage_bubble_view.h", "views/omnibox/omnibox_match_cell_view.cc",
diff --git a/chrome/browser/ui/android/passwords/manual_filling_view_android.cc b/chrome/browser/ui/android/passwords/manual_filling_view_android.cc index 329bf916..63bcb79 100644 --- a/chrome/browser/ui/android/passwords/manual_filling_view_android.cc +++ b/chrome/browser/ui/android/passwords/manual_filling_view_android.cc
@@ -157,7 +157,8 @@ for (const UserInfo& user_info : tab_data.user_info_list()) { ScopedJavaLocalRef<jobject> j_user_info = Java_ManualFillingComponentBridge_addUserInfoToAccessorySheetData( - env, java_object_, j_tab_data); + env, java_object_, j_tab_data, + ConvertUTF8ToJavaString(env, user_info.origin())); for (const UserInfo::Field& field : user_info.fields()) { Java_ManualFillingComponentBridge_addFieldToUserInfo( env, java_object_, j_user_info,
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc index f45f664..cc21f765 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -313,6 +313,7 @@ base::CommandLine::ForCurrentProcess(), base::FilePath(), false); extension_service_->Init(); + bool flush_app_service_mojo_calls = false; if (app_service_proxy_connector_) { DCHECK(profile()); app_service_proxy_impl_.reset(apps::AppServiceProxyImpl::CreateForTesting( @@ -320,11 +321,17 @@ old_app_service_proxy_for_testing_ = AppServiceAppModelBuilder::SetAppServiceProxyForTesting( app_service_proxy_impl_.get()); + // Flush the App Service Mojo calls, but only after calling + // arc_test_.SetUp, as it also pumps the run-loop in general. + flush_app_service_mojo_calls = true; } if (auto_start_arc_test_) arc_test_.SetUp(profile()); + if (flush_app_service_mojo_calls) + app_service_proxy_impl_->FlushMojoCallsForTesting(); + // Wait until |extension_system| is signaled as started. base::RunLoop run_loop; extension_system->ready().Post(FROM_HERE, run_loop.QuitClosure()); @@ -1323,6 +1330,8 @@ EXPECT_EQ("App2, Fake App 1, Chrome, App1, Fake App 0, Gmail", GetPinnedAppStatus()); + if (app_service_proxy_impl_) + app_service_proxy_impl_->FlushMojoCallsForTesting(); copy_sync_list = app_list_syncable_service_->GetAllSyncData(syncer::APP_LIST); ResetLauncherController();
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index b08b03ac..a9da630 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -1715,6 +1715,9 @@ ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(protocol, url); + if (!handler.IsValid()) + return; + ProtocolHandlerRegistry* registry = ProtocolHandlerRegistryFactory::GetForBrowserContext(context); if (registry->SilentlyHandleRegisterHandlerRequest(handler))
diff --git a/chrome/browser/ui/browser_ui_prefs.cc b/chrome/browser/ui/browser_ui_prefs.cc index 6d26c7f..7da71a9 100644 --- a/chrome/browser/ui/browser_ui_prefs.cc +++ b/chrome/browser/ui/browser_ui_prefs.cc
@@ -125,4 +125,9 @@ false); registry->RegisterBooleanPref(prefs::kAllowPopupsDuringPageUnload, false); registry->RegisterBooleanPref(prefs::kUserFeedbackAllowed, true); + +#if !defined(OS_ANDROID) + registry->RegisterBooleanPref(prefs::kShowFirstRunDefaultSearchShortcut, + false); +#endif // !defined(OS_ANDROID) }
diff --git a/chrome/browser/ui/search/local_ntp_browsertest.cc b/chrome/browser/ui/search/local_ntp_browsertest.cc index 1ca8e97..aeafb15 100644 --- a/chrome/browser/ui/search/local_ntp_browsertest.cc +++ b/chrome/browser/ui/search/local_ntp_browsertest.cc
@@ -1163,6 +1163,17 @@ } }; +IN_PROC_BROWSER_TEST_F(LocalNTPFRESearchShortcutTest, PRE_SearchShortcutShown) { + content::WebContents* active_tab = + local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank")); + local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser()); + ASSERT_TRUE(search::IsInstantNTP(active_tab)); + + content::RenderFrameHost* iframe = GetIframe(active_tab, kMostVisitedIframe); + + EXPECT_TRUE(ContainsDefaultSearchTile(iframe)); +} + IN_PROC_BROWSER_TEST_F(LocalNTPFRESearchShortcutTest, SearchShortcutShown) { content::WebContents* active_tab = local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank")); @@ -1171,6 +1182,7 @@ content::RenderFrameHost* iframe = GetIframe(active_tab, kMostVisitedIframe); + // Search shortcut is retained across browser restart EXPECT_TRUE(ContainsDefaultSearchTile(iframe)); } @@ -1213,7 +1225,7 @@ } IN_PROC_BROWSER_TEST_F(LocalNTPExistingProfileSearchShortcutTest, - FRESearchShortcutNotAddedForExistingUsers) { + PRE_FRESearchShortcutNotAddedForExistingUsers) { TestInstantServiceObserver observer( InstantServiceFactory::GetForProfile(browser()->profile())); @@ -1234,16 +1246,24 @@ base::test::ScopedFeatureList scoped_feature_list_; scoped_feature_list_.InitAndEnableFeature( features::kFirstRunDefaultSearchShortcut); - ASSERT_TRUE( - base::FeatureList::IsEnabled(features::kFirstRunDefaultSearchShortcut)); +} - // One new tiles (the non-NTP URL) should be added. +IN_PROC_BROWSER_TEST_F(LocalNTPExistingProfileSearchShortcutTest, + FRESearchShortcutNotAddedForExistingUsers) { + TestInstantServiceObserver observer( + InstantServiceFactory::GetForProfile(browser()->profile())); + + // One new tile (the non-NTP URL "/title2.html") should be added. observer.WaitForMostVisitedItems(kDefaultMostVisitedItemCount + 1); - active_tab = local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank")); + content::WebContents* active_tab = + local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank")); local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser()); ASSERT_TRUE(search::IsInstantNTP(active_tab)); - iframe = GetIframe(active_tab, kMostVisitedIframe); + + content::RenderFrameHost* iframe = GetIframe(active_tab, kMostVisitedIframe); + + // Search shortcut is not added after browser restart EXPECT_FALSE(ContainsDefaultSearchTile(iframe)); } #endif
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.cc b/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.cc index 20323174..e542dba 100644 --- a/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.cc +++ b/chrome/browser/ui/views/native_file_system/native_file_system_permission_view.cc
@@ -8,16 +8,15 @@ #include "chrome/browser/permissions/permission_util.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/chrome_typography.h" +#include "chrome/browser/ui/views/native_file_system/native_file_system_ui_helpers.h" #include "chrome/grit/generated_resources.h" #include "components/constrained_window/constrained_window_views.h" -#include "components/url_formatter/elide_url.h" #include "components/vector_icons/vector_icons.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/paint_vector_icon.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/label.h" -#include "ui/views/controls/styled_label.h" #include "ui/views/layout/box_layout.h" #include "ui/views/window/dialog_client_view.h" @@ -33,26 +32,10 @@ provider->GetDialogInsetsForContentType(views::TEXT, views::TEXT), provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL))); - base::string16 formatted_origin = - url_formatter::FormatOriginForSecurityDisplay( - origin, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC); - size_t offset; - auto label = std::make_unique<views::StyledLabel>( - l10n_util::GetStringFUTF16( - is_directory ? IDS_NATIVE_FILE_SYSTEM_WRITE_PERMISSION_DIRECTORY_TEXT - : IDS_NATIVE_FILE_SYSTEM_WRITE_PERMISSION_FILE_TEXT, - formatted_origin, &offset), - nullptr); - label->SetTextContext(CONTEXT_BODY_TEXT_SMALL); - label->SetDefaultTextStyle(STYLE_SECONDARY); - label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - - views::StyledLabel::RangeStyleInfo origin_style; - origin_style.text_style = STYLE_EMPHASIZED_SECONDARY; - label->AddStyleRange(gfx::Range(offset, offset + formatted_origin.length()), - origin_style); - - AddChildView(std::move(label)); + AddChildView(native_file_system_ui_helper::CreateOriginLabel( + is_directory ? IDS_NATIVE_FILE_SYSTEM_WRITE_PERMISSION_DIRECTORY_TEXT + : IDS_NATIVE_FILE_SYSTEM_WRITE_PERMISSION_FILE_TEXT, + origin, CONTEXT_BODY_TEXT_SMALL)); auto file_label_container = std::make_unique<views::View>(); int indent =
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_ui_helpers.cc b/chrome/browser/ui/views/native_file_system/native_file_system_ui_helpers.cc new file mode 100644 index 0000000..9ec7722d --- /dev/null +++ b/chrome/browser/ui/views/native_file_system/native_file_system_ui_helpers.cc
@@ -0,0 +1,35 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/native_file_system/native_file_system_ui_helpers.h" + +#include "chrome/browser/ui/views/chrome_typography.h" +#include "components/url_formatter/elide_url.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/controls/styled_label.h" + +namespace native_file_system_ui_helper { + +std::unique_ptr<views::View> CreateOriginLabel(int message_id, + const url::Origin& origin, + int text_context) { + base::string16 formatted_origin = + url_formatter::FormatOriginForSecurityDisplay( + origin, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC); + size_t offset; + auto label = std::make_unique<views::StyledLabel>( + l10n_util::GetStringFUTF16(message_id, formatted_origin, &offset), + nullptr); + label->SetTextContext(text_context); + label->SetDefaultTextStyle(STYLE_SECONDARY); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + + views::StyledLabel::RangeStyleInfo origin_style; + origin_style.text_style = STYLE_EMPHASIZED_SECONDARY; + label->AddStyleRange(gfx::Range(offset, offset + formatted_origin.length()), + origin_style); + return label; +} + +} // namespace native_file_system_ui_helper
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_ui_helpers.h b/chrome/browser/ui/views/native_file_system/native_file_system_ui_helpers.h new file mode 100644 index 0000000..ee726c1 --- /dev/null +++ b/chrome/browser/ui/views/native_file_system/native_file_system_ui_helpers.h
@@ -0,0 +1,28 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_UI_HELPERS_H_ +#define CHROME_BROWSER_UI_VIEWS_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_UI_HELPERS_H_ + +#include <memory> + +namespace url { +class Origin; +} + +namespace views { +class View; +} + +namespace native_file_system_ui_helper { + +// Creates and returns a label where the place holder is replaced with |origin|, +// while formatting the origin as emphasized text. +std::unique_ptr<views::View> CreateOriginLabel(int message_id, + const url::Origin& origin, + int text_context); + +} // namespace native_file_system_ui_helper + +#endif // CHROME_BROWSER_UI_VIEWS_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_UI_HELPERS_H_
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_usage_bubble_view.cc b/chrome/browser/ui/views/native_file_system/native_file_system_usage_bubble_view.cc index 014e9e6..d699c73 100644 --- a/chrome/browser/ui/views/native_file_system/native_file_system_usage_bubble_view.cc +++ b/chrome/browser/ui/views/native_file_system/native_file_system_usage_bubble_view.cc
@@ -13,16 +13,15 @@ #include "chrome/browser/ui/views/chrome_typography.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/toolbar_button_provider.h" +#include "chrome/browser/ui/views/native_file_system/native_file_system_ui_helpers.h" #include "chrome/browser/ui/views/page_action/omnibox_page_action_icon_container_view.h" #include "chrome/grit/generated_resources.h" #include "components/strings/grit/components_strings.h" -#include "components/url_formatter/elide_url.h" #include "third_party/icu/source/common/unicode/unistr.h" #include "third_party/icu/source/common/unicode/utypes.h" #include "third_party/icu/source/i18n/unicode/listformatter.h" #include "ui/base/l10n/l10n_util.h" #include "ui/views/controls/label.h" -#include "ui/views/controls/styled_label.h" #include "ui/views/layout/box_layout.h" namespace { @@ -48,6 +47,42 @@ return base::i18n::UnicodeStringToString16(formatted); } +// Returns the message Id to use as heading text, depending on what types of +// usage are present (i.e. just writable files, or also readable directories, +// etc). +// |need_lifetime_text_at_end| is set to false iff the returned message Id +// already includes an explanation for how long a website will have access to +// the listed paths. It is set to true iff a separate label is needed at the end +// of the dialog to explain lifetime. +int ComputeHeadingMessageFromUsage( + const NativeFileSystemUsageBubbleView::Usage& usage, + bool* need_lifetime_text_at_end) { + if (!usage.writable_files.empty() && !usage.writable_directories.empty()) { + *need_lifetime_text_at_end = true; + return IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_AND_DIRECTORIES_TEXT; + } + if (!usage.writable_files.empty()) { + if (usage.readable_directories.empty()) { + *need_lifetime_text_at_end = false; + return IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_TEXT; + } + *need_lifetime_text_at_end = true; + return IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_NO_LIFETIME_TEXT; + } + if (!usage.writable_directories.empty()) { + if (usage.readable_directories.empty()) { + *need_lifetime_text_at_end = false; + return IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_DIRECTORIES_TEXT; + } + *need_lifetime_text_at_end = true; + return IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_DIRECTORIES_NO_LIFETIME_TEXT; + } + + DCHECK(!usage.readable_directories.empty()); + *need_lifetime_text_at_end = false; + return IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_READABLE_DIRECTORIES_TEXT; +} + } // namespace NativeFileSystemUsageBubbleView::Usage::Usage() = default; @@ -156,15 +191,44 @@ views::DISTANCE_DIALOG_CONTENT_MARGIN_BOTTOM_CONTROL), 0)); - AddPathList(IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_FILES_TEXT, - IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_FILES_TEXT, + bool need_lifetime_text_at_end = false; + int heading_message_id = + ComputeHeadingMessageFromUsage(usage_, &need_lifetime_text_at_end); + + AddChildView(native_file_system_ui_helper::CreateOriginLabel( + heading_message_id, origin_, CONTEXT_BODY_TEXT_LARGE)); + + AddPathList(IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_FILES_TEXT, usage_.writable_files); - AddPathList(IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_WRITABLE_DIRECTORIES_TEXT, - IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_DIRECTORIES_TEXT, + AddPathList(IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_DIRECTORIES_TEXT, usage_.writable_directories); - AddPathList(IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_READABLE_DIRECTORIES_TEXT, - IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_DIRECTORIES_TEXT, + + // If the header wasn't already the "readable directories" header (i.e. we + // had at least one writable file or directory as well) add a secondary header + // for the readable directories section. + if (heading_message_id != + IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_READABLE_DIRECTORIES_TEXT) { + auto directory_label = std::make_unique<views::Label>( + l10n_util::GetStringUTF16( + IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_ALSO_READABLE_DIRECTORIES_TEXT), + CONTEXT_BODY_TEXT_LARGE, STYLE_SECONDARY); + directory_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + directory_label->SetMultiLine(true); + AddChildView(std::move(directory_label)); + } + + AddPathList(IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_DIRECTORIES_TEXT, usage_.readable_directories); + + if (need_lifetime_text_at_end) { + auto lifetime_label = std::make_unique<views::Label>( + l10n_util::GetStringUTF16( + IDS_NATIVE_FILE_SYSTEM_USAGE_BUBBLE_LIFETIME_TEXT), + CONTEXT_BODY_TEXT_LARGE, STYLE_SECONDARY); + lifetime_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + lifetime_label->SetMultiLine(true); + AddChildView(std::move(lifetime_label)); + } } void NativeFileSystemUsageBubbleView::WindowClosing() { @@ -189,30 +253,11 @@ } void NativeFileSystemUsageBubbleView::AddPathList( - int caption_message_id, int details_message_id, const std::vector<base::FilePath>& paths) { if (paths.empty()) return; - base::string16 formatted_origin = - url_formatter::FormatOriginForSecurityDisplay( - origin_, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC); - size_t offset; - auto label = std::make_unique<views::StyledLabel>( - l10n_util::GetStringFUTF16(caption_message_id, formatted_origin, &offset), - nullptr); - label->SetTextContext(CONTEXT_BODY_TEXT_LARGE); - label->SetDefaultTextStyle(STYLE_SECONDARY); - label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - - views::StyledLabel::RangeStyleInfo origin_style; - origin_style.text_style = STYLE_EMPHASIZED_SECONDARY; - label->AddStyleRange(gfx::Range(offset, offset + formatted_origin.length()), - origin_style); - - AddChildView(std::move(label)); - std::vector<base::string16> base_names; for (const auto& path : paths) base_names.push_back(path.BaseName().LossyDisplayName());
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_usage_bubble_view.h b/chrome/browser/ui/views/native_file_system/native_file_system_usage_bubble_view.h index c977915..5fea45729 100644 --- a/chrome/browser/ui/views/native_file_system/native_file_system_usage_bubble_view.h +++ b/chrome/browser/ui/views/native_file_system/native_file_system_usage_bubble_view.h
@@ -51,8 +51,7 @@ void CloseBubble() override; gfx::Size CalculatePreferredSize() const override; - void AddPathList(int caption_message_id, - int details_message_id, + void AddPathList(int details_message_id, const std::vector<base::FilePath>& paths); // Singleton instance of the bubble. The bubble can only be shown on the
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc index 75ff54b..4b6b59b 100644 --- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
@@ -203,7 +203,7 @@ RecordAssistantOptInStatus(VOICE_MATCH_ENROLLMENT_ERROR); CallJS("login.AssistantOptInFlowScreen.onVoiceMatchUpdate", base::Value("failure")); - LOG(ERROR) << "Speaker ID enrollmend failure."; + LOG(ERROR) << "Speaker ID enrollment failure."; } void AssistantOptInFlowScreenHandler::SetupAssistantConnection() {
diff --git a/chrome/browser/ui/webui/chromeos/network_ui.cc b/chrome/browser/ui/webui/chromeos/network_ui.cc index bb71ffd..4c767fef 100644 --- a/chrome/browser/ui/webui/chromeos/network_ui.cc +++ b/chrome/browser/ui/webui/chromeos/network_ui.cc
@@ -48,6 +48,7 @@ constexpr char kOpenCellularActivationUi[] = "openCellularActivationUi"; constexpr char kShowNetworkDetails[] = "showNetworkDetails"; constexpr char kShowNetworkConfig[] = "showNetworkConfig"; +constexpr char kShowAddNewWifiNetworkDialog[] = "showAddNewWifi"; bool GetServicePathFromGuid(const std::string& guid, std::string* service_path) { @@ -119,6 +120,10 @@ kShowNetworkConfig, base::BindRepeating(&NetworkConfigMessageHandler::ShowNetworkConfig, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + kShowAddNewWifiNetworkDialog, + base::BindRepeating(&NetworkConfigMessageHandler::ShowAddNewWifi, + base::Unretained(this))); } private: @@ -220,6 +225,10 @@ InternetConfigDialog::ShowDialogForNetworkId(guid); } + void ShowAddNewWifi(const base::ListValue* arg_list) { + InternetConfigDialog::ShowDialogForNetworkType(::onc::network_type::kWiFi); + } + void GetShillDevicePropertiesSuccess( const std::string& device_path, const base::DictionaryValue& dictionary) { @@ -329,6 +338,13 @@ localized_strings->SetString( "noCellularErrorText", l10n_util::GetStringUTF16(IDS_NETWORK_UI_NO_CELLULAR_ERROR_TEXT)); + + localized_strings->SetString( + "addNewWifiLabel", + l10n_util::GetStringUTF16(IDS_NETWORK_UI_ADD_NEW_WIFI_LABEL)); + localized_strings->SetString( + "addNewWifiButtonText", + l10n_util::GetStringUTF16(IDS_NETWORK_UI_ADD_NEW_WIFI_BUTTON_TEXT)); } NetworkUI::NetworkUI(content::WebUI* web_ui)
diff --git a/chrome/browser/ui/webui/management_ui_handler.cc b/chrome/browser/ui/webui/management_ui_handler.cc index 7229fe4..f495672 100644 --- a/chrome/browser/ui/webui/management_ui_handler.cc +++ b/chrome/browser/ui/webui/management_ui_handler.cc
@@ -44,6 +44,7 @@ #include "chrome/browser/chromeos/policy/status_uploader.h" #include "chrome/browser/chromeos/policy/system_log_uploader.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/ui/webui/management_ui_handler_chromeos.h" #include "chrome/grit/chromium_strings.h" #include "components/prefs/pref_service.h" #include "components/user_manager/user_manager.h" @@ -568,29 +569,8 @@ g_browser_process->platform_part()->browser_policy_connector_chromeos(); const auto url = connector->GetCustomerLogoURL(); if (!url.empty() && GURL(url) != logo_url_) { - net::NetworkTrafficAnnotationTag traffic_annotation = - net::DefineNetworkTrafficAnnotation("management_ui_customer_logo", R"( - semantics { - sender: "Management UI Handler" - description: - "Download organization logo for visualization on the " - "chrome://management page." - trigger: - "The user managed by organization that provides a company logo " - "in their GSuites account loads the chrome://management page." - data: - "Organization uploaded image URL." - destination: GOOGLE_OWNED_SERVICE - } - policy { - cookies_allowed: NO - setting: - "This feature cannot be disabled by settings, but it is only " - "triggered by a user action." - policy_exception_justification: "Not implemented." - })"); - icon_fetcher_ = - std::make_unique<BitmapFetcher>(GURL(url), this, traffic_annotation); + icon_fetcher_ = std::make_unique<BitmapFetcher>( + GURL(url), this, GetManagementUICustomerLogoAnnotation()); icon_fetcher_->Init( std::string(), net::URLRequest::NEVER_CLEAR_REFERRER, net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES);
diff --git a/chrome/browser/ui/webui/management_ui_handler_chromeos.cc b/chrome/browser/ui/webui/management_ui_handler_chromeos.cc new file mode 100644 index 0000000..2702f50 --- /dev/null +++ b/chrome/browser/ui/webui/management_ui_handler_chromeos.cc
@@ -0,0 +1,28 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/webui/management_ui_handler_chromeos.h" + +net::NetworkTrafficAnnotationTag GetManagementUICustomerLogoAnnotation() { + return net::DefineNetworkTrafficAnnotation("management_ui_customer_logo", R"( + semantics { + sender: "Management UI Handler" + description: + "Download organization logo for visualization on the " + "chrome://management page." + trigger: + "The user managed by organization that provides a company logo " + "in their GSuites account loads the chrome://management page." + data: + "Organization uploaded image URL." + destination: GOOGLE_OWNED_SERVICE + } + policy { + cookies_allowed: NO + setting: + "This feature cannot be disabled by settings, but it is only " + "triggered by a user action." + policy_exception_justification: "Not implemented." + })"); +}
diff --git a/chrome/browser/ui/webui/management_ui_handler_chromeos.h b/chrome/browser/ui/webui/management_ui_handler_chromeos.h new file mode 100644 index 0000000..b2deb92 --- /dev/null +++ b/chrome/browser/ui/webui/management_ui_handler_chromeos.h
@@ -0,0 +1,12 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_MANAGEMENT_UI_HANDLER_CHROMEOS_H_ +#define CHROME_BROWSER_UI_WEBUI_MANAGEMENT_UI_HANDLER_CHROMEOS_H_ + +#include "net/traffic_annotation/network_traffic_annotation.h" + +net::NetworkTrafficAnnotationTag GetManagementUICustomerLogoAnnotation(); + +#endif // CHROME_BROWSER_UI_WEBUI_MANAGEMENT_UI_HANDLER_CHROMEOS_H_
diff --git a/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc b/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc index e8e300be2..25814f62 100644 --- a/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.cc
@@ -13,6 +13,7 @@ #include "base/values.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h" +#include "chromeos/audio/cras_audio_handler.h" #include "chromeos/constants/chromeos_switches.h" #include "chromeos/services/assistant/public/mojom/constants.mojom.h" #include "components/arc/arc_prefs.h" @@ -25,13 +26,34 @@ namespace settings { GoogleAssistantHandler::GoogleAssistantHandler(Profile* profile) - : profile_(profile), weak_factory_(this) {} + : profile_(profile), weak_factory_(this) { + chromeos::CrasAudioHandler::Get()->AddAudioObserver(this); +} -GoogleAssistantHandler::~GoogleAssistantHandler() {} +GoogleAssistantHandler::~GoogleAssistantHandler() { + chromeos::CrasAudioHandler::Get()->RemoveAudioObserver(this); +} -void GoogleAssistantHandler::OnJavascriptAllowed() {} +void GoogleAssistantHandler::OnJavascriptAllowed() { + if (pending_hotword_update_) { + OnAudioNodesChanged(); + } +} + void GoogleAssistantHandler::OnJavascriptDisallowed() {} +void GoogleAssistantHandler::OnAudioNodesChanged() { + if (!IsJavascriptAllowed()) { + pending_hotword_update_ = true; + return; + } + + pending_hotword_update_ = false; + FireWebUIListener( + "hotwordDeviceUpdated", + base::Value(chromeos::CrasAudioHandler::Get()->HasHotwordDevice())); +} + void GoogleAssistantHandler::RegisterMessages() { web_ui()->RegisterMessageCallback( "showGoogleAssistantSettings", @@ -46,6 +68,10 @@ "syncVoiceModelStatus", base::BindRepeating(&GoogleAssistantHandler::HandleSyncVoiceModelStatus, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "initializeGoogleAssistantPage", + base::BindRepeating(&GoogleAssistantHandler::HandleInitialized, + base::Unretained(this))); } void GoogleAssistantHandler::HandleShowGoogleAssistantSettings( @@ -71,6 +97,11 @@ settings_manager_->SyncSpeakerIdEnrollmentStatus(); } +void GoogleAssistantHandler::HandleInitialized(const base::ListValue* args) { + CHECK_EQ(0U, args->GetSize()); + AllowJavascript(); +} + void GoogleAssistantHandler::BindAssistantSettingsManager() { DCHECK(!settings_manager_.is_bound());
diff --git a/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h b/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h index 87d09bc..8891f4e 100644 --- a/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h
@@ -6,7 +6,9 @@ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_GOOGLE_ASSISTANT_HANDLER_H_ #include "base/macros.h" +#include "base/optional.h" #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" +#include "chromeos/audio/cras_audio_handler.h" #include "chromeos/services/assistant/public/mojom/settings.mojom.h" #include "mojo/public/cpp/bindings/binding.h" @@ -15,7 +17,8 @@ namespace chromeos { namespace settings { -class GoogleAssistantHandler : public ::settings::SettingsPageUIHandler { +class GoogleAssistantHandler : public ::settings::SettingsPageUIHandler, + chromeos::CrasAudioHandler::AudioObserver { public: explicit GoogleAssistantHandler(Profile* profile); ~GoogleAssistantHandler() override; @@ -24,6 +27,9 @@ void OnJavascriptAllowed() override; void OnJavascriptDisallowed() override; + // chromeos::CrasAudioHandler::AudioObserver overrides + void OnAudioNodesChanged() override; + private: // WebUI call to launch into the Google Assistant app settings. void HandleShowGoogleAssistantSettings(const base::ListValue* args); @@ -31,6 +37,8 @@ void HandleRetrainVoiceModel(const base::ListValue* args); // WebUI call to sync Assistant voice model status. void HandleSyncVoiceModelStatus(const base::ListValue* args); + // WebUI call to signal js side is ready. + void HandleInitialized(const base::ListValue* args); // Bind to assistant settings manager. void BindAssistantSettingsManager(); @@ -39,6 +47,8 @@ assistant::mojom::AssistantSettingsManagerPtr settings_manager_; + bool pending_hotword_update_ = false; + base::WeakPtrFactory<GoogleAssistantHandler> weak_factory_; DISALLOW_COPY_AND_ASSIGN(GoogleAssistantHandler);
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index 70e7bb3..cad27f69 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -34,6 +34,10 @@ "web_app_install_task.h", "web_app_registrar.cc", "web_app_registrar.h", + "web_app_sync_bridge.cc", + "web_app_sync_bridge.h", + "web_app_sync_manager.cc", + "web_app_sync_manager.h", "web_app_tab_helper.cc", "web_app_tab_helper.h", ]
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto index 46d5287..fd87aff 100644 --- a/chrome/browser/web_applications/proto/web_app.proto +++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -8,7 +8,7 @@ package web_app; -// Information about web app icon. +// Local data: Information about web app icon. message WebAppIconInfoProto { // The URL of the app icon. required string url = 1; @@ -17,18 +17,18 @@ } // WebApp class data. -// TODO(loyso): Consider moving this proto to components/sync/protocol/ -// crbug.com/902214. +// This should be a superset for WebAppSpecifics in +// components/sync/protocol/web_app_specifics.proto message WebAppProto { // app_id is the client tag for sync system. required string app_id = 1; - optional string name = 2; - optional string description = 3; - required string launch_url = 4; - optional string scope = 5; - optional uint32 theme_color = 6; + required string launch_url = 2; + required string name = 3; + required uint32 theme_color = 4; // Local data members, not to be synced: + optional string description = 5; + optional string scope = 6; // List of icon infos. repeated WebAppIconInfoProto icons = 7; }
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index 309c22df..69f83bbc 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -39,7 +39,6 @@ } void WebApp::SetIcons(Icons icons) { - DCHECK(!icons.empty()); icons_ = std::move(icons); }
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index 005fe8c..129c04dc 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h
@@ -28,6 +28,7 @@ const std::string& description() const { return description_; } const GURL& launch_url() const { return launch_url_; } const GURL& scope() const { return scope_; } + // TODO(loyso): Remove Optional. This is a required field now. const base::Optional<SkColor>& theme_color() const { return theme_color_; } struct IconInfo {
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc index 7043237..d96d7679 100644 --- a/chrome/browser/web_applications/web_app_database.cc +++ b/chrome/browser/web_applications/web_app_database.cc
@@ -63,14 +63,22 @@ const WebApp& web_app) { auto proto = std::make_unique<WebAppProto>(); + // Required fields: + DCHECK(!web_app.app_id().empty()); proto->set_app_id(web_app.app_id()); - proto->set_name(web_app.name()); - proto->set_description(web_app.description()); + + DCHECK(!web_app.launch_url().is_empty() && web_app.launch_url().is_valid()); proto->set_launch_url(web_app.launch_url().spec()); + + proto->set_name(web_app.name()); + + DCHECK(web_app.theme_color()); + proto->set_theme_color(web_app.theme_color().value()); + + // Optional fields: + proto->set_description(web_app.description()); if (!web_app.scope().is_empty()) proto->set_scope(web_app.scope().spec()); - if (web_app.theme_color()) - proto->set_theme_color(web_app.theme_color().value()); for (const WebApp::IconInfo& icon : web_app.icons()) { WebAppIconInfoProto* icon_proto = proto->add_icons(); @@ -85,43 +93,49 @@ std::unique_ptr<WebApp> WebAppDatabase::CreateWebApp(const WebAppProto& proto) { auto web_app = std::make_unique<WebApp>(proto.app_id()); + // Required fields: GURL launch_url(proto.launch_url()); if (launch_url.is_empty() || !launch_url.is_valid()) { - LOG(ERROR) << "WebApp proto launch_url parse error: " - << launch_url.possibly_invalid_spec(); + DLOG(ERROR) << "WebApp proto launch_url parse error: " + << launch_url.possibly_invalid_spec(); return nullptr; } - web_app->SetLaunchUrl(launch_url); + + if (!proto.has_name()) { + DLOG(ERROR) << "WebApp proto parse error: no name field"; + return nullptr; + } web_app->SetName(proto.name()); - web_app->SetDescription(proto.description()); + + if (!proto.has_theme_color()) { + DLOG(ERROR) << "WebApp proto parse error: no theme_color field"; + return nullptr; + } + web_app->SetThemeColor(proto.theme_color()); + + // Optional fields: + if (proto.has_description()) + web_app->SetDescription(proto.description()); if (proto.has_scope()) { GURL scope(proto.scope()); if (scope.is_empty() || !scope.is_valid()) { - LOG(ERROR) << "WebApp proto scope parse error: " - << scope.possibly_invalid_spec(); + DLOG(ERROR) << "WebApp proto scope parse error: " + << scope.possibly_invalid_spec(); return nullptr; } web_app->SetScope(scope); } - if (proto.has_theme_color()) - web_app->SetThemeColor(proto.theme_color()); - - if (proto.icons_size() == 0) { - LOG(ERROR) << "WebApp proto parse icons error: no icons"; - return nullptr; - } - WebApp::Icons icons; for (int i = 0; i < proto.icons_size(); ++i) { const WebAppIconInfoProto& icon_proto = proto.icons(i); GURL icon_url(icon_proto.url()); if (icon_url.is_empty() || !icon_url.is_valid()) { - LOG(ERROR) << "WebApp IconInfo proto url parse error: " - << icon_url.possibly_invalid_spec(); + DLOG(ERROR) << "WebApp IconInfo proto url parse error: " + << icon_url.possibly_invalid_spec(); return nullptr; } @@ -145,11 +159,8 @@ base::OnceClosure closure) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // For now we use syncer:APPS prefix within local isolated LevelDB, no sync. - // TODO(loyso): Create separate ModelType::WEB_APPS before implementing sync. - // Otherwise it may interfere with existing APPS data. std::move(store_factory) - .Run(syncer::APPS, + .Run(syncer::WEB_APPS, base::BindOnce(&WebAppDatabase::OnStoreCreated, weak_ptr_factory_.GetWeakPtr(), std::move(closure))); } @@ -160,7 +171,7 @@ std::unique_ptr<syncer::ModelTypeStore> store) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (error) { - LOG(ERROR) << "WebApps LevelDB opening error: " << error->ToString(); + DLOG(ERROR) << "WebApps LevelDB opening error: " << error->ToString(); return; } @@ -174,7 +185,7 @@ std::unique_ptr<syncer::ModelTypeStore::RecordList> data_records) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (error) { - LOG(ERROR) << "WebApps LevelDB read error: " << error->ToString(); + DLOG(ERROR) << "WebApps LevelDB read error: " << error->ToString(); return; } @@ -194,7 +205,7 @@ const base::Optional<syncer::ModelError>& error) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (error) - LOG(ERROR) << "WebApps LevelDB write error: " << error->ToString(); + DLOG(ERROR) << "WebApps LevelDB write error: " << error->ToString(); } // static @@ -203,7 +214,7 @@ WebAppProto proto; const bool parsed = proto.ParseFromString(value); if (!parsed || proto.app_id() != app_id) { - LOG(ERROR) << "WebApps LevelDB parse error (unknown)."; + DLOG(ERROR) << "WebApps LevelDB parse error (unknown)."; return nullptr; }
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc index 53de77b..f18b545 100644 --- a/chrome/browser/web_applications/web_app_database_unittest.cc +++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -206,20 +206,18 @@ const auto launch_url = GURL("https://example.com/"); const AppId app_id = GenerateAppIdFromURL(GURL(launch_url)); + const std::string name = "Name"; + const SkColor color = 0xAABBCCDDu; auto app = std::make_unique<WebApp>(app_id); - + // Required fields: app->SetLaunchUrl(launch_url); - EXPECT_TRUE(app->name().empty()); + app->SetName(name); + app->SetThemeColor(base::Optional<SkColor>(color)); + // Let optional fields be empty: EXPECT_TRUE(app->description().empty()); EXPECT_TRUE(app->scope().is_empty()); - EXPECT_FALSE(app->theme_color().has_value()); - - // |icons| is mandatory data member for a representation in DB. If no icons, - // WebAppDatabase::CreateWebApp(from_proto) returns nullptr. - WebApp::Icons icons; - icons.push_back({GURL("https://example.com/icon"), 512}); - app->SetIcons(std::move(icons)); + EXPECT_TRUE(app->icons().empty()); registrar_->RegisterApp(std::move(app)); Registry registry = ReadRegistry(); @@ -227,15 +225,16 @@ std::unique_ptr<WebApp>& app_copy = registry.at(app_id); - // Mandatory members. + // Required fields were serialized: EXPECT_EQ(app_id, app_copy->app_id()); EXPECT_EQ(launch_url, app_copy->launch_url()); + EXPECT_EQ(name, app_copy->name()); + EXPECT_EQ(color, app_copy->theme_color().value()); - // No optional members. - EXPECT_TRUE(app_copy->name().empty()); + // No optional fields. EXPECT_TRUE(app_copy->description().empty()); EXPECT_TRUE(app_copy->scope().is_empty()); - EXPECT_FALSE(app_copy->theme_color().has_value()); + EXPECT_TRUE(app_copy->icons().empty()); } TEST_F(WebAppDatabaseTest, WebAppWithManyIcons) {
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc index 69d29151..c54214d 100644 --- a/chrome/browser/web_applications/web_app_provider.cc +++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -36,6 +36,7 @@ #include "chrome/browser/web_applications/web_app_install_manager.h" #include "chrome/browser/web_applications/web_app_provider_factory.h" #include "chrome/browser/web_applications/web_app_registrar.h" +#include "chrome/browser/web_applications/web_app_sync_manager.h" #include "chrome/browser/web_applications/web_app_tab_helper.h" #include "chrome/common/chrome_features.h" #include "components/pref_registry/pref_registry_syncable.h" @@ -154,6 +155,8 @@ web_app_registrar.get(), icon_manager_.get()); install_manager_ = std::make_unique<WebAppInstallManager>(profile); + sync_manager_ = std::make_unique<WebAppSyncManager>(); + registrar_ = std::move(web_app_registrar); }
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h index b37b815..850d1a0c 100644 --- a/chrome/browser/web_applications/web_app_provider.h +++ b/chrome/browser/web_applications/web_app_provider.h
@@ -44,6 +44,7 @@ class WebAppDatabase; class WebAppDatabaseFactory; class WebAppIconManager; +class WebAppSyncManager; // Forward declarations for legacy extension-based subsystems. class WebAppPolicyManager; @@ -80,6 +81,9 @@ WebAppPolicyManager* policy_manager() override; WebAppUiDelegate& ui_delegate() override; + WebAppDatabaseFactory& database_factory() { return *database_factory_; } + WebAppSyncManager& sync_manager() { return *sync_manager_; } + // KeyedService: void Shutdown() override; @@ -126,6 +130,7 @@ std::unique_ptr<WebAppDatabaseFactory> database_factory_; std::unique_ptr<WebAppDatabase> database_; std::unique_ptr<WebAppIconManager> icon_manager_; + std::unique_ptr<WebAppSyncManager> sync_manager_; WebAppUiDelegate* ui_delegate_ = nullptr; // New generalized subsystems:
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.cc b/chrome/browser/web_applications/web_app_sync_bridge.cc new file mode 100644 index 0000000..b238617 --- /dev/null +++ b/chrome/browser/web_applications/web_app_sync_bridge.cc
@@ -0,0 +1,60 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/web_app_sync_bridge.h" + +#include "base/logging.h" +#include "base/optional.h" +#include "components/sync/model/metadata_change_list.h" + +namespace web_app { + +WebAppSyncBridge::WebAppSyncBridge( + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor) + : syncer::ModelTypeSyncBridge(std::move(change_processor)) {} + +WebAppSyncBridge::~WebAppSyncBridge() = default; + +std::unique_ptr<syncer::MetadataChangeList> +WebAppSyncBridge::CreateMetadataChangeList() { + NOTIMPLEMENTED(); + return nullptr; +} + +base::Optional<syncer::ModelError> WebAppSyncBridge::MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) { + NOTIMPLEMENTED(); + return base::nullopt; +} + +base::Optional<syncer::ModelError> WebAppSyncBridge::ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_changes) { + NOTIMPLEMENTED(); + return base::nullopt; +} + +void WebAppSyncBridge::GetData(StorageKeyList storage_keys, + DataCallback callback) { + NOTIMPLEMENTED(); +} + +void WebAppSyncBridge::GetAllDataForDebugging(DataCallback callback) { + NOTIMPLEMENTED(); +} + +std::string WebAppSyncBridge::GetClientTag( + const syncer::EntityData& entity_data) { + NOTIMPLEMENTED(); + return std::string(); +} + +std::string WebAppSyncBridge::GetStorageKey( + const syncer::EntityData& entity_data) { + NOTIMPLEMENTED(); + return std::string(); +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.h b/chrome/browser/web_applications/web_app_sync_bridge.h new file mode 100644 index 0000000..4306435 --- /dev/null +++ b/chrome/browser/web_applications/web_app_sync_bridge.h
@@ -0,0 +1,46 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_BRIDGE_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_BRIDGE_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/optional.h" +#include "components/sync/model/model_type_sync_bridge.h" + +namespace syncer { +class ModelTypeChangeProcessor; +} + +namespace web_app { + +class WebAppSyncBridge : public syncer::ModelTypeSyncBridge { + public: + explicit WebAppSyncBridge( + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor); + ~WebAppSyncBridge() override; + + // syncer::ModelTypeSyncBridge: + std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList() + override; + base::Optional<syncer::ModelError> MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) override; + base::Optional<syncer::ModelError> ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_changes) override; + void GetData(StorageKeyList storage_keys, DataCallback callback) override; + void GetAllDataForDebugging(DataCallback callback) override; + std::string GetClientTag(const syncer::EntityData& entity_data) override; + std::string GetStorageKey(const syncer::EntityData& entity_data) override; + + private: + DISALLOW_COPY_AND_ASSIGN(WebAppSyncBridge); +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_BRIDGE_H_
diff --git a/chrome/browser/web_applications/web_app_sync_manager.cc b/chrome/browser/web_applications/web_app_sync_manager.cc new file mode 100644 index 0000000..6b82c4a --- /dev/null +++ b/chrome/browser/web_applications/web_app_sync_manager.cc
@@ -0,0 +1,28 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/web_app_sync_manager.h" + +#include "base/bind.h" +#include "chrome/browser/web_applications/web_app_sync_bridge.h" +#include "chrome/common/channel_info.h" +#include "components/sync/base/model_type.h" +#include "components/sync/base/report_unrecoverable_error.h" +#include "components/sync/model_impl/client_tag_based_model_type_processor.h" + +namespace web_app { + +WebAppSyncManager::WebAppSyncManager() { + auto change_processor = + std::make_unique<syncer::ClientTagBasedModelTypeProcessor>( + syncer::WEB_APPS, + base::BindRepeating(&syncer::ReportUnrecoverableError, + chrome::GetChannel())); + + bridge_ = std::make_unique<WebAppSyncBridge>(std::move(change_processor)); +} + +WebAppSyncManager::~WebAppSyncManager() = default; + +} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_sync_manager.h b/chrome/browser/web_applications/web_app_sync_manager.h new file mode 100644 index 0000000..08a1bc04 --- /dev/null +++ b/chrome/browser/web_applications/web_app_sync_manager.h
@@ -0,0 +1,32 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_MANAGER_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_MANAGER_H_ + +#include <memory> + +#include "base/macros.h" + +namespace web_app { + +class WebAppSyncBridge; + +// Exclusively used from the UI thread. +class WebAppSyncManager { + public: + WebAppSyncManager(); + ~WebAppSyncManager(); + + WebAppSyncBridge& bridge() { return *bridge_; } + + private: + std::unique_ptr<WebAppSyncBridge> bridge_; + + DISALLOW_COPY_AND_ASSIGN(WebAppSyncManager); +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_SYNC_MANAGER_H_
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 7fd74d5..fa89d6d2 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -232,6 +232,12 @@ const base::Feature kDesktopPWAsUnifiedInstall{ "DesktopPWAsUnifiedInstall", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enables or disables new Desktop PWAs Unified Sync and Storage (USS) +// implementation that does not use extensions. Requires +// kDesktopPWAsWithoutExtensions to be enabled. +const base::Feature kDesktopPWAsUSS{"DesktopPWAsUSS", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables or disables the ability to install PWAs from the omnibox. const base::Feature kDesktopPWAsOmniboxInstall{ "DesktopPWAsOmniboxInstall", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 289ab87a..b8d830e 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -139,6 +139,9 @@ extern const base::Feature kDesktopPWAsUnifiedInstall; COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kDesktopPWAsUSS; + +COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kDesktopPWAsOmniboxInstall; COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 1a473b18..db9e27ee 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc
@@ -667,12 +667,6 @@ // resulted in a browser startup. const char kWinJumplistAction[] = "win-jumplist-action"; -#if !defined(GOOGLE_CHROME_BUILD) -// Enables a live-reload for local NTP resources. This only works when Chrome -// is running from a Chrome source directory. -const char kLocalNtpReload[] = "local-ntp-reload"; -#endif - #if defined(OS_ANDROID) // Android authentication account type for SPNEGO authentication const char kAuthAndroidNegotiateAccountType[] = "auth-spnego-account-type";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index c7b4ed7..942b698 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h
@@ -193,10 +193,6 @@ extern const char kWinHttpProxyResolver[]; extern const char kWinJumplistAction[]; -#if !defined(GOOGLE_CHROME_BUILD) -extern const char kLocalNtpReload[]; -#endif - #if defined(OS_ANDROID) extern const char kAuthAndroidNegotiateAccountType[]; extern const char kEnableAccessibilityTabSwitcher[];
diff --git a/chrome/common/custom_handlers/protocol_handler.cc b/chrome/common/custom_handlers/protocol_handler.cc index 19649d5..24c0b875 100644 --- a/chrome/common/custom_handlers/protocol_handler.cc +++ b/chrome/common/custom_handlers/protocol_handler.cc
@@ -9,6 +9,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/value_conversions.h" #include "chrome/grit/generated_resources.h" +#include "content/public/common/origin_util.h" #include "net/base/escape.h" #include "ui/base/l10n/l10n_util.h" @@ -34,6 +35,35 @@ return value->HasKey("protocol") && value->HasKey("url"); } +bool ProtocolHandler::IsValid() const { + // TODO(https://crbug.com/977083): Consider limiting to secure contexts. + + // This matches SupportedSchemes() in blink's NavigatorContentUtils. + + // Although not enforced in the spec the spec gives freedom to do additional + // security checks. Bugs have arisen from allowing non-http/https URLs, e.g. + // https://crbug.com/971917 so we check this here. + if (!url_.SchemeIsHTTPOrHTTPS()) { + return false; + } + + // From: + // https://html.spec.whatwg.org/multipage/system-state.html#safelisted-scheme + static constexpr const char* const kProtocolSafelist[] = { + "bitcoin", "geo", "im", "irc", "ircs", "magnet", "mailto", + "mms", "news", "nntp", "openpgp4fpr", "sip", "sms", "smsto", + "ssh", "tel", "urn", "webcal", "wtai", "xmpp"}; + static constexpr const char kWebPrefix[] = "web+"; + + bool has_web_prefix = + base::StartsWith(protocol_, kWebPrefix, + base::CompareCase::INSENSITIVE_ASCII) && + protocol_ != kWebPrefix; + + return has_web_prefix || + base::Contains(kProtocolSafelist, base::ToLowerASCII(protocol_)); +} + bool ProtocolHandler::IsSameOrigin( const ProtocolHandler& handler) const { return handler.url().GetOrigin() == url_.GetOrigin();
diff --git a/chrome/common/custom_handlers/protocol_handler.h b/chrome/common/custom_handlers/protocol_handler.h index 36b56799..d538705 100644 --- a/chrome/common/custom_handlers/protocol_handler.h +++ b/chrome/common/custom_handlers/protocol_handler.h
@@ -34,6 +34,9 @@ // define a ProtocolHandler. static bool IsValidDict(const base::DictionaryValue* value); + // Return true if the protocol handler meets security constraints. + bool IsValid() const; + // Returns true if this handler's url has the same origin as the given one. bool IsSameOrigin(const ProtocolHandler& handler) const;
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 12db442..6e0de1f 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -1409,6 +1409,11 @@ #if !defined(OS_ANDROID) // Whether or not this profile has been shown the Welcome page. const char kHasSeenWelcomePage[] = "browser.has_seen_welcome_page"; + +// A boolean specifying whether the default search shortcut should be shown on +// the New Tab Page after it has been initialized during first run. +const char kShowFirstRunDefaultSearchShortcut[] = + "profile.show_first_run_default_search_shortcut"; #endif #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index a4f7619a..8560cdee 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -462,6 +462,7 @@ #if !defined(OS_ANDROID) extern const char kHasSeenWelcomePage[]; +extern const char kShowFirstRunDefaultSearchShortcut[]; #endif #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
diff --git a/chrome/services/cups_proxy/BUILD.gn b/chrome/services/cups_proxy/BUILD.gn index 031c02a..f163e54 100644 --- a/chrome/services/cups_proxy/BUILD.gn +++ b/chrome/services/cups_proxy/BUILD.gn
@@ -74,6 +74,7 @@ ":test_support", "//base", "//chrome/services/cups_proxy/public/cpp", + "//chrome/services/cups_proxy/public/cpp:unit_tests", "//testing/gtest", ]
diff --git a/chrome/services/cups_proxy/ipp_validator.cc b/chrome/services/cups_proxy/ipp_validator.cc index 18deadd..5485fd75 100644 --- a/chrome/services/cups_proxy/ipp_validator.cc +++ b/chrome/services/cups_proxy/ipp_validator.cc
@@ -18,6 +18,7 @@ #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "chrome/services/cups_proxy/ipp_attribute_validator.h" +#include "chrome/services/cups_proxy/public/cpp/cups_util.h" #include "net/http/http_util.h" #include "printing/backend/cups_ipp_util.h" @@ -95,9 +96,20 @@ return base::nullopt; } - // Ensure endpoint is either default('/') or known printer - auto printer = delegate_->GetPrinter(endpoint.as_string()); - if (endpoint != "/" && !printer) { + // Empty endpoint is allowed. + if (endpoint == "/") { + return HttpRequestLine{method.as_string(), endpoint.as_string(), + http_version.as_string()}; + } + + // Ensure endpoint is a known printer. + auto printer_id = ParseEndpointForPrinterId(endpoint.as_string()); + if (!printer_id.has_value()) { + return base::nullopt; + } + + auto printer = delegate_->GetPrinter(*printer_id); + if (!printer.has_value()) { return base::nullopt; }
diff --git a/chrome/services/cups_proxy/ipp_validator_unittest.cc b/chrome/services/cups_proxy/ipp_validator_unittest.cc index fea795a..76bd154 100644 --- a/chrome/services/cups_proxy/ipp_validator_unittest.cc +++ b/chrome/services/cups_proxy/ipp_validator_unittest.cc
@@ -27,6 +27,10 @@ using Printer = chromeos::Printer; +std::string EncodeEndpointForPrinterId(std::string printer_id) { + return "/printers/" + printer_id; +} + // Fake backend for CupsProxyServiceDelegate. class FakeServiceDelegate : public chromeos::printing::FakeCupsProxyServiceDelegate { @@ -137,7 +141,7 @@ auto request = GetBasicIppRequest(); std::string printer_id = "abc"; - request->endpoint = printer_id; + request->endpoint = EncodeEndpointForPrinterId(printer_id); EXPECT_FALSE(RunValidateIppRequest(request)); // Should succeed now that |delegate_| knows about the printer.
diff --git a/chrome/services/cups_proxy/public/cpp/BUILD.gn b/chrome/services/cups_proxy/public/cpp/BUILD.gn index 0c35dc6..ac042cf 100644 --- a/chrome/services/cups_proxy/public/cpp/BUILD.gn +++ b/chrome/services/cups_proxy/public/cpp/BUILD.gn
@@ -32,6 +32,20 @@ } } +source_set("unit_tests") { + testonly = true + + sources = [ + "cups_util_unittest.cc", + ] + deps = [ + ":cpp", + "//base", + "//testing/gmock", + "//testing/gtest", + ] +} + source_set("manifest") { sources = [ "manifest.cc",
diff --git a/chrome/services/cups_proxy/public/cpp/cups_util.cc b/chrome/services/cups_proxy/public/cpp/cups_util.cc index a7712ce9..11a5959f 100644 --- a/chrome/services/cups_proxy/public/cpp/cups_util.cc +++ b/chrome/services/cups_proxy/public/cpp/cups_util.cc
@@ -35,4 +35,16 @@ return uuid.substr(uuid_start + 1).as_string(); } +base::Optional<std::string> ParseEndpointForPrinterId( + base::StringPiece endpoint) { + size_t last_path = endpoint.find_last_of('/'); + if (last_path == base::StringPiece::npos || + last_path + 1 >= endpoint.size()) { + return base::nullopt; + } + + endpoint.remove_prefix(last_path + 1); + return endpoint.as_string(); +} + } // namespace cups_proxy
diff --git a/chrome/services/cups_proxy/public/cpp/cups_util.h b/chrome/services/cups_proxy/public/cpp/cups_util.h index 55d393f..ffac05b 100644 --- a/chrome/services/cups_proxy/public/cpp/cups_util.h +++ b/chrome/services/cups_proxy/public/cpp/cups_util.h
@@ -23,9 +23,14 @@ // If |ipp| refers to a printer, we return the associated printer_id. // Note: Expects the printer id to be embedded in the resource field of the // 'printer-uri' IPP attribute. -// TODO(crbug.com/945409): Add testing suite. +// TODO(crbug.com/945409): Expand testing suite. base::Optional<std::string> GetPrinterId(ipp_t* ipp); +// Expects |endpoint| to be of the form '/printers/{printer_id}'. +// Returns an empty Optional if parsing fails or yields an empty printer_id. +base::Optional<std::string> ParseEndpointForPrinterId( + base::StringPiece endpoint); + } // namespace cups_proxy #endif // CHROME_SERVICES_CUPS_PROXY_PUBLIC_CPP_CUPS_UTIL_H_
diff --git a/chrome/services/cups_proxy/public/cpp/cups_util_unittest.cc b/chrome/services/cups_proxy/public/cpp/cups_util_unittest.cc new file mode 100644 index 0000000..fe1c384e --- /dev/null +++ b/chrome/services/cups_proxy/public/cpp/cups_util_unittest.cc
@@ -0,0 +1,45 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/services/cups_proxy/public/cpp/cups_util.h" + +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/strings/string_piece.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cups_proxy { +namespace { + +using ::testing::IsEmpty; +using ::testing::Not; + +const char kPrinterIdPrefix[] = "/printers/"; + +// Generated via base::GenerateGUID. +const char kDefaultPrinterId[] = "fd4c5f2e-7549-43d5-b931-9bf4e4f1bf51"; + +TEST(ParseEndpointForPrinterIdTest, SimpleSanityTest) { + base::Optional<std::string> printer_id = ParseEndpointForPrinterId( + std::string(kPrinterIdPrefix) + kDefaultPrinterId); + + EXPECT_TRUE(printer_id.has_value()); + EXPECT_THAT(*printer_id, Not(IsEmpty())); +} + +// PrinterId's must be non-empty. +TEST(ParseEndpointForPrinterIdTest, EmptyPrinterId) { + EXPECT_FALSE(ParseEndpointForPrinterId(kPrinterIdPrefix)); +} + +// Endpoints must contain a '/'. +TEST(ParseEndpointForPrinterIdTest, MissingPathDelimeter) { + EXPECT_FALSE(ParseEndpointForPrinterId(kDefaultPrinterId)); +} + +} // namespace +} // namespace cups_proxy
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index b9fbf43..57af7a48 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3616,10 +3616,10 @@ "../browser/safe_browsing/chrome_cleaner/srt_field_trial_win_unittest.cc", "../browser/search/background/ntp_background_service_unittest.cc", "../browser/search/chrome_colors/chrome_colors_service_unittest.cc", - "../browser/search/iframe_source_unittest.cc", "../browser/search/instant_service_unittest.cc", "../browser/search/instant_unittest_base.cc", "../browser/search/instant_unittest_base.h", + "../browser/search/most_visited_iframe_source_unittest.cc", "../browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc", "../browser/search/one_google_bar/one_google_bar_service_unittest.cc", "../browser/search/promos/promo_service_unittest.cc",
diff --git a/chrome/test/base/browser_with_test_window_test.cc b/chrome/test/base/browser_with_test_window_test.cc index 9e2350a..30f54cd 100644 --- a/chrome/test/base/browser_with_test_window_test.cc +++ b/chrome/test/base/browser_with_test_window_test.cc
@@ -51,7 +51,8 @@ void BrowserWithTestWindowTest::SetUp() { testing::Test::SetUp(); #if defined(OS_CHROMEOS) - ash_test_helper_.SetUp(true); + ash::AshTestHelper::InitParams init_params; + ash_test_helper_.SetUp(init_params); #elif defined(TOOLKIT_VIEWS) views_test_helper_.reset(new views::ScopedViewsTestHelper()); #endif
diff --git a/chrome/test/data/custom_handler_foo.html b/chrome/test/data/custom_handler.html similarity index 100% rename from chrome/test/data/custom_handler_foo.html rename to chrome/test/data/custom_handler.html
diff --git a/chrome/test/data/webui/welcome/app_chooser_test.js b/chrome/test/data/webui/welcome/app_chooser_test.js index 3871ed4..4bd0318 100644 --- a/chrome/test/data/webui/welcome/app_chooser_test.js +++ b/chrome/test/data/webui/welcome/app_chooser_test.js
@@ -37,13 +37,13 @@ }, ]; - /** @type {nux.NuxAppProxy} */ + /** @type {welcome.NuxAppProxy} */ let testAppBrowserProxy; - /** @type {nux.ModuleMetricsProxy} */ + /** @type {welcome.ModuleMetricsProxy} */ let testAppMetricsProxy; - /** @type {nux.BookmarkProxy} */ + /** @type {welcome.BookmarkProxy} */ let testBookmarkBrowserProxy; /** @type {AppChooserElement} */ @@ -54,10 +54,10 @@ testAppMetricsProxy = new TestMetricsProxy(); testBookmarkBrowserProxy = new TestBookmarkProxy(); - nux.GoogleAppProxyImpl.instance_ = testAppBrowserProxy; - nux.GoogleAppsMetricsProxyImpl.instance_ = testAppMetricsProxy; - nux.BookmarkProxyImpl.instance_ = testBookmarkBrowserProxy; - nux.BookmarkBarManager.instance_ = new nux.BookmarkBarManager(); + welcome.GoogleAppProxyImpl.instance_ = testAppBrowserProxy; + welcome.GoogleAppsMetricsProxyImpl.instance_ = testAppMetricsProxy; + welcome.BookmarkProxyImpl.instance_ = testBookmarkBrowserProxy; + welcome.BookmarkBarManager.instance_ = new welcome.BookmarkBarManager(); testAppBrowserProxy.setAppList(apps);
diff --git a/chrome/test/data/webui/welcome/module_metrics_test.js b/chrome/test/data/webui/welcome/module_metrics_test.js index 9ca564b8..4c729898 100644 --- a/chrome/test/data/webui/welcome/module_metrics_test.js +++ b/chrome/test/data/webui/welcome/module_metrics_test.js
@@ -4,15 +4,15 @@ cr.define('onboarding_welcome_module_metrics', function() { suite('ModuleMetricsTest', function() { - /** @type {nux.ModuleMetricsProxy} */ + /** @type {welcome.ModuleMetricsProxy} */ let testMetricsProxy; - /** @type {nux.ModuleMetricsManager} */ + /** @type {welcome.ModuleMetricsManager} */ let testMetricsManager; setup(function() { testMetricsProxy = new TestMetricsProxy(); - testMetricsManager = new nux.ModuleMetricsManager(testMetricsProxy); + testMetricsManager = new welcome.ModuleMetricsManager(testMetricsProxy); testMetricsManager.recordPageInitialized();
diff --git a/chrome/test/data/webui/welcome/nux_ntp_background_test.js b/chrome/test/data/webui/welcome/nux_ntp_background_test.js index 0dd420fe..4798026 100644 --- a/chrome/test/data/webui/welcome/nux_ntp_background_test.js +++ b/chrome/test/data/webui/welcome/nux_ntp_background_test.js
@@ -4,7 +4,7 @@ cr.define('onboarding_ntp_background_test', function() { suite('NuxNtpBackgroundTest', function() { - /** @type {!Array<!nux.NtpBackgroundData} */ + /** @type {!Array<!welcome.NtpBackgroundData} */ let backgrounds = [ { id: 0, @@ -25,10 +25,10 @@ /** @type {NuxNtpBackgroundElement} */ let testElement; - /** @type {nux.ModuleMetricsProxy} */ + /** @type {welcome.ModuleMetricsProxy} */ let testMetricsProxy; - /** @type {nux.NtpBackgroundProxy} */ + /** @type {welcome.NtpBackgroundProxy} */ let testNtpBackgroundProxy; setup(function() { @@ -37,9 +37,9 @@ }); testMetricsProxy = new TestMetricsProxy(); - nux.NtpBackgroundMetricsProxyImpl.instance_ = testMetricsProxy; + welcome.NtpBackgroundMetricsProxyImpl.instance_ = testMetricsProxy; testNtpBackgroundProxy = new TestNtpBackgroundProxy(); - nux.NtpBackgroundProxyImpl.instance_ = testNtpBackgroundProxy; + welcome.NtpBackgroundProxyImpl.instance_ = testNtpBackgroundProxy; testNtpBackgroundProxy.setBackgroundsList(backgrounds); PolymerTest.clearBody();
diff --git a/chrome/test/data/webui/welcome/nux_set_as_default_test.js b/chrome/test/data/webui/welcome/nux_set_as_default_test.js index 2f470fb4..aedb067 100644 --- a/chrome/test/data/webui/welcome/nux_set_as_default_test.js +++ b/chrome/test/data/webui/welcome/nux_set_as_default_test.js
@@ -7,7 +7,7 @@ /** @type {NuxSetAsDefaultElement} */ let testElement; - /** @type {nux.NuxSetAsDefaultProxy} */ + /** @type {welcome.NuxSetAsDefaultProxy} */ let testSetAsDefaultProxy; /** @type {!Promise} */ @@ -15,7 +15,7 @@ setup(function() { testSetAsDefaultProxy = new TestNuxSetAsDefaultProxy(); - nux.NuxSetAsDefaultProxyImpl.instance_ = testSetAsDefaultProxy; + welcome.NuxSetAsDefaultProxyImpl.instance_ = testSetAsDefaultProxy; navigatedPromise = new Promise(resolve => { // Spy on navigational function to make sure it's called.
diff --git a/chrome/test/data/webui/welcome/test_bookmark_proxy.js b/chrome/test/data/webui/welcome/test_bookmark_proxy.js index 9ba70638..911722f 100644 --- a/chrome/test/data/webui/welcome/test_bookmark_proxy.js +++ b/chrome/test/data/webui/welcome/test_bookmark_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** @implements {nux.BookmarkProxy} */ +/** @implements {welcome.BookmarkProxy} */ class TestBookmarkProxy extends TestBrowserProxy { constructor() { super([
diff --git a/chrome/test/data/webui/welcome/test_google_app_proxy.js b/chrome/test/data/webui/welcome/test_google_app_proxy.js index 6b0af9e..c352083 100644 --- a/chrome/test/data/webui/welcome/test_google_app_proxy.js +++ b/chrome/test/data/webui/welcome/test_google_app_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** @implements {nux.GoogleAppProxy} */ +/** @implements {welcome.GoogleAppProxy} */ class TestGoogleAppProxy extends TestBrowserProxy { constructor() { super([ @@ -13,7 +13,7 @@ this.providerSelectedCount = 0; - /** @private {!Array<!nux.BookmarkListItem>} */ + /** @private {!Array<!welcome.BookmarkListItem>} */ this.appList_ = []; } @@ -34,7 +34,7 @@ this.providerSelectedCount++; } - /** @param {!Array<!nux.BookmarkListItem>} appList */ + /** @param {!Array<!welcome.BookmarkListItem>} appList */ setAppList(appList) { this.appList_ = appList; }
diff --git a/chrome/test/data/webui/welcome/test_metrics_proxy.js b/chrome/test/data/webui/welcome/test_metrics_proxy.js index ef5d4fc..87ec0156 100644 --- a/chrome/test/data/webui/welcome/test_metrics_proxy.js +++ b/chrome/test/data/webui/welcome/test_metrics_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** @implements {nux.ModuleMetricsProxy} */ +/** @implements {welcome.ModuleMetricsProxy} */ class TestMetricsProxy extends TestBrowserProxy { constructor() { super([
diff --git a/chrome/test/data/webui/welcome/test_ntp_background_proxy.js b/chrome/test/data/webui/welcome/test_ntp_background_proxy.js index cae93b8..223b6f4 100644 --- a/chrome/test/data/webui/welcome/test_ntp_background_proxy.js +++ b/chrome/test/data/webui/welcome/test_ntp_background_proxy.js
@@ -14,7 +14,7 @@ 'setBackground', ]); - /** @private {!Array<!nux.NtpBackgroundData} */ + /** @private {!Array<!welcome.NtpBackgroundData} */ this.backgroundsList_ = []; /** @private {boolean} */ @@ -58,7 +58,7 @@ this.preloadImageSuccess_ = success; } - /** @param {!Array<!nux.NtpBackgroundData>} backgroundsList */ + /** @param {!Array<!welcome.NtpBackgroundData>} backgroundsList */ setBackgroundsList(backgroundsList) { this.backgroundsList_ = backgroundsList; }
diff --git a/chrome/test/data/webui/welcome/test_nux_set_as_default_proxy.js b/chrome/test/data/webui/welcome/test_nux_set_as_default_proxy.js index a91e168..c6ab9262 100644 --- a/chrome/test/data/webui/welcome/test_nux_set_as_default_proxy.js +++ b/chrome/test/data/webui/welcome/test_nux_set_as_default_proxy.js
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** @implements {nux.NuxSetAsDefaultProxy} */ +/** @implements {welcome.NuxSetAsDefaultProxy} */ class TestNuxSetAsDefaultProxy extends TestBrowserProxy { constructor() { super([ @@ -30,7 +30,7 @@ this.methodCalled('setAsDefault'); } - /** @param {!nux.DefaultBrowserInfo} status */ + /** @param {!welcome.DefaultBrowserInfo} status */ setDefaultStatus(status) { this.defaultStatus_ = status; }
diff --git a/chrome/test/data/webui/welcome/welcome_app_test.js b/chrome/test/data/webui/welcome/welcome_app_test.js index cd17f3d..2a5112f 100644 --- a/chrome/test/data/webui/welcome/welcome_app_test.js +++ b/chrome/test/data/webui/welcome/welcome_app_test.js
@@ -11,7 +11,7 @@ /** @type {welcome.WelcomeBrowserProxy} */ let testWelcomeBrowserProxy; - /** @type {nux.NuxSetAsDefaultProxy} */ + /** @type {welcome.NuxSetAsDefaultProxy} */ let testSetAsDefaultProxy; function resetTestElement() { @@ -48,11 +48,11 @@ welcome.WelcomeBrowserProxyImpl.instance_ = testWelcomeBrowserProxy; testSetAsDefaultProxy = new TestNuxSetAsDefaultProxy(); - nux.NuxSetAsDefaultProxyImpl.instance_ = testSetAsDefaultProxy; + welcome.NuxSetAsDefaultProxyImpl.instance_ = testSetAsDefaultProxy; // Not used in test, but setting to test proxy anyway, in order to prevent // calls to backend. - nux.BookmarkProxyImpl.instance_ = new TestBookmarkProxy(); + welcome.BookmarkProxyImpl.instance_ = new TestBookmarkProxy(); resetTestElement(); }); @@ -123,7 +123,7 @@ test('default-status check resolves with correct value', function() { /** - * @param {!nux.DefaultBrowserInfo} status + * @param {!welcome.DefaultBrowserInfo} status * @param {boolean} expectedDefaultExists * @return {!Promise} */
diff --git a/chromecast/media/audio/BUILD.gn b/chromecast/media/audio/BUILD.gn index 308ad35..2919478 100644 --- a/chromecast/media/audio/BUILD.gn +++ b/chromecast/media/audio/BUILD.gn
@@ -15,6 +15,8 @@ cast_source_set("audio") { sources = [ + "cast_audio_input_stream.cc", + "cast_audio_input_stream.h", "cast_audio_manager.cc", "cast_audio_manager.h", "cast_audio_mixer.cc",
diff --git a/chromecast/media/audio/cast_audio_input_stream.cc b/chromecast/media/audio/cast_audio_input_stream.cc new file mode 100644 index 0000000..32790704 --- /dev/null +++ b/chromecast/media/audio/cast_audio_input_stream.cc
@@ -0,0 +1,100 @@ +// Copyright 2019 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 "chromecast/media/audio/cast_audio_input_stream.h" + +#include "base/logging.h" +#include "chromecast/media/audio/capture_service/capture_service_receiver.h" + +namespace chromecast { +namespace media { + +CastAudioInputStream::CastAudioInputStream( + const ::media::AudioParameters& audio_params, + const std::string& device_id) + : audio_params_(audio_params) { + DETACH_FROM_THREAD(audio_thread_checker_); + LOG(INFO) << __func__ << " " << this + << " created from device_id = " << device_id + << " with audio_params = {" << audio_params_.AsHumanReadableString() + << "}."; +} + +CastAudioInputStream::~CastAudioInputStream() { + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); +} + +bool CastAudioInputStream::Open() { + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); + DCHECK(!capture_service_receiver_); + LOG(INFO) << __func__ << " " << this << "."; + + // Sanity check the audio parameters. + ::media::AudioParameters::Format format = audio_params_.format(); + DCHECK((format == ::media::AudioParameters::AUDIO_PCM_LINEAR) || + (format == ::media::AudioParameters::AUDIO_PCM_LOW_LATENCY)); + ::media::ChannelLayout channel_layout = audio_params_.channel_layout(); + if ((channel_layout != ::media::CHANNEL_LAYOUT_MONO) && + (channel_layout != ::media::CHANNEL_LAYOUT_STEREO)) { + LOG(WARNING) << "Unsupported channel layout: " << channel_layout; + return false; + } + DCHECK_GE(audio_params_.channels(), 1); + DCHECK_LE(audio_params_.channels(), 2); + + capture_service_receiver_ = + std::make_unique<CaptureServiceReceiver>(audio_params_); + return true; +} + +void CastAudioInputStream::Start(AudioInputCallback* input_callback) { + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); + DCHECK(capture_service_receiver_); + DCHECK(input_callback); + LOG(INFO) << __func__ << " " << this << "."; + capture_service_receiver_->Start(input_callback); +} + +void CastAudioInputStream::Stop() { + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); + DCHECK(capture_service_receiver_); + LOG(INFO) << __func__ << " " << this << "."; + capture_service_receiver_->Stop(); +} + +void CastAudioInputStream::Close() { + DCHECK_CALLED_ON_VALID_THREAD(audio_thread_checker_); + LOG(INFO) << __func__ << " " << this << "."; + capture_service_receiver_.reset(); +} + +double CastAudioInputStream::GetMaxVolume() { + return 1.0; +} + +void CastAudioInputStream::SetVolume(double volume) {} + +double CastAudioInputStream::GetVolume() { + return 1.0; +} + +bool CastAudioInputStream::SetAutomaticGainControl(bool enabled) { + return false; +} + +bool CastAudioInputStream::GetAutomaticGainControl() { + return false; +} + +bool CastAudioInputStream::IsMuted() { + return false; +} + +void CastAudioInputStream::SetOutputDeviceForAec( + const std::string& output_device_id) { + // Not supported. Do nothing. +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/audio/cast_audio_input_stream.h b/chromecast/media/audio/cast_audio_input_stream.h new file mode 100644 index 0000000..dc54bac --- /dev/null +++ b/chromecast/media/audio/cast_audio_input_stream.h
@@ -0,0 +1,53 @@ +// Copyright 2019 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 CHROMECAST_MEDIA_AUDIO_CAST_AUDIO_INPUT_STREAM_H_ +#define CHROMECAST_MEDIA_AUDIO_CAST_AUDIO_INPUT_STREAM_H_ + +#include <memory> +#include <string> + +#include "base/macros.h" +#include "base/threading/thread_checker.h" +#include "media/audio/audio_io.h" +#include "media/base/audio_parameters.h" + +namespace chromecast { +namespace media { + +class CaptureServiceReceiver; +class CastAudioManager; + +class CastAudioInputStream : public ::media::AudioInputStream { + public: + CastAudioInputStream(const ::media::AudioParameters& audio_params, + const std::string& device_id); + ~CastAudioInputStream() override; + + // ::media::AudioInputStream implementation: + bool Open() override; + void Start(AudioInputCallback* source_callback) override; + void Stop() override; + void Close() override; + double GetMaxVolume() override; + void SetVolume(double volume) override; + double GetVolume() override; + bool SetAutomaticGainControl(bool enabled) override; + bool GetAutomaticGainControl() override; + bool IsMuted() override; + void SetOutputDeviceForAec(const std::string& output_device_id) override; + + private: + const ::media::AudioParameters audio_params_; + std::unique_ptr<CaptureServiceReceiver> capture_service_receiver_; + + THREAD_CHECKER(audio_thread_checker_); + + DISALLOW_COPY_AND_ASSIGN(CastAudioInputStream); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_AUDIO_CAST_AUDIO_INPUT_STREAM_H_
diff --git a/chromecast/media/audio/cast_audio_manager_alsa.cc b/chromecast/media/audio/cast_audio_manager_alsa.cc index 6112900..fb22185 100644 --- a/chromecast/media/audio/cast_audio_manager_alsa.cc +++ b/chromecast/media/audio/cast_audio_manager_alsa.cc
@@ -4,12 +4,13 @@ #include "chromecast/media/audio/cast_audio_manager_alsa.h" -#include <string> #include <utility> #include "base/memory/free_deleter.h" #include "base/stl_util.h" +#include "base/strings/string_piece.h" #include "chromecast/media/audio/audio_buildflags.h" +#include "chromecast/media/audio/cast_audio_input_stream.h" #include "chromecast/media/cma/backend/cma_backend_factory.h" #include "media/audio/alsa/alsa_input.h" #include "media/audio/alsa/alsa_wrapper.h" @@ -18,18 +19,62 @@ namespace media { namespace { + // TODO(alokp): Query the preferred value from media backend. const int kDefaultSampleRate = BUILDFLAG(AUDIO_INPUT_SAMPLE_RATE); // TODO(jyw): Query the preferred value from media backend. -static const int kDefaultInputBufferSize = 1024; +const int kDefaultInputBufferSize = 1024; + +const int kCommunicationsSampleRate = 16000; +const int kCommunicationsInputBufferSize = 160; // 10 ms. // Since "default" and "dmix" devices are virtual devices mapped to real // devices, we remove them from the list to avoiding duplicate counting. -static const char* kInvalidAudioInputDevices[] = { - "default", "dmix", "null", +constexpr base::StringPiece kInvalidAudioInputDevices[] = { + "default", + "dmix", + "null", + "communications", }; +// Constants specified by the ALSA API for device hints. +constexpr char kPcmInterfaceName[] = "pcm"; +constexpr char kIoHintName[] = "IOID"; +constexpr char kNameHintName[] = "NAME"; +constexpr char kDescriptionHintName[] = "DESC"; + +bool IsAlsaDeviceAvailable(CastAudioManagerAlsa::StreamType type, + const char* device_name) { + if (!device_name) + return false; + + // We do prefix matches on the device name to see whether to include + // it or not. + if (type == CastAudioManagerAlsa::kStreamCapture) { + // Check if the device is in the list of invalid devices. + for (size_t i = 0; i < base::size(kInvalidAudioInputDevices); ++i) { + if (kInvalidAudioInputDevices[i] == device_name) + return false; + } + return true; + } else { + DCHECK_EQ(CastAudioManagerAlsa::kStreamPlayback, type); + // We prefer the device type that maps straight to hardware but + // goes through software conversion if needed (e.g. incompatible + // sample rate). + // TODO(joi): Should we prefer "hw" instead? + const std::string kDeviceTypeDesired = "plughw"; + return kDeviceTypeDesired == device_name; + } +} + +std::string UnwantedDeviceTypeWhenEnumerating( + CastAudioManagerAlsa::StreamType wanted_type) { + return wanted_type == CastAudioManagerAlsa::kStreamPlayback ? "Input" + : "Output"; +} + } // namespace CastAudioManagerAlsa::CastAudioManagerAlsa( @@ -60,11 +105,23 @@ void CastAudioManagerAlsa::GetAudioInputDeviceNames( ::media::AudioDeviceNames* device_names) { DCHECK(device_names->empty()); + // Prepend the default device since we always want it to be on the top of the + // list for all platforms. Note, pulse has exclusively opened the default + // device, so we must open the device via the "default" moniker. + device_names->push_front(::media::AudioDeviceName::CreateDefault()); + device_names->push_back(::media::AudioDeviceName::CreateCommunications()); + GetAlsaAudioDevices(kStreamCapture, device_names); } ::media::AudioParameters CastAudioManagerAlsa::GetInputStreamParameters( const std::string& device_id) { + if (device_id == ::media::AudioDeviceDescription::kCommunicationsDeviceId) { + return ::media::AudioParameters(::media::AudioParameters::AUDIO_PCM_LINEAR, + ::media::CHANNEL_LAYOUT_MONO, + kCommunicationsSampleRate, + kCommunicationsInputBufferSize); + } // TODO(jyw): Be smarter about sample rate instead of hardcoding it. // Need to send a valid AudioParameters object even when it will be unused. return ::media::AudioParameters( @@ -96,6 +153,9 @@ (device_id == ::media::AudioDeviceDescription::kDefaultDeviceId) ? ::media::AlsaPcmInputStream::kAutoSelectDevice : device_id; + if (device_name == ::media::AudioDeviceDescription::kCommunicationsDeviceId) { + return new CastAudioInputStream(params, device_name); + } return new ::media::AlsaPcmInputStream(this, device_name, params, wrapper_.get()); } @@ -103,8 +163,6 @@ void CastAudioManagerAlsa::GetAlsaAudioDevices( StreamType type, ::media::AudioDeviceNames* device_names) { - // Constants specified by the ALSA API for device hints. - static const char kPcmInterfaceName[] = "pcm"; int card = -1; // Loop through the sound cards to get ALSA device hints. @@ -127,28 +185,17 @@ StreamType type, void** hints, ::media::AudioDeviceNames* device_names) { - static const char kIoHintName[] = "IOID"; - static const char kNameHintName[] = "NAME"; - static const char kDescriptionHintName[] = "DESC"; - - const char* unwanted_device_type = UnwantedDeviceTypeWhenEnumerating(type); + const std::string unwanted_device_type = + UnwantedDeviceTypeWhenEnumerating(type); for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { // Only examine devices of the right type. Valid values are // "Input", "Output", and NULL which means both input and output. std::unique_ptr<char, base::FreeDeleter> io( wrapper_->DeviceNameGetHint(*hint_iter, kIoHintName)); - if (io != NULL && strcmp(unwanted_device_type, io.get()) == 0) + if (io && unwanted_device_type == io.get()) continue; - // Found a device, prepend the default device since we always want - // it to be on the top of the list for all platforms. And there is - // no duplicate counting here since it is only done if the list is - // still empty. Note, pulse has exclusively opened the default - // device, so we must open the device via the "default" moniker. - if (device_names->empty()) - device_names->push_front(::media::AudioDeviceName::CreateDefault()); - // Get the unique device name for the device. std::unique_ptr<char, base::FreeDeleter> unique_device_name( wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName)); @@ -162,12 +209,10 @@ ::media::AudioDeviceName name; name.unique_id = unique_device_name.get(); if (desc) { + name.device_name = desc.get(); // Use the more user friendly description as name. // Replace '\n' with '-'. - char* pret = strchr(desc.get(), '\n'); - if (pret) - *pret = '-'; - name.device_name = desc.get(); + name.device_name.replace(name.device_name.find('\n'), 1, 1, '-'); } else { // Virtual devices don't necessarily have descriptions. // Use their names instead. @@ -180,39 +225,5 @@ } } -// static -bool CastAudioManagerAlsa::IsAlsaDeviceAvailable(StreamType type, - const char* device_name) { - if (!device_name) - return false; - - // We do prefix matches on the device name to see whether to include - // it or not. - if (type == kStreamCapture) { - // Check if the device is in the list of invalid devices. - for (size_t i = 0; i < base::size(kInvalidAudioInputDevices); ++i) { - if (strncmp(kInvalidAudioInputDevices[i], device_name, - strlen(kInvalidAudioInputDevices[i])) == 0) - return false; - } - return true; - } else { - DCHECK_EQ(kStreamPlayback, type); - // We prefer the device type that maps straight to hardware but - // goes through software conversion if needed (e.g. incompatible - // sample rate). - // TODO(joi): Should we prefer "hw" instead? - static const char kDeviceTypeDesired[] = "plughw"; - return strncmp(kDeviceTypeDesired, device_name, - base::size(kDeviceTypeDesired) - 1) == 0; - } -} - -// static -const char* CastAudioManagerAlsa::UnwantedDeviceTypeWhenEnumerating( - StreamType wanted_type) { - return wanted_type == kStreamPlayback ? "Input" : "Output"; -} - } // namespace media } // namespace chromecast
diff --git a/chromecast/media/audio/cast_audio_manager_alsa.h b/chromecast/media/audio/cast_audio_manager_alsa.h index 5a0c49f108..d0fa9a4 100644 --- a/chromecast/media/audio/cast_audio_manager_alsa.h +++ b/chromecast/media/audio/cast_audio_manager_alsa.h
@@ -22,6 +22,11 @@ class CastAudioManagerAlsa : public CastAudioManager { public: + enum StreamType { + kStreamPlayback = 0, + kStreamCapture, + }; + CastAudioManagerAlsa( std::unique_ptr<::media::AudioThread> audio_thread, ::media::AudioLogFactory* audio_log_factory, @@ -41,11 +46,6 @@ const std::string& device_id) override; private: - enum StreamType { - kStreamPlayback = 0, - kStreamCapture, - }; - // CastAudioManager implementation. ::media::AudioInputStream* MakeLinearInputStream( const ::media::AudioParameters& params, @@ -70,11 +70,6 @@ void** hint, ::media::AudioDeviceNames* device_names); - // Checks if the specific ALSA device is available. - static bool IsAlsaDeviceAvailable(StreamType type, const char* device_name); - - static const char* UnwantedDeviceTypeWhenEnumerating(StreamType wanted_type); - std::unique_ptr<::media::AlsaWrapper> wrapper_; DISALLOW_COPY_AND_ASSIGN(CastAudioManagerAlsa);
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc index 625ee5ff..30098ec 100644 --- a/chromeos/constants/chromeos_features.cc +++ b/chromeos/constants/chromeos_features.cc
@@ -40,6 +40,10 @@ const base::Feature kCrostiniUsbAllowUnsupported{ "CrostiniUsbAllowUnsupported", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables or disables the new WebUI Crostini installer. +const base::Feature kCrostiniWebUIInstaller{"CrostiniWebUIInstaller", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables or disables the CryptAuth v2 Enrollment flow. const base::Feature kCryptAuthV2Enrollment{"CryptAuthV2Enrollment", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h index 7903111..128f9b0 100644 --- a/chromeos/constants/chromeos_features.h +++ b/chromeos/constants/chromeos_features.h
@@ -31,6 +31,8 @@ COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kCrostiniUsbAllowUnsupported; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) +extern const base::Feature kCrostiniWebUIInstaller; +COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kCryptAuthV2Enrollment; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kDiscoverApp; COMPONENT_EXPORT(CHROMEOS_CONSTANTS) extern const base::Feature kDriveFs;
diff --git a/components/autofill/core/browser/ui/accessory_sheet_data.cc b/components/autofill/core/browser/ui/accessory_sheet_data.cc index 36eb0fb..3f9740d 100644 --- a/components/autofill/core/browser/ui/accessory_sheet_data.cc +++ b/components/autofill/core/browser/ui/accessory_sheet_data.cc
@@ -56,6 +56,8 @@ UserInfo::UserInfo() = default; +UserInfo::UserInfo(std::string origin) : origin_(std::move(origin)) {} + UserInfo::UserInfo(const UserInfo& user_info) = default; UserInfo::UserInfo(UserInfo&& field) = default; @@ -67,11 +69,12 @@ UserInfo& UserInfo::operator=(UserInfo&& user_info) = default; bool UserInfo::operator==(const UserInfo& user_info) const { - return fields_ == user_info.fields_; + return fields_ == user_info.fields_ && origin_ == user_info.origin_; } std::ostream& operator<<(std::ostream& os, const UserInfo& user_info) { - os << "[\n"; + os << "origin: \"" << user_info.origin() << "\", \n" + << "fields: [\n"; for (const UserInfo::Field& field : user_info.fields()) { os << field << ", \n"; } @@ -164,13 +167,15 @@ AccessorySheetData::Builder::~Builder() = default; -AccessorySheetData::Builder&& AccessorySheetData::Builder::AddUserInfo() && { +AccessorySheetData::Builder&& AccessorySheetData::Builder::AddUserInfo( + std::string origin) && { // Calls AddUserInfo()& since |this| is an lvalue. - return std::move(AddUserInfo()); + return std::move(AddUserInfo(std::move(origin))); } -AccessorySheetData::Builder& AccessorySheetData::Builder::AddUserInfo() & { - accessory_sheet_data_.add_user_info(UserInfo()); +AccessorySheetData::Builder& AccessorySheetData::Builder::AddUserInfo( + std::string origin) & { + accessory_sheet_data_.add_user_info(UserInfo(std::move(origin))); return *this; }
diff --git a/components/autofill/core/browser/ui/accessory_sheet_data.h b/components/autofill/core/browser/ui/accessory_sheet_data.h index c4fc354d..1c1fa830 100644 --- a/components/autofill/core/browser/ui/accessory_sheet_data.h +++ b/components/autofill/core/browser/ui/accessory_sheet_data.h
@@ -59,6 +59,7 @@ }; UserInfo(); + explicit UserInfo(std::string origin); UserInfo(const UserInfo& user_info); UserInfo(UserInfo&& field); @@ -70,10 +71,12 @@ void add_field(Field field) { fields_.push_back(std::move(field)); } const std::vector<Field>& fields() const { return fields_; } + const std::string& origin() const { return origin_; } bool operator==(const UserInfo& user_info) const; private: + std::string origin_; std::vector<Field> fields_; }; @@ -175,8 +178,8 @@ ~Builder(); // Adds a new UserInfo object to |accessory_sheet_data_|. - Builder&& AddUserInfo() &&; - Builder& AddUserInfo() &; + Builder&& AddUserInfo(std::string origin = std::string()) &&; + Builder& AddUserInfo(std::string origin = std::string()) &; // Appends a selectable, non-obfuscated field to the last UserInfo object. Builder&& AppendSimpleField(base::string16 text) &&;
diff --git a/components/exo/wayland/clients/test/wayland_client_test_helper.cc b/components/exo/wayland/clients/test/wayland_client_test_helper.cc index 3f5a2cf..ad65264c 100644 --- a/components/exo/wayland/clients/test/wayland_client_test_helper.cc +++ b/components/exo/wayland/clients/test/wayland_client_test_helper.cc
@@ -107,9 +107,8 @@ command_line->AppendSwitch(wm::switches::kWindowAnimationsDisabled); ash_test_helper_ = std::make_unique<ash::AshTestHelper>(); - - ash_test_helper_->SetUp(/*start_session=*/true, - /*provide_local_state=*/true); + ash::AshTestHelper::InitParams init_params; + ash_test_helper_->SetUp(init_params); ash::Shell::GetPrimaryRootWindow()->Show(); ash::Shell::GetPrimaryRootWindow()->GetHost()->Show(); ash::Shell::GetPrimaryRootWindow()->MoveCursorTo(gfx::Point(-1000, -1000));
diff --git a/components/favicon/core/large_icon_service_impl.cc b/components/favicon/core/large_icon_service_impl.cc index f4f37fe..3a894cf 100644 --- a/components/favicon/core/large_icon_service_impl.cc +++ b/components/favicon/core/large_icon_service_impl.cc
@@ -13,7 +13,6 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/singleton.h" -#include "base/metrics/field_trial_params.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" @@ -34,11 +33,6 @@ namespace favicon { -// This feature is only used for accessing field trial parameters, not for -// switching on/off the code. -const base::Feature kLargeIconServiceFetchingFeature{ - "LargeIconServiceFetching", base::FEATURE_ENABLED_BY_DEFAULT}; - namespace { using favicon_base::GoogleFaviconServerRequestStatus; @@ -48,22 +42,16 @@ const char kGoogleServerV2RequestFormat[] = "https://t0.gstatic.com/faviconV2?client=chrome&nfrp=2&%s" "size=%d&min_size=%d&max_size=%d&fallback_opts=TYPE,SIZE,URL&url=%s"; -const char kGoogleServerV2RequestFormatParam[] = "request_format"; const char kClientParam[] = "client=chrome"; const char kCheckSeenParam[] = "check_seen=true&"; const int kGoogleServerV2EnforcedMinSizeInPixel = 16; -const char kGoogleServerV2EnforcedMinSizeInPixelParam[] = - "enforced_min_size_in_pixel"; const double kGoogleServerV2DesiredToMaxSizeFactor = 2.0; -const char kGoogleServerV2DesiredToMaxSizeFactorParam[] = - "desired_to_max_size_factor"; -const double kGoogleServerV2MinimumMaxSizeInPixel = 256.0; -const char kGoogleServerV2MinimumMaxSizeInPixelParam[] = "minimum_max_size"; +const int kGoogleServerV2MinimumMaxSizeInPixel = 256; const int kInvalidOrganizationId = -1; @@ -88,30 +76,17 @@ int min_source_size_in_pixel, int desired_size_in_pixel, bool may_page_url_be_private) { - std::string url_format = base::GetFieldTrialParamValueByFeature( - kLargeIconServiceFetchingFeature, kGoogleServerV2RequestFormatParam); - double desired_to_max_size_factor = base::GetFieldTrialParamByFeatureAsDouble( - kLargeIconServiceFetchingFeature, - kGoogleServerV2DesiredToMaxSizeFactorParam, - kGoogleServerV2DesiredToMaxSizeFactor); - int minimum_max_size_in_pixel = base::GetFieldTrialParamByFeatureAsInt( - kLargeIconServiceFetchingFeature, - kGoogleServerV2MinimumMaxSizeInPixelParam, - kGoogleServerV2MinimumMaxSizeInPixel); - - min_source_size_in_pixel = std::max( - min_source_size_in_pixel, base::GetFieldTrialParamByFeatureAsInt( - kLargeIconServiceFetchingFeature, - kGoogleServerV2EnforcedMinSizeInPixelParam, - kGoogleServerV2EnforcedMinSizeInPixel)); + min_source_size_in_pixel = + std::max(min_source_size_in_pixel, kGoogleServerV2EnforcedMinSizeInPixel); desired_size_in_pixel = std::max(desired_size_in_pixel, min_source_size_in_pixel); - int max_size_in_pixel = - static_cast<int>(desired_size_in_pixel * desired_to_max_size_factor); - max_size_in_pixel = std::max(max_size_in_pixel, minimum_max_size_in_pixel); + int max_size_in_pixel = static_cast<int>( + desired_size_in_pixel * kGoogleServerV2DesiredToMaxSizeFactor); + max_size_in_pixel = + std::max(max_size_in_pixel, kGoogleServerV2MinimumMaxSizeInPixel); std::string request_url = base::StringPrintf( - url_format.empty() ? kGoogleServerV2RequestFormat : url_format.c_str(), + kGoogleServerV2RequestFormat, may_page_url_be_private ? kCheckSeenParam : "", desired_size_in_pixel, min_source_size_in_pixel, max_size_in_pixel, page_url.spec().c_str()); base::ReplaceFirstSubstringAfterOffset(
diff --git a/components/favicon/core/large_icon_service_impl_unittest.cc b/components/favicon/core/large_icon_service_impl_unittest.cc index 55243a9..c7f4d728 100644 --- a/components/favicon/core/large_icon_service_impl_unittest.cc +++ b/components/favicon/core/large_icon_service_impl_unittest.cc
@@ -225,56 +225,6 @@ "Favicons.LargeIconService.DownloadedSize", 32, /*expected_count=*/1); } -TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithCustomUrl) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeatureWithParameters( - kLargeIconServiceFetchingFeature, - {{"request_format", - "https://t0.gstatic.com/" - "faviconV2?%ssize=%d&min_size=%d&max_size=%d&url=%s"}, - {"enforced_min_size_in_pixel", "43"}, - {"desired_to_max_size_factor", "6.5"}}); - const GURL kExpectedServerUrl( - "https://t0.gstatic.com/faviconV2?check_seen=true&" - "size=61&min_size=43&max_size=396&url=http://www.example.com/"); - - EXPECT_CALL(mock_favicon_service_, UnableToDownloadFavicon(_)).Times(0); - EXPECT_CALL(mock_favicon_service_, - CanSetOnDemandFavicons(GURL(kDummyUrl), - favicon_base::IconType::kTouchIcon, _)) - .WillOnce([](auto, auto, base::OnceCallback<void(bool)> callback) { - return base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), true)); - }); - - base::MockCallback<favicon_base::GoogleFaviconServerCallback> callback; - EXPECT_CALL(*mock_image_fetcher_, - FetchImageAndData_(kExpectedServerUrl, _, _, _)) - .WillOnce(PostFetchReply(gfx::Image::CreateFrom1xBitmap( - CreateTestSkBitmap(64, 64, kTestColor)))); - EXPECT_CALL(mock_favicon_service_, - SetOnDemandFavicons(GURL(kDummyUrl), kExpectedServerUrl, - favicon_base::IconType::kTouchIcon, _, _)) - .WillOnce( - [](auto, auto, auto, auto, base::OnceCallback<void(bool)> callback) { - return base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), true)); - }); - - large_icon_service_ - .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache( - favicon::FaviconServerFetcherParams::CreateForMobile( - GURL(kDummyUrl), - /*min_source_size_in_pixel=*/42, - /*desired_size_in_pixel=*/61), - /*may_page_url_be_private=*/true, /*should_trim_page_url_path=*/false, - TRAFFIC_ANNOTATION_FOR_TESTS, callback.Get()); - - EXPECT_CALL(callback, - Run(favicon_base::GoogleFaviconServerRequestStatus::SUCCESS)); - scoped_task_environment_.RunUntilIdle(); -} - TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithOriginalUrl) { const GURL kExpectedServerUrl( "https://t0.gstatic.com/faviconV2?client=chrome&nfrp=2"
diff --git a/components/gcm_driver/resources/gcm_internals.html b/components/gcm_driver/resources/gcm_internals.html index 54d5874..92068078 100644 --- a/components/gcm_driver/resources/gcm_internals.html +++ b/components/gcm_driver/resources/gcm_internals.html
@@ -1,5 +1,5 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <title>GCM Internals</title>
diff --git a/components/network_hints/browser/network_hints_message_filter.cc b/components/network_hints/browser/network_hints_message_filter.cc index 0a4f9107..998bad3 100644 --- a/components/network_hints/browser/network_hints_message_filter.cc +++ b/components/network_hints/browser/network_hints_message_filter.cc
@@ -83,7 +83,7 @@ int result, const base::Optional<net::AddressList>& resolved_addresses) override { VLOG(2) << __FUNCTION__ << ": " << hostname_ << ", result=" << result; - std::move(request_); + request_.reset(); } mojo::Binding<network::mojom::ResolveHostClient> binding_;
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc index 3c6b171f..b99abea2 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc
@@ -1215,19 +1215,14 @@ return true; } -bool LoginDatabase::GetAutoSignInLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - DCHECK(forms); +bool LoginDatabase::GetAutoSignInLogins(PrimaryKeyToFormMap* key_to_form_map) { + DCHECK(key_to_form_map); DCHECK(!autosignin_statement_.empty()); - forms->clear(); + key_to_form_map->clear(); sql::Statement s( db_.GetCachedStatement(SQL_FROM_HERE, autosignin_statement_.c_str())); - PrimaryKeyToFormMap key_to_form_map; - FormRetrievalResult result = StatementToForms(&s, nullptr, &key_to_form_map); - for (auto& pair : key_to_form_map) { - forms->push_back(std::move(pair.second)); - } + FormRetrievalResult result = StatementToForms(&s, nullptr, key_to_form_map); return result == FormRetrievalResult::kSuccess; }
diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h index 5b07dcf..303210a 100644 --- a/components/password_manager/core/browser/login_database.h +++ b/components/password_manager/core/browser/login_database.h
@@ -142,8 +142,8 @@ forms) WARN_UNUSED_RESULT; // Gets the list of auto-sign-inable credentials. - bool GetAutoSignInLogins(std::vector<std::unique_ptr<autofill::PasswordForm>>* - forms) WARN_UNUSED_RESULT; + bool GetAutoSignInLogins(PrimaryKeyToFormMap* key_to_form_map) + WARN_UNUSED_RESULT; // Deletes the login database file on disk, and creates a new, empty database. // This can be used after migrating passwords to some other store, to ensure
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc index 37762be..22609bf 100644 --- a/components/password_manager/core/browser/login_database_unittest.cc +++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -1011,7 +1011,7 @@ } TEST_F(LoginDatabaseTest, GetAutoSignInLogins) { - std::vector<std::unique_ptr<PasswordForm>> result; + PrimaryKeyToFormMap key_to_form_map; GURL origin("https://example.com"); EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo1", origin)); @@ -1019,14 +1019,14 @@ EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo3", origin)); EXPECT_TRUE(AddZeroClickableLogin(&db(), "foo4", origin)); - EXPECT_TRUE(db().GetAutoSignInLogins(&result)); - EXPECT_EQ(4U, result.size()); - for (const auto& form : result) - EXPECT_FALSE(form->skip_zero_click); + EXPECT_TRUE(db().GetAutoSignInLogins(&key_to_form_map)); + EXPECT_EQ(4U, key_to_form_map.size()); + for (const auto& pair : key_to_form_map) + EXPECT_FALSE(pair.second->skip_zero_click); EXPECT_TRUE(db().DisableAutoSignInForOrigin(origin)); - EXPECT_TRUE(db().GetAutoSignInLogins(&result)); - EXPECT_EQ(0U, result.size()); + EXPECT_TRUE(db().GetAutoSignInLogins(&key_to_form_map)); + EXPECT_EQ(0U, key_to_form_map.size()); } TEST_F(LoginDatabaseTest, DisableAutoSignInForOrigin) {
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc index 67266c62..b34eff7 100644 --- a/components/password_manager/core/browser/password_store_default.cc +++ b/components/password_manager/core/browser/password_store_default.cc
@@ -124,15 +124,15 @@ PasswordStoreChangeList PasswordStoreDefault::DisableAutoSignInForOriginsImpl( const base::Callback<bool(const GURL&)>& origin_filter) { - std::vector<std::unique_ptr<PasswordForm>> forms; + PrimaryKeyToFormMap key_to_form_map; PasswordStoreChangeList changes; - if (!login_db_ || !login_db_->GetAutoSignInLogins(&forms)) + if (!login_db_ || !login_db_->GetAutoSignInLogins(&key_to_form_map)) return changes; std::set<GURL> origins_to_update; - for (const auto& form : forms) { - if (origin_filter.Run(form->origin)) - origins_to_update.insert(form->origin); + for (const auto& pair : key_to_form_map) { + if (origin_filter.Run(pair.second->origin)) + origins_to_update.insert(pair.second->origin); } std::set<GURL> origins_updated; @@ -141,10 +141,10 @@ origins_updated.insert(origin); } - for (const auto& form : forms) { - if (origins_updated.count(form->origin)) { - changes.push_back( - PasswordStoreChange(PasswordStoreChange::UPDATE, *form)); + for (const auto& pair : key_to_form_map) { + if (origins_updated.count(pair.second->origin)) { + changes.emplace_back(PasswordStoreChange::UPDATE, *pair.second, + /*primary_key=*/pair.first); } }
diff --git a/components/signin/core/browser/resources/signin_index.html b/components/signin/core/browser/resources/signin_index.html index 64d6602..b54d72bbf 100644 --- a/components/signin/core/browser/resources/signin_index.html +++ b/components/signin/core/browser/resources/signin_index.html
@@ -1,15 +1,15 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <script src="chrome://resources/js/cr.js"></script> <script src="chrome://resources/js/util.js"></script> <script src="chrome://resources/js/load_time_data.js"></script> <script src="strings.js"></script> - <if expr="is_ios"> - <!-- TODO(crbug.com/487000): Remove this once injected by the web layer. --> - <script src="chrome://resources/js/ios/web_ui.js"></script> - </if> +<if expr="is_ios"> + <!-- TODO(crbug.com/487000): Remove this once injected by the web layer. --> + <script src="chrome://resources/js/ios/web_ui.js"></script> +</if> <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> <link rel="stylesheet" type="text/css" href="signin_index.css"> </head>
diff --git a/components/sync/base/data_type_histogram.h b/components/sync/base/data_type_histogram.h index 5814eee2..4c5131b 100644 --- a/components/sync/base/data_type_histogram.h +++ b/components/sync/base/data_type_histogram.h
@@ -170,6 +170,9 @@ case ::syncer::SECURITY_EVENTS: \ PER_DATA_TYPE_MACRO("SecurityEvents"); \ break; \ + case ::syncer::WEB_APPS: \ + PER_DATA_TYPE_MACRO("WebApps"); \ + break; \ case ::syncer::WIFI_CONFIGURATIONS: \ PER_DATA_TYPE_MACRO("WifiConfigurations"); \ break; \
diff --git a/components/sync/base/model_type.cc b/components/sync/base/model_type.cc index 518410a..50bd0dc 100644 --- a/components/sync/base/model_type.cc +++ b/components/sync/base/model_type.cc
@@ -155,6 +155,8 @@ {WIFI_CONFIGURATIONS, "WIFI_CONFIGURATION", "wifi_configurations", "Wifi Configurations", sync_pb::EntitySpecifics::kWifiConfigurationFieldNumber, 44}, + {WEB_APPS, "WEB_APP", "web_apps", "Web Apps", + sync_pb::EntitySpecifics::kWebAppFieldNumber, 45}, // ---- Proxy types ---- {PROXY_TABS, "", "", "Tabs", -1, 25}, // ---- Control Types ---- @@ -167,11 +169,11 @@ static_assert(base::size(kModelTypeInfoMap) == ModelType::NUM_ENTRIES, "kModelTypeInfoMap should have ModelType::NUM_ENTRIES elements"); -static_assert(45 == syncer::ModelType::NUM_ENTRIES, +static_assert(46 == syncer::ModelType::NUM_ENTRIES, "When adding a new type, update enum SyncModelTypes in enums.xml " "and suffix SyncModelType in histograms.xml."); -static_assert(45 == syncer::ModelType::NUM_ENTRIES, +static_assert(46 == syncer::ModelType::NUM_ENTRIES, "When adding a new type, update kAllocatorDumpNameWhitelist in " "base/trace_event/memory_infra_background_whitelist.cc."); @@ -307,6 +309,9 @@ case DEPRECATED_EXPERIMENTS: specifics->mutable_experiments(); break; + case WEB_APPS: + specifics->mutable_web_app(); + break; case WIFI_CONFIGURATIONS: specifics->mutable_wifi_configuration(); break; @@ -360,7 +365,7 @@ } ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) { - static_assert(45 == ModelType::NUM_ENTRIES, + static_assert(46 == ModelType::NUM_ENTRIES, "When adding new protocol types, the following type lookup " "logic must be updated."); if (specifics.has_bookmark()) @@ -445,6 +450,8 @@ return SEND_TAB_TO_SELF; if (specifics.has_security_event()) return SECURITY_EVENTS; + if (specifics.has_web_app()) + return WEB_APPS; if (specifics.has_wifi_configuration()) return WIFI_CONFIGURATIONS; @@ -452,7 +459,7 @@ } ModelTypeSet EncryptableUserTypes() { - static_assert(45 == ModelType::NUM_ENTRIES, + static_assert(46 == ModelType::NUM_ENTRIES, "If adding an unencryptable type, remove from " "encryptable_user_types below."); ModelTypeSet encryptable_user_types = UserTypes();
diff --git a/components/sync/base/model_type.h b/components/sync/base/model_type.h index d751ce7..794f038f 100644 --- a/components/sync/base/model_type.h +++ b/components/sync/base/model_type.h
@@ -139,6 +139,8 @@ SECURITY_EVENTS, // Wi-Fi network configurations + credentials WIFI_CONFIGURATIONS, + // A web app object. + WEB_APPS, // ---- Proxy types ---- // Proxy types are excluded from the sync protocol, but are still considered @@ -203,7 +205,7 @@ DEPRECATED_WIFI_CREDENTIALS, SUPERVISED_USER_WHITELISTS, ARC_PACKAGE, PRINTERS, READING_LIST, USER_EVENTS, NIGORI, DEPRECATED_EXPERIMENTS, MOUNTAIN_SHARES, USER_CONSENTS, SEND_TAB_TO_SELF, SECURITY_EVENTS, - WIFI_CONFIGURATIONS); + WEB_APPS, WIFI_CONFIGURATIONS); } // These are the normal user-controlled types. This is to distinguish from
diff --git a/components/sync/base/user_selectable_type.cc b/components/sync/base/user_selectable_type.cc index 766f582..04f7c34 100644 --- a/components/sync/base/user_selectable_type.cc +++ b/components/sync/base/user_selectable_type.cc
@@ -45,7 +45,8 @@ case UserSelectableType::kExtensions: return {"extensions", EXTENSIONS, {EXTENSIONS, EXTENSION_SETTINGS}}; case UserSelectableType::kApps: - return {"apps", APPS, {APPS, APP_SETTINGS, APP_LIST, ARC_PACKAGE}}; + return { + "apps", APPS, {APPS, APP_SETTINGS, APP_LIST, ARC_PACKAGE, WEB_APPS}}; #if BUILDFLAG(ENABLE_READING_LIST) case UserSelectableType::kReadingList: return {"readingList", READING_LIST, {READING_LIST}};
diff --git a/components/sync/driver/model_association_manager.cc b/components/sync/driver/model_association_manager.cc index 5d5ce05..735efe1 100644 --- a/components/sync/driver/model_association_manager.cc +++ b/components/sync/driver/model_association_manager.cc
@@ -47,7 +47,7 @@ SUPERVISED_USER_WHITELISTS, DEPRECATED_WIFI_CREDENTIALS, DEPRECATED_SUPERVISED_USERS, MOUNTAIN_SHARES, DEPRECATED_SUPERVISED_USER_SHARED_SETTINGS, DEPRECATED_ARTICLES, - SEND_TAB_TO_SELF, SECURITY_EVENTS, WIFI_CONFIGURATIONS}; + SEND_TAB_TO_SELF, SECURITY_EVENTS, WEB_APPS, WIFI_CONFIGURATIONS}; static_assert(base::size(kStartOrder) == ModelType::NUM_ENTRIES - FIRST_REAL_MODEL_TYPE,
diff --git a/components/sync/driver/resources/index.html b/components/sync/driver/resources/index.html index d03c356..58b52b4 100644 --- a/components/sync/driver/resources/index.html +++ b/components/sync/driver/resources/index.html
@@ -1,5 +1,5 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <!-- If you change the title, make sure you also update chrome/test/functional/special_tabs.py. -->
diff --git a/components/sync/driver/sync_user_settings_impl.cc b/components/sync/driver/sync_user_settings_impl.cc index ab2aa5702..7782c57 100644 --- a/components/sync/driver/sync_user_settings_impl.cc +++ b/components/sync/driver/sync_user_settings_impl.cc
@@ -182,7 +182,7 @@ types.RetainAll(registered_model_types_); } - static_assert(45 == ModelType::NUM_ENTRIES, + static_assert(46 == ModelType::NUM_ENTRIES, "If adding a new sync data type, update the list below below if" " you want to disable the new data type for local sync."); types.PutAll(ControlTypes());
diff --git a/components/sync/driver/sync_user_settings_unittest.cc b/components/sync/driver/sync_user_settings_unittest.cc index 1d5f017..6a54f3e 100644 --- a/components/sync/driver/sync_user_settings_unittest.cc +++ b/components/sync/driver/sync_user_settings_unittest.cc
@@ -141,6 +141,7 @@ expected_preferred_types.Put(APP_LIST); expected_preferred_types.Put(APP_SETTINGS); expected_preferred_types.Put(ARC_PACKAGE); + expected_preferred_types.Put(WEB_APPS); } if (type == UserSelectableType::kExtensions) { expected_preferred_types.Put(EXTENSION_SETTINGS);
diff --git a/components/sync/nigori/nigori_sync_bridge_impl.cc b/components/sync/nigori/nigori_sync_bridge_impl.cc index 681c379d..31df65a 100644 --- a/components/sync/nigori/nigori_sync_bridge_impl.cc +++ b/components/sync/nigori/nigori_sync_bridge_impl.cc
@@ -306,7 +306,7 @@ void UpdateNigoriSpecificsFromEncryptedTypes( ModelTypeSet encrypted_types, sync_pb::NigoriSpecifics* specifics) { - static_assert(45 == ModelType::NUM_ENTRIES, + static_assert(46 == ModelType::NUM_ENTRIES, "If adding an encryptable type, update handling below."); specifics->set_encrypt_bookmarks(encrypted_types.Has(BOOKMARKS)); specifics->set_encrypt_preferences(encrypted_types.Has(PREFERENCES)); @@ -338,6 +338,7 @@ specifics->set_encrypt_mountain_shares(encrypted_types.Has(MOUNTAIN_SHARES)); specifics->set_encrypt_send_tab_to_self( encrypted_types.Has(SEND_TAB_TO_SELF)); + specifics->set_encrypt_web_apps(encrypted_types.Has(WEB_APPS)); } } // namespace
diff --git a/components/sync/protocol/nigori_specifics.proto b/components/sync/protocol/nigori_specifics.proto index cee80f1..757059a4 100644 --- a/components/sync/protocol/nigori_specifics.proto +++ b/components/sync/protocol/nigori_specifics.proto
@@ -179,4 +179,7 @@ // Boolean corresponding to whether send tab should be encrypted. optional bool encrypt_send_tab_to_self = 47; + + // Boolean corresponding to whether Web Apps data should be encrypted. + optional bool encrypt_web_apps = 48; }
diff --git a/components/sync/protocol/proto_value_conversions.cc b/components/sync/protocol/proto_value_conversions.cc index 089f7d8..e0d1bb5 100644 --- a/components/sync/protocol/proto_value_conversions.cc +++ b/components/sync/protocol/proto_value_conversions.cc
@@ -362,6 +362,7 @@ IMPLEMENT_PROTO_TO_VALUE(WalletMaskedCreditCard) IMPLEMENT_PROTO_TO_VALUE(WalletMetadataSpecifics) IMPLEMENT_PROTO_TO_VALUE(WalletPostalAddress) +IMPLEMENT_PROTO_TO_VALUE(WebAppSpecifics) IMPLEMENT_PROTO_TO_VALUE(WifiConfigurationSpecifics) IMPLEMENT_PROTO_TO_VALUE(WifiCredentialSpecifics)
diff --git a/components/sync/protocol/proto_value_conversions.h b/components/sync/protocol/proto_value_conversions.h index ea0c4c4c..c8ef6867 100644 --- a/components/sync/protocol/proto_value_conversions.h +++ b/components/sync/protocol/proto_value_conversions.h
@@ -78,6 +78,7 @@ class WalletMaskedCreditCard; class WalletMetadataSpecifics; class WalletPostalAddress; +class WebAppSpecifics; class WifiConfigurationSpecifics; class WifiCredentialSpecifics; } // namespace sync_pb @@ -285,6 +286,9 @@ std::unique_ptr<base::DictionaryValue> WalletPostalAddressToValue( const sync_pb::WalletPostalAddress& wallet_postal_address); +std::unique_ptr<base::DictionaryValue> WebAppSpecificsToValue( + const sync_pb::WebAppSpecifics& web_app_specifics); + std::unique_ptr<base::DictionaryValue> WifiConfigurationSpecificsToValue( const sync_pb::WifiConfigurationSpecifics& wifi_configuration_specifics);
diff --git a/components/sync/protocol/proto_value_conversions_unittest.cc b/components/sync/protocol/proto_value_conversions_unittest.cc index 57106a6..72b3320 100644 --- a/components/sync/protocol/proto_value_conversions_unittest.cc +++ b/components/sync/protocol/proto_value_conversions_unittest.cc
@@ -60,7 +60,7 @@ DEFINE_SPECIFICS_TO_VALUE_TEST(encrypted) -static_assert(45 == syncer::ModelType::NUM_ENTRIES, +static_assert(46 == syncer::ModelType::NUM_ENTRIES, "When adding a new field, add a DEFINE_SPECIFICS_TO_VALUE_TEST " "for your field below, and optionally a test for the specific " "conversions."); @@ -105,6 +105,7 @@ DEFINE_SPECIFICS_TO_VALUE_TEST(user_consent) DEFINE_SPECIFICS_TO_VALUE_TEST(user_event) DEFINE_SPECIFICS_TO_VALUE_TEST(wallet_metadata) +DEFINE_SPECIFICS_TO_VALUE_TEST(web_app) DEFINE_SPECIFICS_TO_VALUE_TEST(wifi_configuration) DEFINE_SPECIFICS_TO_VALUE_TEST(wifi_credential)
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h index a86bdd4..c6c2278 100644 --- a/components/sync/protocol/proto_visitors.h +++ b/components/sync/protocol/proto_visitors.h
@@ -41,6 +41,7 @@ #include "components/sync/protocol/unique_position.pb.h" #include "components/sync/protocol/user_consent_specifics.pb.h" #include "components/sync/protocol/user_event_specifics.pb.h" +#include "components/sync/protocol/web_app_specifics.pb.h" // This file implements VisitProtoFields() functions for sync protos. // @@ -371,7 +372,7 @@ } VISIT_PROTO_FIELDS(const sync_pb::EntitySpecifics& proto) { - static_assert(45 == ModelType::NUM_ENTRIES, + static_assert(46 == ModelType::NUM_ENTRIES, "When adding a new protocol type, you will likely need to add " "it here as well."); VISIT(encrypted); @@ -415,6 +416,7 @@ VISIT(user_consent); VISIT(user_event); VISIT(wallet_metadata); + VISIT(web_app); VISIT(wifi_configuration); VISIT(wifi_credential); } @@ -1087,6 +1089,13 @@ VISIT(enabled); } +VISIT_PROTO_FIELDS(const sync_pb::WebAppSpecifics& proto) { + VISIT(app_id); + VISIT(launch_url); + VISIT(name); + VISIT(theme_color); +} + VISIT_PROTO_FIELDS(const sync_pb::WifiCredentialSpecifics& proto) { VISIT_BYTES(ssid); VISIT_ENUM(security_class);
diff --git a/components/sync/protocol/protocol_sources.gni b/components/sync/protocol/protocol_sources.gni index 561c05cd..975c0ca 100644 --- a/components/sync/protocol/protocol_sources.gni +++ b/components/sync/protocol/protocol_sources.gni
@@ -58,6 +58,7 @@ "user_consent_specifics", "user_consent_types", "user_event_specifics", + "web_app_specifics", "wifi_configuration_specifics", "wifi_credential_specifics", ]
diff --git a/components/sync/protocol/sync.proto b/components/sync/protocol/sync.proto index 56734f6..da6f094e 100644 --- a/components/sync/protocol/sync.proto +++ b/components/sync/protocol/sync.proto
@@ -57,6 +57,7 @@ import "unique_position.proto"; import "user_consent_specifics.proto"; import "user_event_specifics.proto"; +import "web_app_specifics.proto"; import "wifi_configuration_specifics.proto"; import "wifi_credential_specifics.proto"; @@ -150,6 +151,7 @@ MountainShareSpecifics mountain_share = 545005; SendTabToSelfSpecifics send_tab_to_self = 601980; SecurityEventSpecifics security_event = 600372; + WebAppSpecifics web_app = 673225; WifiConfigurationSpecifics wifi_configuration = 662827; } }
diff --git a/components/sync/protocol/web_app_specifics.proto b/components/sync/protocol/web_app_specifics.proto new file mode 100644 index 0000000..e7d87bd3 --- /dev/null +++ b/components/sync/protocol/web_app_specifics.proto
@@ -0,0 +1,19 @@ +// Copyright 2019 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. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package sync_pb; + +// WebApp data. This should be a subset of WebAppProto in +// chrome/browser/web_applications/proto/web_app.proto +message WebAppSpecifics { + // app_id is the client tag for sync system. + optional string app_id = 1; + optional string launch_url = 2; + optional string name = 3; + optional uint32 theme_color = 4; +}
diff --git a/components/sync/syncable/nigori_util.cc b/components/sync/syncable/nigori_util.cc index 8229e22..c591696 100644 --- a/components/sync/syncable/nigori_util.cc +++ b/components/sync/syncable/nigori_util.cc
@@ -250,7 +250,7 @@ bool encrypt_everything, sync_pb::NigoriSpecifics* nigori) { nigori->set_encrypt_everything(encrypt_everything); - static_assert(45 == ModelType::NUM_ENTRIES, + static_assert(46 == ModelType::NUM_ENTRIES, "If adding an encryptable type, update handling below."); nigori->set_encrypt_bookmarks(encrypted_types.Has(BOOKMARKS)); nigori->set_encrypt_preferences(encrypted_types.Has(PREFERENCES)); @@ -279,6 +279,7 @@ nigori->set_encrypt_reading_list(encrypted_types.Has(READING_LIST)); nigori->set_encrypt_mountain_shares(encrypted_types.Has(MOUNTAIN_SHARES)); nigori->set_encrypt_send_tab_to_self(encrypted_types.Has(SEND_TAB_TO_SELF)); + nigori->set_encrypt_web_apps(encrypted_types.Has(WEB_APPS)); } ModelTypeSet GetEncryptedTypesFromNigori( @@ -287,7 +288,7 @@ return ModelTypeSet::All(); ModelTypeSet encrypted_types; - static_assert(45 == ModelType::NUM_ENTRIES, + static_assert(46 == ModelType::NUM_ENTRIES, "If adding an encryptable type, update handling below."); if (nigori.encrypt_bookmarks()) encrypted_types.Put(BOOKMARKS); @@ -337,6 +338,8 @@ encrypted_types.Put(MOUNTAIN_SHARES); if (nigori.encrypt_send_tab_to_self()) encrypted_types.Put(SEND_TAB_TO_SELF); + if (nigori.encrypt_web_apps()) + encrypted_types.Put(WEB_APPS); return encrypted_types; }
diff --git a/components/translate/translate_internals/translate_internals.html b/components/translate/translate_internals/translate_internals.html index 061cbcd..d5d896a 100644 --- a/components/translate/translate_internals/translate_internals.html +++ b/components/translate/translate_internals/translate_internals.html
@@ -1,5 +1,5 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <!-- Copyright 2013 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be @@ -12,8 +12,8 @@ <link rel="stylesheet" href="chrome://resources/css/tabs.css"> <link rel="stylesheet" href="./translate_internals.css"> <if expr="is_ios"> - <!-- TODO(crbug.com/487000): Remove this once injected by web. --> - <script src="chrome://resources/js/ios/web_ui.js"></script> + <!-- TODO(crbug.com/487000): Remove this once injected by web. --> + <script src="chrome://resources/js/ios/web_ui.js"></script> </if> <script src="chrome://resources/js/util.js"></script> <script src="chrome://resources/js/cr.js"></script>
diff --git a/components/viz/test/test_context_provider.cc b/components/viz/test/test_context_provider.cc index 7dd29e0..0e1378c4 100644 --- a/components/viz/test/test_context_provider.cc +++ b/components/viz/test/test_context_provider.cc
@@ -277,8 +277,19 @@ std::unique_ptr<TestContextSupport> support, std::unique_ptr<TestGLES2Interface> gl, bool support_locking) + : TestContextProvider(std::move(support), + std::move(gl), + /*raster=*/nullptr, + support_locking) {} + +TestContextProvider::TestContextProvider( + std::unique_ptr<TestContextSupport> support, + std::unique_ptr<TestGLES2Interface> gl, + std::unique_ptr<gpu::raster::RasterInterface> raster, + bool support_locking) : support_(std::move(support)), context_gl_(std::move(gl)), + raster_context_(std::move(raster)), shared_image_interface_(std::make_unique<TestSharedImageInterface>()), support_locking_(support_locking), weak_ptr_factory_(this) { @@ -286,8 +297,10 @@ DCHECK(context_gl_); context_thread_checker_.DetachFromThread(); context_gl_->set_test_support(support_.get()); - raster_context_ = std::make_unique<gpu::raster::RasterImplementationGLES>( - context_gl_.get()); + if (!raster_context_) { + raster_context_ = std::make_unique<gpu::raster::RasterImplementationGLES>( + context_gl_.get()); + } // Just pass nullptr to the ContextCacheController for its task runner. // Idle handling is tested directly in ContextCacheController's // unittests, and isn't needed here.
diff --git a/components/viz/test/test_context_provider.h b/components/viz/test/test_context_provider.h index cc2d5e26..fbbd098 100644 --- a/components/viz/test/test_context_provider.h +++ b/components/viz/test/test_context_provider.h
@@ -119,6 +119,11 @@ std::unique_ptr<TestContextSupport> support, std::unique_ptr<TestGLES2Interface> gl, bool support_locking); + explicit TestContextProvider( + std::unique_ptr<TestContextSupport> support, + std::unique_ptr<TestGLES2Interface> gl, + std::unique_ptr<gpu::raster::RasterInterface> raster, + bool support_locking); // ContextProvider / RasterContextProvider implementation. void AddRef() const override;
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc index 59214415..f832e1bee 100644 --- a/content/browser/accessibility/browser_accessibility_manager_win.cc +++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -252,6 +252,7 @@ FireWinAccessibilityEvent(EVENT_OBJECT_SHOW, node); FireUiaStructureChangedEvent(StructureChangeType_ChildAdded, node); } + aria_properties_events_.insert(node); break; case ui::AXEventGenerator::Event::IMAGE_ANNOTATION_CHANGED: FireWinAccessibilityEvent(EVENT_OBJECT_NAMECHANGE, node); @@ -463,10 +464,16 @@ return; if (!ShouldFireEventForNode(node)) return; - // Suppress events when |IGNORED_CHANGED| + + // Suppress events when |IGNORED_CHANGED| with the exception for firing + // UIA_AriaPropertiesPropertyId-hidden event on non-text node marked as + // ignored. if (node->HasState(ax::mojom::State::kIgnored) || - base::Contains(ignored_changed_nodes_, node)) - return; + base::Contains(ignored_changed_nodes_, node)) { + if (uia_property != UIA_AriaPropertiesPropertyId || + node->IsTextOnlyObject()) + return; + } // The old value is not used by the system VARIANT old_value = {};
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc index e67dd7dd..5c99258 100644 --- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -283,6 +283,11 @@ } IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest, + AccessibilityEventsAriaHiddenChanged) { + RunEventTest(FILE_PATH_LITERAL("aria-hidden-changed.html")); +} + +IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest, AccessibilityEventsAriaInvalidChanged) { RunEventTest(FILE_PATH_LITERAL("aria-invalid-changed.html")); } @@ -721,6 +726,11 @@ RunEventTest(FILE_PATH_LITERAL("tbody-focus.html")); } +IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest, + AccessibilityEventsVisibilityHiddenChanged) { + RunEventTest(FILE_PATH_LITERAL("visibility-hidden-changed.html")); +} + // Even with the deflaking in WaitForAccessibilityTreeToContainNodeWithName, // this test is still flaky on Windows. // TODO(aboxhall, dmazzoni, meredithl): re-enable with better fix for above.
diff --git a/content/browser/appcache/appcache_database.cc b/content/browser/appcache/appcache_database.cc index 2f63fdd..b3a1698 100644 --- a/content/browser/appcache/appcache_database.cc +++ b/content/browser/appcache/appcache_database.cc
@@ -14,7 +14,6 @@ #include "content/browser/appcache/appcache_backfillers.h" #include "content/browser/appcache/appcache_entry.h" #include "content/browser/appcache/appcache_histograms.h" -#include "content/public/common/content_features.h" #include "sql/database.h" #include "sql/error_delegate_util.h" #include "sql/meta_table.h" @@ -249,15 +248,8 @@ return 0; int64_t origin_usage = 0; - bool padding_enabled = - base::FeatureList::IsEnabled(features::kAppCacheIncludePaddingInQuota); - for (const auto& cache : caches) { - if (padding_enabled) { - origin_usage += cache.cache_size + cache.padding_size; - } else { - origin_usage += cache.cache_size; - } - } + for (const auto& cache : caches) + origin_usage += cache.cache_size + cache.padding_size; return origin_usage; }
diff --git a/content/browser/appcache/appcache_database.h b/content/browser/appcache/appcache_database.h index 99d5b011..0472d255 100644 --- a/content/browser/appcache/appcache_database.h +++ b/content/browser/appcache/appcache_database.h
@@ -42,8 +42,7 @@ FORWARD_DECLARE_TEST(AppCacheDatabaseTest, OnlineWhiteListRecords); FORWARD_DECLARE_TEST(AppCacheDatabaseTest, ReCreate); FORWARD_DECLARE_TEST(AppCacheDatabaseTest, DeletableResponseIds); -FORWARD_DECLARE_TEST(AppCacheDatabaseTest, OriginUsageWithPaddingDisabled); -FORWARD_DECLARE_TEST(AppCacheDatabaseTest, OriginUsageWithPaddingEnabled); +FORWARD_DECLARE_TEST(AppCacheDatabaseTest, OriginUsage); FORWARD_DECLARE_TEST(AppCacheDatabaseTest, FindCachesForOrigin); FORWARD_DECLARE_TEST(AppCacheDatabaseTest, UpgradeSchemaForVersionsWithoutSupportedMigrations); @@ -273,10 +272,7 @@ OnlineWhiteListRecords); FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, ReCreate); FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, DeletableResponseIds); - FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, - OriginUsageWithPaddingDisabled); - FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, - OriginUsageWithPaddingEnabled); + FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, OriginUsage); FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, FindCachesForOrigin); FRIEND_TEST_ALL_PREFIXES(content::AppCacheDatabaseTest, UpgradeSchemaForVersionsWithoutSupportedMigrations);
diff --git a/content/browser/appcache/appcache_database_unittest.cc b/content/browser/appcache/appcache_database_unittest.cc index 0960822..037bb647 100644 --- a/content/browser/appcache/appcache_database_unittest.cc +++ b/content/browser/appcache/appcache_database_unittest.cc
@@ -11,10 +11,8 @@ #include "base/files/scoped_temp_dir.h" #include "base/macros.h" #include "base/strings/stringprintf.h" -#include "base/test/scoped_feature_list.h" #include "content/browser/appcache/appcache_database.h" #include "content/browser/appcache/appcache_entry.h" -#include "content/public/common/content_features.h" #include "sql/database.h" #include "sql/meta_table.h" #include "sql/statement.h" @@ -767,75 +765,7 @@ ASSERT_TRUE(expecter.SawExpectedErrors()); } -TEST(AppCacheDatabaseTest, OriginUsageWithPaddingDisabled) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(features::kAppCacheIncludePaddingInQuota); - - const GURL kManifestUrl("http://blah/manifest"); - const GURL kManifestUrl2("http://blah/manifest2"); - const url::Origin kOrigin = url::Origin::Create(kManifestUrl); - const GURL kOtherOriginManifestUrl("http://other/manifest"); - const url::Origin kOtherOrigin = url::Origin::Create(kOtherOriginManifestUrl); - - const base::FilePath kEmptyPath; - AppCacheDatabase db(kEmptyPath); - EXPECT_TRUE(db.LazyOpen(true)); - - std::vector<AppCacheDatabase::CacheRecord> cache_records; - EXPECT_EQ(0, db.GetOriginUsage(kOrigin)); - - AppCacheDatabase::GroupRecord group_record; - group_record.group_id = 1; - group_record.manifest_url = kManifestUrl; - group_record.origin = kOrigin; - EXPECT_TRUE(db.InsertGroup(&group_record)); - AppCacheDatabase::CacheRecord cache_record; - cache_record.cache_id = 1; - cache_record.group_id = 1; - cache_record.online_wildcard = true; - cache_record.update_time = kZeroTime; - cache_record.cache_size = 100; - cache_record.padding_size = 1; - EXPECT_TRUE(db.InsertCache(&cache_record)); - - EXPECT_EQ(100, db.GetOriginUsage(kOrigin)); - - group_record.group_id = 2; - group_record.manifest_url = kManifestUrl2; - group_record.origin = kOrigin; - EXPECT_TRUE(db.InsertGroup(&group_record)); - cache_record.cache_id = 2; - cache_record.group_id = 2; - cache_record.online_wildcard = true; - cache_record.update_time = kZeroTime; - cache_record.cache_size = 1000; - cache_record.padding_size = 1; - EXPECT_TRUE(db.InsertCache(&cache_record)); - - EXPECT_EQ(1100, db.GetOriginUsage(kOrigin)); - - group_record.group_id = 3; - group_record.manifest_url = kOtherOriginManifestUrl; - group_record.origin = kOtherOrigin; - EXPECT_TRUE(db.InsertGroup(&group_record)); - cache_record.cache_id = 3; - cache_record.group_id = 3; - cache_record.online_wildcard = true; - cache_record.update_time = kZeroTime; - cache_record.cache_size = 5000; - cache_record.padding_size = 1; - EXPECT_TRUE(db.InsertCache(&cache_record)); - - EXPECT_EQ(5000, db.GetOriginUsage(kOtherOrigin)); - - std::map<url::Origin, int64_t> usage_map; - EXPECT_TRUE(db.GetAllOriginUsage(&usage_map)); - EXPECT_EQ(2U, usage_map.size()); - EXPECT_EQ(1100, usage_map[kOrigin]); - EXPECT_EQ(5000, usage_map[kOtherOrigin]); -} - -TEST(AppCacheDatabaseTest, OriginUsageWithPaddingEnabled) { +TEST(AppCacheDatabaseTest, OriginUsage) { const GURL kManifestUrl("http://blah/manifest"); const GURL kManifestUrl2("http://blah/manifest2"); const url::Origin kOrigin = url::Origin::Create(kManifestUrl);
diff --git a/content/browser/appcache/appcache_storage.h b/content/browser/appcache/appcache_storage.h index 73f8fc4..7d6ad74 100644 --- a/content/browser/appcache/appcache_storage.h +++ b/content/browser/appcache/appcache_storage.h
@@ -328,7 +328,7 @@ int64_t last_group_id_; int64_t last_response_id_; - // Maps origin to usage (includes padding, unless padding feature is disabled) + // Maps origin to padded usage. std::map<url::Origin, int64_t> usage_map_; AppCacheWorkingSet working_set_; AppCacheServiceImpl* service_;
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc index 038244f..64123ec 100644 --- a/content/browser/appcache/appcache_storage_impl_unittest.cc +++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -37,7 +37,6 @@ #include "content/browser/appcache/appcache_url_loader_request.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/public/browser/browser_task_traits.h" -#include "content/public/common/content_features.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread_bundle.h" #include "net/base/net_errors.h" @@ -566,34 +565,6 @@ storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate()); } - void StoreNewGroup_PaddingDisabled() { - // Store a group and its newest cache. Should complete asynchronously. - PushNextTask(base::BindOnce(&AppCacheStorageImplTest::Verify_StoreNewGroup, - base::Unretained(this))); - - // Set up some preconditions. Create a group and newest cache that - // appear to be "unstored" and big enough to exceed the 5M limit. - const int64_t kTooBig = 10 * 1024 * 1024; // 10M - group_ = base::MakeRefCounted<AppCacheGroup>(storage(), kManifestUrl, - storage()->NewGroupId()); - cache_ = base::MakeRefCounted<AppCache>(storage(), storage()->NewCacheId()); - cache_->AddEntry(kEntryUrl, - AppCacheEntry(AppCacheEntry::EXPLICIT, - /*response_id=*/1, - /*response_size=*/kDefaultEntrySize, - /*padding_size=*/kTooBig)); - // Hold a ref to the cache to simulate the UpdateJob holding that ref, - // and hold a ref to the group to simulate the CacheHost holding that ref. - - // Have the quota manager return asynchronously for this test. - mock_quota_manager_proxy_->mock_manager_->async_ = true; - - // Conduct the store test. The records should commit successfully even - // though the padding size exceeds the limit since the test disabled the - // padding feature flag. - storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate()); - } - void Verify_StoreNewGroup() { EXPECT_TRUE(delegate()->stored_group_success_); EXPECT_EQ(group_.get(), delegate()->stored_group_.get()); @@ -1945,12 +1916,6 @@ RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup); } -TEST_F(AppCacheStorageImplTest, StoreNewGroup_PaddingDisabled) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature(features::kAppCacheIncludePaddingInQuota); - RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup_PaddingDisabled); -} - TEST_F(AppCacheStorageImplTest, StoreExistingGroup) { RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup); }
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h index 8514757..315d5813 100644 --- a/content/browser/bad_message.h +++ b/content/browser/bad_message.h
@@ -243,6 +243,7 @@ RFHI_BEGIN_NAVIGATION_NON_WEBBY_TRANSITION = 215, RFH_NO_MATCHING_NAVIGATION_REQUEST_ON_COMMIT = 216, AUTH_INVALID_ICON_URL = 217, + REGISTER_PROTOCOL_HANDLER_INVALID_URL = 218, // Please add new elements here. The naming convention is abbreviated class // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc index 7978e38..36e2898 100644 --- a/content/browser/child_process_security_policy_impl.cc +++ b/content/browser/child_process_security_policy_impl.cc
@@ -1626,10 +1626,10 @@ if (matches_browsing_instance_id && IsolatedOriginUtil::DoesOriginMatchIsolatedOrigin( origin, isolated_origin_entry.origin())) { - // If a match has been found that requires all subdomains to be - // isolated then return immediately. |origin| is returned to ensure - // proper process isolation, e.g. https://a.b.c.isolated.com matches - // an IsolatedOriginEntry constructed from http://**.isolated.com, so + // If a match has been found that requires all subdomains to be isolated + // then return immediately. |origin| is returned to ensure proper + // process isolation, e.g. https://a.b.c.isolated.com matches an + // IsolatedOriginEntry constructed from http://[*.]isolated.com, so // https://a.b.c.isolated.com must be returned. if (isolated_origin_entry.isolate_all_subdomains()) { *result = origin;
diff --git a/content/browser/child_process_security_policy_unittest.cc b/content/browser/child_process_security_policy_unittest.cc index 1a701a3..263e804 100644 --- a/content/browser/child_process_security_policy_unittest.cc +++ b/content/browser/child_process_security_policy_unittest.cc
@@ -1439,8 +1439,8 @@ TEST_F(ChildProcessSecurityPolicyTest, IsolateAllSuborigins) { url::Origin qux = url::Origin::Create(GURL("https://qux.com/")); - IsolatedOriginPattern etld1_wild("https://**.foo.com"); - IsolatedOriginPattern etld2_wild("https://**.bar.foo.com"); + IsolatedOriginPattern etld1_wild("https://[*.]foo.com"); + IsolatedOriginPattern etld2_wild("https://[*.]bar.foo.com"); url::Origin etld1 = url::Origin::Create(GURL("https://foo.com")); url::Origin etld2 = url::Origin::Create(GURL("https://bar.foo.com")); @@ -1498,8 +1498,8 @@ // Construct a simple case, a single isolated origin. // IsolatedOriginPattern isolated("https://isolated.com"); IsolatedOriginPattern inner_isolated("https://inner.isolated.com"); - IsolatedOriginPattern wildcard("https://**.wildcard.com"); - IsolatedOriginPattern inner_wildcard("https://**.inner.wildcard.com"); + IsolatedOriginPattern wildcard("https://[*.]wildcard.com"); + IsolatedOriginPattern inner_wildcard("https://[*.]inner.wildcard.com"); GURL isolated_url("https://isolated.com"); GURL inner_isolated_url("https://inner.isolated.com"); @@ -1565,7 +1565,8 @@ // isolated origin. Removing the isolated origin should have no effect on // the wildcard origin. IsolatedOriginPattern isolated("https://isolated.com"); - IsolatedOriginPattern wildcard_isolated("https://**.wildcard.isolated.com"); + IsolatedOriginPattern wildcard_isolated( + "https://[*.]wildcard.isolated.com"); GURL isolated_url("https://isolated.com"); GURL a_isolated_url("https://a.isolated.com"); @@ -1594,7 +1595,7 @@ { // A single isolated origin is nested within a wildcard origin. In this // scenario the wildcard origin supersedes isolated origins. - IsolatedOriginPattern wildcard("https://**.wildcard.com"); + IsolatedOriginPattern wildcard("https://[*.]wildcard.com"); IsolatedOriginPattern isolated_wildcard("https://isolated.wildcard.com"); GURL wildcard_url("https://wildcard.com"); @@ -1623,8 +1624,8 @@ { // Nest wildcard isolated origins within each other. Verify that removing // the outer wildcard origin doesn't affect the inner one. - IsolatedOriginPattern outer("https://**.outer.com"); - IsolatedOriginPattern inner("https://**.inner.outer.com"); + IsolatedOriginPattern outer("https://[*.]outer.com"); + IsolatedOriginPattern inner("https://[*.]inner.outer.com"); GURL outer_url("https://outer.com"); GURL a_outer_url("https://a.outer.com"); @@ -1652,7 +1653,7 @@ // doesn't affect the isolating behavior of the wildcard, i.e. whichever // isolated domain is added entered 'wins'. { - IsolatedOriginPattern wild("https://**.bar.foo.com"); + IsolatedOriginPattern wild("https://[*.]bar.foo.com"); IsolatedOriginPattern single("https://bar.foo.com"); GURL host_url("https://host.bar.foo.com"); @@ -1678,7 +1679,7 @@ // Verify the first domain added remains dominant in the case of differing // wildcard and non-wildcard statuses. { - IsolatedOriginPattern wild("https://**.bar.foo.com"); + IsolatedOriginPattern wild("https://[*.]bar.foo.com"); IsolatedOriginPattern single("https://bar.foo.com"); GURL host_url("https://host.bar.foo.com"); @@ -2118,14 +2119,14 @@ } TEST_F(ChildProcessSecurityPolicyTest, IsolatedOriginPattern) { - const base::StringPiece etld1_wild("https://**.foo.com"); + const base::StringPiece etld1_wild("https://[*.]foo.com"); url::Origin etld1_wild_origin = url::Origin::Create(GURL("https://foo.com")); IsolatedOriginPattern p(etld1_wild); EXPECT_TRUE(p.isolate_all_subdomains()); EXPECT_TRUE(p.is_valid()); EXPECT_EQ(p.origin(), etld1_wild_origin); - const base::StringPiece etld2_wild("https://**.bar.foo.com"); + const base::StringPiece etld2_wild("https://[*.]bar.foo.com"); url::Origin etld2_wild_origin = url::Origin::Create(GURL("https://bar.foo.com")); bool result = p.Parse(etld2_wild); @@ -2181,7 +2182,7 @@ EXPECT_TRUE(p.is_valid()); EXPECT_EQ(p.origin(), ip_origin); - const base::StringPiece wild_ip_addr("https://**.10.20.30.40"); + const base::StringPiece wild_ip_addr("https://[*.]10.20.30.40"); result = p.Parse(wild_ip_addr); EXPECT_FALSE(result); EXPECT_FALSE(p.isolate_all_subdomains()); @@ -2304,9 +2305,9 @@ EXPECT_EQ(IsolatedOriginPattern(foo), IsolatedOriginPattern(foo_port)); EXPECT_EQ(IsolatedOriginPattern(foo), IsolatedOriginPattern(foo_path)); - std::string wild_foo("https://**.foo.com"); - std::string wild_foo_port("https://**.foo.com:8000"); - std::string wild_foo_path("https://**.foo.com/some/path"); + std::string wild_foo("https://[*.]foo.com"); + std::string wild_foo_port("https://[*.]foo.com:8000"); + std::string wild_foo_path("https://[*.]foo.com/some/path"); EXPECT_EQ(IsolatedOriginPattern(wild_foo), IsolatedOriginPattern(wild_foo_port)); @@ -2347,14 +2348,14 @@ // A single wildcard origin. EXPECT_THAT( ChildProcessSecurityPolicyImpl::ParseIsolatedOrigins( - "https://**.wild.foo.com"), - testing::ElementsAre(IsolatedOriginPattern("https://**.wild.foo.com"))); + "https://[*.]wild.foo.com"), + testing::ElementsAre(IsolatedOriginPattern("https://[*.]wild.foo.com"))); // A mixture of wildcard and non-wildcard origins. EXPECT_THAT( ChildProcessSecurityPolicyImpl::ParseIsolatedOrigins( - "https://**.wild.foo.com,https://isolated.foo.com"), - testing::ElementsAre(IsolatedOriginPattern("https://**.wild.foo.com"), + "https://[*.]wild.foo.com,https://isolated.foo.com"), + testing::ElementsAre(IsolatedOriginPattern("https://[*.]wild.foo.com"), IsolatedOriginPattern("https://isolated.foo.com"))); } @@ -2373,7 +2374,7 @@ url::Origin wild_with_port = url::Origin::Create(GURL("https://a.wild.com:5678")); url::Origin wild_origin = url::Origin::Create(GURL("https://a.wild.com")); - IsolatedOriginPattern wild_pattern("https://**.wild.com:5678"); + IsolatedOriginPattern wild_pattern("https://[*.]wild.com:5678"); p->AddIsolatedOrigins({isolated_origin_with_port}, IsolatedOriginSource::TEST);
diff --git a/content/browser/download/mhtml_generation_browsertest.cc b/content/browser/download/mhtml_generation_browsertest.cc index 0f10768..7c3693b 100644 --- a/content/browser/download/mhtml_generation_browsertest.cc +++ b/content/browser/download/mhtml_generation_browsertest.cc
@@ -141,7 +141,9 @@ // This Mock injects our overwritten interface, running the callback // SerializeAsMHTMLResponse and immediately disconnecting the message pipe. -class RespondAndDisconnectMockWriter : public MockWriterBase { +class RespondAndDisconnectMockWriter + : public MockWriterBase, + public base::RefCountedThreadSafe<RespondAndDisconnectMockWriter> { public: RespondAndDisconnectMockWriter() {} @@ -232,26 +234,32 @@ // as there can be at most two watcher invocations to write a block of // data smaller than the data pipe buffer to file. download::GetDownloadTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&RespondAndDisconnectMockWriter::TaskX, - base::Unretained(this))); + FROM_HERE, + base::BindOnce(&RespondAndDisconnectMockWriter::TaskX, + scoped_refptr<RespondAndDisconnectMockWriter>(this))); } void TaskX() { download::GetDownloadTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&RespondAndDisconnectMockWriter::TaskY, - base::Unretained(this))); + FROM_HERE, + base::BindOnce(&RespondAndDisconnectMockWriter::TaskY, + scoped_refptr<RespondAndDisconnectMockWriter>(this))); } void TaskY() { base::PostTaskWithTraits( FROM_HERE, {BrowserThread::UI}, base::BindOnce(&RespondAndDisconnectMockWriter::TaskZ, - base::Unretained(this))); + scoped_refptr<RespondAndDisconnectMockWriter>(this))); } void TaskZ() { binding_.Unbind(); } private: + friend base::RefCountedThreadSafe<RespondAndDisconnectMockWriter>; + + ~RespondAndDisconnectMockWriter() override = default; + DISALLOW_COPY_AND_ASSIGN(RespondAndDisconnectMockWriter); }; @@ -467,13 +475,14 @@ #endif IN_PROC_BROWSER_TEST_P(MHTMLGenerationTest, MAYBE_GenerateMHTMLAndCloseConnection) { - RespondAndDisconnectMockWriter mock_writer; + scoped_refptr<RespondAndDisconnectMockWriter> mock_writer = + base::MakeRefCounted<RespondAndDisconnectMockWriter>(); NavigateToURL(shell(), embedded_test_server()->GetURL("/simple_page.html")); base::FilePath path(temp_dir_.GetPath()); path = path.Append(FILE_PATH_LITERAL("test.mht")); - OverrideInterface(&mock_writer); + OverrideInterface(mock_writer.get()); DisableWellformednessCheck(); MHTMLGenerationParams params(path);
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc index 8872b1e..7b662fb 100644 --- a/content/browser/isolated_origin_browsertest.cc +++ b/content/browser/isolated_origin_browsertest.cc
@@ -2715,11 +2715,11 @@ } private: - const char* kAllSubdomainWildcard = "**."; + const char* kAllSubdomainWildcard = "[*.]"; // Calling GetURL() on the embedded test server will escape any '*' characters // into '%2A', so to create a wildcard origin they must be post-processed to - // have the string '**.' inserted at the correct point. + // have the string '[*.]' inserted at the correct point. std::string MakeWildcard(GURL url) { DCHECK(url.is_valid()); return url.scheme() + url::kStandardSchemeSeparator +
diff --git a/content/browser/isolated_origin_util.cc b/content/browser/isolated_origin_util.cc index 07cfb127..3d6770e8 100644 --- a/content/browser/isolated_origin_util.cc +++ b/content/browser/isolated_origin_util.cc
@@ -10,7 +10,7 @@ #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "url/gurl.h" -const char* kAllSubdomainsWildcard = "**."; +const char* kAllSubdomainsWildcard = "[*.]"; namespace content {
diff --git a/content/browser/isolated_origin_util.h b/content/browser/isolated_origin_util.h index 7721104..9486db2 100644 --- a/content/browser/isolated_origin_util.h +++ b/content/browser/isolated_origin_util.h
@@ -14,7 +14,7 @@ namespace content { // This class holds isolated origin patterns, providing support for double -// wildcard origins, e.g. https://**.foo.com indicates that all domains under +// wildcard origins, e.g. https://[*.]foo.com indicates that all domains under // foo.com are to be treated as if they are distinct isolated // origins. Non-wildcard origins to be isolated are also supported, e.g. // https://bar.com. @@ -47,8 +47,8 @@ // this oriqin will be opaque. const url::Origin& origin() const { return origin_; } - // True if the supplied pattern was of the form https://**.foo.com, indicating - // all subdomains of foo.com are to be isolated. + // True if the supplied pattern was of the form https://[*.]foo.com, + // indicating all subdomains of foo.com are to be isolated. bool isolate_all_subdomains() const { return isolate_all_subdomains_; } // Return the original pattern used to construct this instance.
diff --git a/content/browser/renderer_host/render_widget_targeter.cc b/content/browser/renderer_host/render_widget_targeter.cc index 0749033..50bc7544d 100644 --- a/content/browser/renderer_host/render_widget_targeter.cc +++ b/content/browser/renderer_host/render_widget_targeter.cc
@@ -5,6 +5,8 @@ #include "content/browser/renderer_host/render_widget_targeter.h" #include "base/bind.h" +#include "base/debug/crash_logging.h" +#include "base/debug/dump_without_crashing.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" @@ -12,8 +14,10 @@ #include "components/viz/host/host_frame_sink_manager.h" #include "content/browser/compositor/surface_utils.h" #include "content/browser/renderer_host/input/one_shot_timeout_monitor.h" +#include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/site_isolation_policy.h" #include "third_party/blink/public/platform/web_input_event.h" #include "ui/events/blink/blink_event_util.h" @@ -51,6 +55,29 @@ constexpr const char kTracingCategory[] = "input,latency"; +// This function helps with debugging the reasons of viz hit testing mismatch. +void DumpWithoutCrashing(RenderWidgetHostViewBase* root_view, + RenderWidgetHostViewBase* target, + const base::Optional<gfx::PointF>& target_location) { + RenderViewHostImpl* rvh = + RenderViewHostImpl::From(root_view->GetRenderWidgetHost()); + if (!rvh || !rvh->GetMainFrame()) + return; + static auto* crash_key = base::debug::AllocateCrashKeyString( + "vizhittest-mismatch-v2-url", base::debug::CrashKeySize::Size256); + const std::string& url = + rvh->GetMainFrame()->GetLastCommittedURL().GetOrigin().spec(); + base::debug::SetCrashKeyString(crash_key, url); + + crash_key = base::debug::AllocateCrashKeyString( + "vizhittest-mismatch-v2-coordinate", base::debug::CrashKeySize::Size32); + const std::string& global_coordinate = + target->TransformPointToRootCoordSpaceF(target_location.value()) + .ToString(); + base::debug::SetCrashKeyString(crash_key, global_coordinate); + base::debug::DumpWithoutCrashing(); +} + } // namespace class TracingUmaTracker { @@ -455,6 +482,7 @@ // If the result did not change, it is likely that viz hit test finds // the wrong target. match_result = HitTestResultsMatch::kDoNotMatch; + DumpWithoutCrashing(root_view, target, target_location); } else { // Hit test data changed, so the result is no longer reliable. match_result = HitTestResultsMatch::kHitTestResultChanged;
diff --git a/content/browser/resources/appcache/appcache_internals.html b/content/browser/resources/appcache/appcache_internals.html index 7dfd489..d3c3d36 100644 --- a/content/browser/resources/appcache/appcache_internals.html +++ b/content/browser/resources/appcache/appcache_internals.html
@@ -4,7 +4,7 @@ found in the LICENSE file. --> <!DOCTYPE html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <title>AppCache</title>
diff --git a/content/browser/resources/gpu/gpu_internals.html b/content/browser/resources/gpu/gpu_internals.html index 731ee86c..7995d2b 100644 --- a/content/browser/resources/gpu/gpu_internals.html +++ b/content/browser/resources/gpu/gpu_internals.html
@@ -1,5 +1,5 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <!-- Copyright (c) 2012 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be
diff --git a/content/browser/resources/histograms/histograms_internals.html b/content/browser/resources/histograms/histograms_internals.html index 16a22436..7a9c448c 100644 --- a/content/browser/resources/histograms/histograms_internals.html +++ b/content/browser/resources/histograms/histograms_internals.html
@@ -2,7 +2,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.--> <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <script src="chrome://resources/js/cr.js"></script>
diff --git a/content/browser/resources/indexed_db/indexeddb_internals.html b/content/browser/resources/indexed_db/indexeddb_internals.html index 0b66ea2..30e8a96d 100644 --- a/content/browser/resources/indexed_db/indexeddb_internals.html +++ b/content/browser/resources/indexed_db/indexeddb_internals.html
@@ -1,5 +1,5 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <title>IndexedDB</title>
diff --git a/content/browser/resources/media/media_internals.html b/content/browser/resources/media/media_internals.html index 57c8433..abd3244 100644 --- a/content/browser/resources/media/media_internals.html +++ b/content/browser/resources/media/media_internals.html
@@ -4,7 +4,7 @@ found in the LICENSE file. --> <!DOCTYPE html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1">
diff --git a/content/browser/resources/process/process_internals.html b/content/browser/resources/process/process_internals.html index 07d458c3..25a70ac0 100644 --- a/content/browser/resources/process/process_internals.html +++ b/content/browser/resources/process/process_internals.html
@@ -2,7 +2,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.--> <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
diff --git a/content/browser/resources/service_worker/serviceworker_internals.html b/content/browser/resources/service_worker/serviceworker_internals.html index fc3f6e5..4842288 100644 --- a/content/browser/resources/service_worker/serviceworker_internals.html +++ b/content/browser/resources/service_worker/serviceworker_internals.html
@@ -1,5 +1,5 @@ <!doctype html> -<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <title>chrome://serviceworker-internals</title>
diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h index b06af8e..295dced 100644 --- a/content/browser/service_worker/service_worker_context_core.h +++ b/content/browser/service_worker/service_worker_context_core.h
@@ -161,8 +161,8 @@ // Returns a ProviderHost iterator for all service worker clients for the // |origin|. If |include_reserved_clients| is false, this only returns clients - // that are execution ready (i.e., for windows, the navigation has been - // committed and for workers, the final response after redirects has been + // that are execution ready (i.e., for windows, the document has been + // created and for workers, the final response after redirects has been // delivered). std::unique_ptr<ProviderHostIterator> GetClientProviderHostIterator( const GURL& origin,
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc index 2ac8aa45..92d4d956 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler.cc +++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -60,34 +60,6 @@ } // namespace -// RAII class that disallows calling SetControllerRegistration() on a provider -// host. -class ServiceWorkerControlleeRequestHandler:: - ScopedDisallowSetControllerRegistration { - public: - explicit ScopedDisallowSetControllerRegistration( - base::WeakPtr<ServiceWorkerProviderHost> provider_host) - : provider_host_(std::move(provider_host)) { - DCHECK(provider_host_->IsSetControllerRegistrationAllowed()) - << "The host already disallows using a registration; nested disallow " - "is not supported."; - provider_host_->AllowSetControllerRegistration(false); - } - - ~ScopedDisallowSetControllerRegistration() { - if (!provider_host_) - return; - DCHECK(!provider_host_->IsSetControllerRegistrationAllowed()) - << "Failed to disallow using a registration."; - provider_host_->AllowSetControllerRegistration(true); - } - - private: - base::WeakPtr<ServiceWorkerProviderHost> provider_host_; - - DISALLOW_COPY_AND_ASSIGN(ScopedDisallowSetControllerRegistration); -}; - ServiceWorkerControlleeRequestHandler::ServiceWorkerControlleeRequestHandler( base::WeakPtr<ServiceWorkerContextCore> context, base::WeakPtr<ServiceWorkerProviderHost> provider_host, @@ -155,34 +127,36 @@ } #endif // BUILDFLAG(ENABLE_OFFLINE_PAGES) - loader_wrapper_ = std::make_unique<ServiceWorkerNavigationLoaderWrapper>( - std::make_unique<ServiceWorkerNavigationLoader>( - std::move(callback), std::move(fallback_callback), this, - tentative_resource_request, provider_host_, - base::WrapRefCounted(context_->loader_factory_getter()))); - resource_context_ = resource_context; - PrepareForMainResource(tentative_resource_request.url, - tentative_resource_request.site_for_cookies); + TRACE_EVENT_ASYNC_BEGIN1( + "ServiceWorker", + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, "URL", + tentative_resource_request.url.spec()); + // The provider host may already have set a controller in redirect case, + // unset it now. + provider_host_->SetControllerRegistration( + nullptr, false /* notify_controllerchange */); - if (loader()->ShouldFallbackToNetwork()) { - // The job already fell back to network. Clear the job now. - ClearJob(); - return; - } + loader_callback_ = std::move(callback); + fallback_callback_ = std::move(fallback_callback); + stripped_url_ = net::SimplifyUrlForRequest(tentative_resource_request.url); + provider_host_->UpdateUrls(stripped_url_, + tentative_resource_request.site_for_cookies); + registration_lookup_start_time_ = base::TimeTicks::Now(); - // We will asynchronously continue on DidLookupRegistrationForMainResource. + // Look up a registration. + context_->storage()->FindRegistrationForDocument( + stripped_url_, + base::BindOnce( + &ServiceWorkerControlleeRequestHandler::ContinueWithRegistration, + weak_factory_.GetWeakPtr())); } base::Optional<SubresourceLoaderParams> ServiceWorkerControlleeRequestHandler::MaybeCreateSubresourceLoaderParams() { - // We didn't create URLLoader for this request. - if (!loader()) - return base::nullopt; - - // DidLookupRegistrationForMainResource() for the request didn't find - // a matching service worker for this request, and + // ContinueWithRegistration() for the request didn't find a matching service + // worker for this request, and // ServiceWorkerProviderHost::SetControllerRegistration() was not called. if (!provider_host_ || !provider_host_->controller()) return base::nullopt; @@ -218,97 +192,60 @@ return base::Optional<SubresourceLoaderParams>(std::move(params)); } -void ServiceWorkerControlleeRequestHandler::PrepareForMainResource( - const GURL& url, - const GURL& site_for_cookies) { - DCHECK(loader()); - DCHECK(context_); - DCHECK(provider_host_); - TRACE_EVENT_ASYNC_BEGIN1( - "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, - "URL", url.spec()); - // The provider host may already have set a controller in redirect case, - // unset it now. - provider_host_->SetControllerRegistration( - nullptr, false /* notify_controllerchange */); - - // Also prevent a registration from claiming this host while it's not - // yet execution ready. - auto disallow_controller = - std::make_unique<ScopedDisallowSetControllerRegistration>(provider_host_); - - stripped_url_ = net::SimplifyUrlForRequest(url); - provider_host_->UpdateUrls(stripped_url_, site_for_cookies); - registration_lookup_start_time_ = base::TimeTicks::Now(); - context_->storage()->FindRegistrationForDocument( - stripped_url_, base::BindOnce(&ServiceWorkerControlleeRequestHandler:: - DidLookupRegistrationForMainResource, - weak_factory_.GetWeakPtr(), - std::move(disallow_controller))); -} - -void ServiceWorkerControlleeRequestHandler:: - DidLookupRegistrationForMainResource( - std::unique_ptr<ScopedDisallowSetControllerRegistration> - disallow_controller, - blink::ServiceWorkerStatusCode status, - scoped_refptr<ServiceWorkerRegistration> registration) { - // The job may have been destroyed before this was invoked. - if (!loader()) - return; - +void ServiceWorkerControlleeRequestHandler::ContinueWithRegistration( + blink::ServiceWorkerStatusCode status, + scoped_refptr<ServiceWorkerRegistration> registration) { ServiceWorkerMetrics::RecordLookupRegistrationTime( status, base::TimeTicks::Now() - registration_lookup_start_time_); if (status != blink::ServiceWorkerStatusCode::kOk) { - loader()->FallbackToNetwork(); TRACE_EVENT_ASYNC_END1( "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, "Status", blink::ServiceWorkerStatusToString(status)); + CompleteWithoutLoader(); return; } DCHECK(registration); if (!provider_host_) { - loader()->FallbackToNetwork(); TRACE_EVENT_ASYNC_END1( "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, "Info", "No Provider"); + CompleteWithoutLoader(); return; } provider_host_->AddMatchingRegistration(registration.get()); if (!context_) { - loader()->FallbackToNetwork(); TRACE_EVENT_ASYNC_END1( "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, "Info", "No Context"); + CompleteWithoutLoader(); return; } if (!GetContentClient()->browser()->AllowServiceWorker( registration->scope(), provider_host_->site_for_cookies(), GURL(), resource_context_, provider_host_->web_contents_getter())) { - loader()->FallbackToNetwork(); TRACE_EVENT_ASYNC_END1( "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, "Info", "ServiceWorker is blocked"); + CompleteWithoutLoader(); return; } if (!provider_host_->IsContextSecureForServiceWorker()) { // TODO(falken): Figure out a way to surface in the page's DevTools // console that the service worker was blocked for security. - loader()->FallbackToNetwork(); TRACE_EVENT_ASYNC_END1( "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, "Info", "Insecure context"); + CompleteWithoutLoader(); return; } @@ -321,8 +258,7 @@ true /* skip_script_comparison */, base::BindOnce( &ServiceWorkerControlleeRequestHandler::DidUpdateRegistration, - weak_factory_.GetWeakPtr(), registration, - std::move(disallow_controller))); + weak_factory_.GetWeakPtr(), registration)); return; } @@ -335,11 +271,11 @@ scoped_refptr<ServiceWorkerVersion> active_version = registration->active_version(); if (!active_version) { - loader()->FallbackToNetwork(); TRACE_EVENT_ASYNC_END1( "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, "Info", "No active version, so falling back to network"); + CompleteWithoutLoader(); return; } @@ -348,45 +284,30 @@ << ServiceWorkerVersion::VersionStatusToString(active_version->status()); // Wait until it's activated before firing fetch events. if (active_version->status() == ServiceWorkerVersion::ACTIVATING) { - registration->active_version()->RegisterStatusChangeCallback( - base::BindOnce(&ServiceWorkerControlleeRequestHandler:: - ContinueWithInScopeMainResourceRequest, - weak_factory_.GetWeakPtr(), registration, active_version, - std::move(disallow_controller))); + registration->active_version()->RegisterStatusChangeCallback(base::BindOnce( + &ServiceWorkerControlleeRequestHandler::ContinueWithActivatedVersion, + weak_factory_.GetWeakPtr(), registration, active_version)); TRACE_EVENT_ASYNC_END1( "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, "Info", "Wait until finished SW activation"); return; } - ContinueWithInScopeMainResourceRequest(std::move(registration), - std::move(active_version), - std::move(disallow_controller)); + ContinueWithActivatedVersion(std::move(registration), + std::move(active_version)); } -void ServiceWorkerControlleeRequestHandler:: - ContinueWithInScopeMainResourceRequest( - scoped_refptr<ServiceWorkerRegistration> registration, - scoped_refptr<ServiceWorkerVersion> active_version, - std::unique_ptr<ScopedDisallowSetControllerRegistration> - disallow_controller) { - // The job may have been destroyed before this was invoked. In that - // case, |loader()| can't be used, so return. - if (!loader()) { +void ServiceWorkerControlleeRequestHandler::ContinueWithActivatedVersion( + scoped_refptr<ServiceWorkerRegistration> registration, + scoped_refptr<ServiceWorkerVersion> active_version) { + if (!context_ || !provider_host_) { TRACE_EVENT_ASYNC_END1( "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, - "Info", "The job was destroyed"); - return; - } - - if (!provider_host_) { - loader()->FallbackToNetwork(); - TRACE_EVENT_ASYNC_END1( - "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, - "Info", "The provider host is gone, so falling back to network"); + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, + "Info", + "The context or provider host is gone, so falling back to network"); + CompleteWithoutLoader(); return; } @@ -409,19 +330,18 @@ // retries. // 3) If the provider host does not have an active version, just fail the // load. - loader()->FallbackToNetwork(); TRACE_EVENT_ASYNC_END2( "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, "Info", "The expected active version is not ACTIVATED, so falling back to " "network", "Status", ServiceWorkerVersion::VersionStatusToString(active_version->status())); + CompleteWithoutLoader(); return; } - disallow_controller.reset(); provider_host_->SetControllerRegistration( registration, false /* notify_controllerchange */); @@ -436,37 +356,45 @@ if (IsResourceTypeFrame(resource_type_)) provider_host_->AddServiceWorkerToUpdate(active_version); - bool should_forward = active_version->fetch_handler_existence() == - ServiceWorkerVersion::FetchHandlerExistence::EXISTS; - if (should_forward) - loader()->ForwardToServiceWorker(); - else - loader()->FallbackToNetwork(); + if (active_version->fetch_handler_existence() != + ServiceWorkerVersion::FetchHandlerExistence::EXISTS) { + TRACE_EVENT_ASYNC_END1( + "ServiceWorker", + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, + "Info", "Skipped the ServiceWorker which has no fetch handler"); + CompleteWithoutLoader(); + return; + } + + // Finally, we want to forward to the service worker! Make a + // ServiceWorkerNavigationLoader which does that work. + loader_wrapper_ = std::make_unique<ServiceWorkerNavigationLoaderWrapper>( + std::make_unique<ServiceWorkerNavigationLoader>( + std::move(fallback_callback_), this, provider_host_, + base::WrapRefCounted(context_->loader_factory_getter()))); TRACE_EVENT_ASYNC_END1( "ServiceWorker", - "ServiceWorkerControlleeRequestHandler::PrepareForMainResource", this, - "Info", - (should_forward) - ? "Forwarded to the ServiceWorker" - : "Skipped the ServiceWorker which has no fetch handler"); + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, "Info", + "Forwarded to the ServiceWorker"); + std::move(loader_callback_) + .Run(base::BindOnce(&ServiceWorkerNavigationLoader::StartRequest, + loader_wrapper_->get()->AsWeakPtr())); } void ServiceWorkerControlleeRequestHandler::DidUpdateRegistration( scoped_refptr<ServiceWorkerRegistration> original_registration, - std::unique_ptr<ScopedDisallowSetControllerRegistration> - disallow_controller, blink::ServiceWorkerStatusCode status, const std::string& status_message, int64_t registration_id) { DCHECK(force_update_started_); - // The job may have been destroyed before this was invoked. - if (!loader()) - return; - if (!context_) { - loader()->FallbackToNetwork(); + TRACE_EVENT_ASYNC_END1( + "ServiceWorker", + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, + "Info", "The context is gone in DidUpdateRegistration"); + CompleteWithoutLoader(); return; } if (status != blink::ServiceWorkerStatusCode::kOk || @@ -474,10 +402,10 @@ // Update failed. Look up the registration again since the original // registration was possibly unregistered in the meantime. context_->storage()->FindRegistrationForDocument( - stripped_url_, base::BindOnce(&ServiceWorkerControlleeRequestHandler:: - DidLookupRegistrationForMainResource, - weak_factory_.GetWeakPtr(), - std::move(disallow_controller))); + stripped_url_, + base::BindOnce( + &ServiceWorkerControlleeRequestHandler::ContinueWithRegistration, + weak_factory_.GetWeakPtr())); return; } DCHECK_EQ(original_registration->id(), registration_id); @@ -488,20 +416,18 @@ new_version->RegisterStatusChangeCallback(base::BindOnce( &ServiceWorkerControlleeRequestHandler::OnUpdatedVersionStatusChanged, weak_factory_.GetWeakPtr(), std::move(original_registration), - base::WrapRefCounted(new_version), std::move(disallow_controller))); + base::WrapRefCounted(new_version))); } void ServiceWorkerControlleeRequestHandler::OnUpdatedVersionStatusChanged( scoped_refptr<ServiceWorkerRegistration> registration, - scoped_refptr<ServiceWorkerVersion> version, - std::unique_ptr<ScopedDisallowSetControllerRegistration> - disallow_controller) { - // The job may have been destroyed before this was invoked. - if (!loader()) - return; - + scoped_refptr<ServiceWorkerVersion> version) { if (!context_) { - loader()->FallbackToNetwork(); + TRACE_EVENT_ASYNC_END1( + "ServiceWorker", + "ServiceWorkerControlleeRequestHandler::MaybeCreateLoader", this, + "Info", "The context is gone in OnUpdatedVersionStatusChanged"); + CompleteWithoutLoader(); return; } if (version->status() == ServiceWorkerVersion::ACTIVATED || @@ -510,16 +436,15 @@ // continue with the incumbent version. // In case unregister job may have run, look up the registration again. context_->storage()->FindRegistrationForDocument( - stripped_url_, base::BindOnce(&ServiceWorkerControlleeRequestHandler:: - DidLookupRegistrationForMainResource, - weak_factory_.GetWeakPtr(), - std::move(disallow_controller))); + stripped_url_, + base::BindOnce( + &ServiceWorkerControlleeRequestHandler::ContinueWithRegistration, + weak_factory_.GetWeakPtr())); return; } version->RegisterStatusChangeCallback(base::BindOnce( &ServiceWorkerControlleeRequestHandler::OnUpdatedVersionStatusChanged, - weak_factory_.GetWeakPtr(), std::move(registration), version, - std::move(disallow_controller))); + weak_factory_.GetWeakPtr(), std::move(registration), version)); } ServiceWorkerVersion* @@ -551,4 +476,8 @@ loader_wrapper_.reset(); } +void ServiceWorkerControlleeRequestHandler::CompleteWithoutLoader() { + std::move(loader_callback_).Run({}); +} + } // namespace content
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.h b/content/browser/service_worker/service_worker_controllee_request_handler.h index 3d819e6..5b53366 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler.h +++ b/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -6,6 +6,7 @@ #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTROLLEE_REQUEST_HANDLER_H_ #include <stdint.h> + #include <memory> #include <string> @@ -18,6 +19,7 @@ #include "content/common/content_export.h" #include "content/common/service_worker/service_worker_types.h" #include "content/public/common/resource_type.h" +#include "services/network/public/cpp/resource_request.h" #include "services/network/public/mojom/fetch_api.mojom.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h" #include "url/gurl.h" @@ -66,35 +68,23 @@ private: FRIEND_TEST_ALL_PREFIXES(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion); - class ScopedDisallowSetControllerRegistration; - // TODO(falken): Remove the "MainResource" names, they are redundant as this - // handler is for main resources only. - void PrepareForMainResource(const GURL& url, const GURL& site_for_cookies); - void DidLookupRegistrationForMainResource( - std::unique_ptr<ScopedDisallowSetControllerRegistration> - disallow_controller, + void ContinueWithRegistration( blink::ServiceWorkerStatusCode status, scoped_refptr<ServiceWorkerRegistration> registration); - void ContinueWithInScopeMainResourceRequest( + void ContinueWithActivatedVersion( scoped_refptr<ServiceWorkerRegistration> registration, - scoped_refptr<ServiceWorkerVersion> version, - std::unique_ptr<ScopedDisallowSetControllerRegistration> - disallow_controller); + scoped_refptr<ServiceWorkerVersion> version); // For forced update. void DidUpdateRegistration( scoped_refptr<ServiceWorkerRegistration> original_registration, - std::unique_ptr<ScopedDisallowSetControllerRegistration> - disallow_controller, blink::ServiceWorkerStatusCode status, const std::string& status_message, int64_t registration_id); void OnUpdatedVersionStatusChanged( scoped_refptr<ServiceWorkerRegistration> registration, - scoped_refptr<ServiceWorkerVersion> version, - std::unique_ptr<ScopedDisallowSetControllerRegistration> - disallow_controller); + scoped_refptr<ServiceWorkerVersion> version); // ServiceWorkerNavigationLoader::Delegate implementation: ServiceWorkerVersion* GetServiceWorkerVersion() override; @@ -105,6 +95,8 @@ // that job, except for timing information. void ClearJob(); + void CompleteWithoutLoader(); + // Schedules a service worker update to occur shortly after the page and its // initial subresources load, if this handler was for a navigation. void MaybeScheduleUpdate(); @@ -118,6 +110,9 @@ bool force_update_started_; base::TimeTicks registration_lookup_start_time_; + LoaderCallback loader_callback_; + FallbackCallback fallback_callback_; + base::WeakPtrFactory<ServiceWorkerControlleeRequestHandler> weak_factory_; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerControlleeRequestHandler);
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc index 1baf2c31..b38c8e23 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc +++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -19,7 +19,6 @@ #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_registration.h" -#include "content/browser/service_worker/service_worker_response_type.h" #include "content/browser/service_worker/service_worker_test_utils.h" #include "content/common/service_worker/service_worker_types.h" #include "content/public/browser/resource_context.h" @@ -58,16 +57,17 @@ test->provider_host_, type)) {} - ServiceWorkerNavigationLoader* MaybeCreateLoader() { + void MaybeCreateLoader() { network::ResourceRequest resource_request; resource_request.url = request_->url(); resource_request.resource_type = static_cast<int>(resource_type_); resource_request.headers = request()->extra_request_headers(); handler_->MaybeCreateLoader(resource_request, nullptr, nullptr, base::DoNothing(), base::DoNothing()); - return handler_->loader(); } + ServiceWorkerNavigationLoader* loader() { return handler_->loader(); } + void ResetHandler() { handler_.reset(nullptr); } net::URLRequest* request() const { return request_.get(); } @@ -185,16 +185,12 @@ // Conduct a main resource load. ServiceWorkerRequestTestResources test_resources( this, GURL("https://host/scope/doc"), ResourceType::kMainFrame); - ServiceWorkerNavigationLoader* loader = test_resources.MaybeCreateLoader(); - - EXPECT_FALSE(loader->ShouldFallbackToNetwork()); - EXPECT_FALSE(loader->ShouldForwardToServiceWorker()); - EXPECT_FALSE(version_->HasControllee()); + test_resources.MaybeCreateLoader(); + EXPECT_FALSE(test_resources.loader()); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(loader->ShouldFallbackToNetwork()); - EXPECT_TRUE(loader->ShouldForwardToServiceWorker()); + EXPECT_TRUE(test_resources.loader()); EXPECT_TRUE(version_->HasControllee()); histogram_tester.ExpectTotalCount( "ServiceWorker.LookupRegistration.MainResource.Time.Exists", 1); @@ -212,8 +208,8 @@ // Conduct a main resource load. ServiceWorkerRequestTestResources test_resources( this, GURL("https://host/scope/doc"), ResourceType::kMainFrame); - ServiceWorkerNavigationLoader* loader = test_resources.MaybeCreateLoader(); - EXPECT_FALSE(loader); + test_resources.MaybeCreateLoader(); + EXPECT_FALSE(test_resources.loader()); histogram_tester.ExpectTotalCount( "ServiceWorker.LookupRegistration.MainResource.Time.DoesNotExist", 1); @@ -233,8 +229,8 @@ // Conduct a main resource load. ServiceWorkerRequestTestResources test_resources( this, GURL("https://host/scope/doc"), ResourceType::kMainFrame); - ServiceWorkerNavigationLoader* loader = test_resources.MaybeCreateLoader(); - EXPECT_FALSE(loader); + test_resources.MaybeCreateLoader(); + EXPECT_FALSE(test_resources.loader()); histogram_tester.ExpectTotalCount( "ServiceWorker.LookupRegistration.MainResource.Time.Error", 1); @@ -259,17 +255,13 @@ // Conduct a main resource load. ServiceWorkerRequestTestResources test_resources( this, GURL("https://host/scope/doc"), ResourceType::kMainFrame); - ServiceWorkerNavigationLoader* loader = test_resources.MaybeCreateLoader(); - ASSERT_TRUE(loader); + test_resources.MaybeCreateLoader(); + EXPECT_FALSE(test_resources.loader()); - EXPECT_FALSE(loader->ShouldFallbackToNetwork()); - EXPECT_FALSE(loader->ShouldForwardToServiceWorker()); - EXPECT_FALSE(version_->HasControllee()); base::RunLoop().RunUntilIdle(); // Verify we did not use the worker. - EXPECT_TRUE(loader->ShouldFallbackToNetwork()); - EXPECT_FALSE(loader->ShouldForwardToServiceWorker()); + EXPECT_FALSE(test_resources.loader()); EXPECT_FALSE(version_->HasControllee()); SetBrowserClientForTesting(old_browser_client); @@ -290,17 +282,13 @@ // Conduct a main resource load. ServiceWorkerRequestTestResources test_resources( this, GURL("https://host/scope/doc"), ResourceType::kMainFrame); - ServiceWorkerNavigationLoader* loader = test_resources.MaybeCreateLoader(); - ASSERT_TRUE(loader); - - EXPECT_FALSE(loader->ShouldFallbackToNetwork()); - EXPECT_FALSE(loader->ShouldForwardToServiceWorker()); + test_resources.MaybeCreateLoader(); + EXPECT_FALSE(test_resources.loader()); EXPECT_FALSE(version_->HasControllee()); base::RunLoop().RunUntilIdle(); // Verify we did not use the worker. - EXPECT_TRUE(loader->ShouldFallbackToNetwork()); - EXPECT_FALSE(loader->ShouldForwardToServiceWorker()); + EXPECT_FALSE(test_resources.loader()); EXPECT_FALSE(version_->HasControllee()); } @@ -317,18 +305,14 @@ // Conduct a main resource load. ServiceWorkerRequestTestResources test_resources( this, GURL("https://host/scope/doc"), ResourceType::kMainFrame); - ServiceWorkerNavigationLoader* loader = test_resources.MaybeCreateLoader(); - ASSERT_TRUE(loader); - - EXPECT_FALSE(loader->ShouldFallbackToNetwork()); - EXPECT_FALSE(loader->ShouldForwardToServiceWorker()); + test_resources.MaybeCreateLoader(); + EXPECT_FALSE(test_resources.loader()); EXPECT_FALSE(version_->HasControllee()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version_->status()); - EXPECT_FALSE(loader->ShouldFallbackToNetwork()); - EXPECT_TRUE(loader->ShouldForwardToServiceWorker()); + EXPECT_TRUE(test_resources.loader()); EXPECT_TRUE(version_->HasControllee()); test_resources.ResetHandler(); @@ -346,7 +330,7 @@ // Conduct a main resource load. ServiceWorkerRequestTestResources test_resources( this, GURL("https://host/scope/doc"), ResourceType::kMainFrame); - ServiceWorkerNavigationLoader* job = test_resources.MaybeCreateLoader(); + test_resources.MaybeCreateLoader(); base::RunLoop().RunUntilIdle(); @@ -354,7 +338,7 @@ // provider host should not be controlled. However it should add the // registration as a matching registration so it can be used for .ready and // claim(). - EXPECT_FALSE(job); + EXPECT_FALSE(test_resources.loader()); EXPECT_FALSE(version_->HasControllee()); EXPECT_FALSE(provider_host_->controller()); EXPECT_EQ(registration_.get(), provider_host_->MatchRegistration()); @@ -377,19 +361,15 @@ // Conduct a main resource load. ServiceWorkerRequestTestResources test_resources( this, GURL("https://host/scope/doc"), ResourceType::kMainFrame); - ServiceWorkerNavigationLoader* loader = test_resources.MaybeCreateLoader(); - ASSERT_TRUE(loader); - - EXPECT_FALSE(loader->ShouldFallbackToNetwork()); - EXPECT_FALSE(loader->ShouldForwardToServiceWorker()); + test_resources.MaybeCreateLoader(); + EXPECT_FALSE(test_resources.loader()); // Shouldn't crash if the ProviderHost is deleted prior to completion of // the database lookup. context()->RemoveProviderHost(provider_host_->provider_id()); EXPECT_FALSE(provider_host_.get()); base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(loader->ShouldFallbackToNetwork()); - EXPECT_FALSE(loader->ShouldForwardToServiceWorker()); + EXPECT_FALSE(test_resources.loader()); } #if BUILDFLAG(ENABLE_OFFLINE_PAGES) @@ -409,9 +389,9 @@ // Sets an offline header to indicate force loading offline page. test_resources.request()->SetExtraRequestHeaderByName( "X-Chrome-offline", "reason=download", true); - ServiceWorkerNavigationLoader* loader = test_resources.MaybeCreateLoader(); - - EXPECT_FALSE(loader); + test_resources.MaybeCreateLoader(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(test_resources.loader()); } TEST_F(ServiceWorkerControlleeRequestHandlerTest, FallbackWithNoOfflineHeader) { @@ -430,9 +410,9 @@ // Empty offline header value should not cause fallback. test_resources.request()->SetExtraRequestHeaderByName("X-Chrome-offline", "", true); - ServiceWorkerNavigationLoader* loader = test_resources.MaybeCreateLoader(); - - EXPECT_TRUE(loader); + test_resources.MaybeCreateLoader(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(test_resources.loader()); } #endif // BUILDFLAG(ENABLE_OFFLINE_PAGE)
diff --git a/content/browser/service_worker/service_worker_navigation_loader.cc b/content/browser/service_worker/service_worker_navigation_loader.cc index 4a1699b..d74ca80 100644 --- a/content/browser/service_worker/service_worker_navigation_loader.cc +++ b/content/browser/service_worker/service_worker_navigation_loader.cc
@@ -78,34 +78,25 @@ }; ServiceWorkerNavigationLoader::ServiceWorkerNavigationLoader( - NavigationLoaderInterceptor::LoaderCallback callback, NavigationLoaderInterceptor::FallbackCallback fallback_callback, Delegate* delegate, - const network::ResourceRequest& tentative_resource_request, base::WeakPtr<ServiceWorkerProviderHost> provider_host, scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter) - : loader_callback_(std::move(callback)), - fallback_callback_(std::move(fallback_callback)), + : fallback_callback_(std::move(fallback_callback)), delegate_(delegate), provider_host_(std::move(provider_host)), url_loader_factory_getter_(std::move(url_loader_factory_getter)), binding_(this), weak_factory_(this) { - TRACE_EVENT_WITH_FLOW1( + TRACE_EVENT_WITH_FLOW0( "ServiceWorker", - "ServiceWorkerNavigationLoader::ServiceWorkerNavigationloader", this, - TRACE_EVENT_FLAG_FLOW_OUT, "url", tentative_resource_request.url.spec()); + "ServiceWorkerNavigationLoader::ServiceWorkerNavigationLoader", this, + TRACE_EVENT_FLAG_FLOW_OUT); DCHECK(delegate_); - DCHECK(ServiceWorkerUtils::IsMainResourceType( - static_cast<ResourceType>(tentative_resource_request.resource_type))); response_head_.load_timing.request_start = base::TimeTicks::Now(); response_head_.load_timing.request_start_time = base::Time::Now(); - - // Beware that the final resource request may change due to throttles, so - // don't save |tentative_resource_request| here. We'll get the real one in - // StartRequest. } ServiceWorkerNavigationLoader::~ServiceWorkerNavigationLoader() { @@ -115,44 +106,6 @@ TRACE_EVENT_FLAG_FLOW_IN); } -void ServiceWorkerNavigationLoader::FallbackToNetwork() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - TRACE_EVENT_WITH_FLOW0( - "ServiceWorker", "ServiceWorkerNavigationLoader::FallbackToNetwork", this, - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - // ServiceWorkerControlleeRequestHandler only calls this if this loader never - // intercepted the request. Fallback to network after interception uses - // |fallback_callback_| instead. - DCHECK_EQ(response_type_, ResponseType::NOT_DETERMINED); - response_type_ = ResponseType::FALLBACK_TO_NETWORK; - - TransitionToStatus(Status::kCompleted); - - std::move(loader_callback_).Run({}); -} - -void ServiceWorkerNavigationLoader::ForwardToServiceWorker() { - TRACE_EVENT_WITH_FLOW0( - "ServiceWorker", "ServiceWorkerNavigationLoader::ForwardToServiceWorker", - this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - DCHECK_EQ(status_, Status::kNotStarted); - DCHECK_EQ(response_type_, ResponseType::NOT_DETERMINED); - - response_type_ = ResponseType::FORWARD_TO_SERVICE_WORKER; - - std::move(loader_callback_) - .Run(base::BindOnce(&ServiceWorkerNavigationLoader::StartRequest, - weak_factory_.GetWeakPtr())); -} - -bool ServiceWorkerNavigationLoader::ShouldFallbackToNetwork() { - return response_type_ == ResponseType::FALLBACK_TO_NETWORK; -} - -bool ServiceWorkerNavigationLoader::ShouldForwardToServiceWorker() { - return response_type_ == ResponseType::FORWARD_TO_SERVICE_WORKER; -} - void ServiceWorkerNavigationLoader::DetachedFromRequest() { delegate_ = nullptr; DeleteIfNeeded(); @@ -167,6 +120,13 @@ const network::ResourceRequest& resource_request, network::mojom::URLLoaderRequest request, network::mojom::URLLoaderClientPtr client) { + TRACE_EVENT_WITH_FLOW1("ServiceWorker", + "ServiceWorkerNavigationLoader::StartRequest", this, + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "url", resource_request.url.spec()); + DCHECK(ServiceWorkerUtils::IsMainResourceType( + static_cast<ResourceType>(resource_request.resource_type))); + resource_request_ = resource_request; if (provider_host_ && provider_host_->fetch_request_window_id()) { resource_request_.fetch_window_id = @@ -182,13 +142,8 @@ base::Unretained(this))); url_loader_client_ = std::move(client); - DCHECK_EQ(ResponseType::FORWARD_TO_SERVICE_WORKER, response_type_); TransitionToStatus(Status::kStarted); - TRACE_EVENT_WITH_FLOW0("ServiceWorker", - "ServiceWorkerNavigationLoader::StartRequest", this, - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT); - ServiceWorkerVersion* active_worker = delegate_->GetServiceWorkerVersion(); if (!active_worker) { CommitCompleted(net::ERR_FAILED, "No active worker");
diff --git a/content/browser/service_worker/service_worker_navigation_loader.h b/content/browser/service_worker/service_worker_navigation_loader.h index 9b31b990..af871ed 100644 --- a/content/browser/service_worker/service_worker_navigation_loader.h +++ b/content/browser/service_worker/service_worker_navigation_loader.h
@@ -15,7 +15,6 @@ #include "content/browser/service_worker/embedded_worker_status.h" #include "content/browser/service_worker/service_worker_fetch_dispatcher.h" #include "content/browser/service_worker/service_worker_metrics.h" -#include "content/browser/service_worker/service_worker_response_type.h" #include "content/browser/url_loader_factory_getter.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/system/data_pipe.h" @@ -42,8 +41,6 @@ class CONTENT_EXPORT ServiceWorkerNavigationLoader : public network::mojom::URLLoader { public: - using ResponseType = ServiceWorkerResponseType; - class CONTENT_EXPORT Delegate { public: virtual ~Delegate() {} @@ -63,26 +60,20 @@ virtual void MainResourceLoadFailed() = 0; }; - // Created by ServiceWorkerControlleeRequestHandler::MaybeCreateLoader - // when starting to load a main resource. + // Created by ServiceWorkerControlleeRequestHandler + // after it determines the load should go through a service worker. // // For the navigation case, this job typically works in the following order: - // 1. One of the FallbackTo* or ForwardTo* methods are called by - // ServiceWorkerControlleeRequestHandler, which determines how the request - // should be served (e.g. should fallback to network or should be sent to - // the SW). If it decides to fallback to the network this will call - // |loader_callback| with a null RequestHandler, which will be then handled - // by NavigationURLLoaderImpl. - // 2. If it is decided that the request should be sent to the SW, - // this job calls |loader_callback|, passing StartRequest as the + // 1. ServiceWorkerControlleeRequestHandler::MaybeCreateLoader() creates the + // ServiceWorkerNavigationLoader, passing StartRequest() as the // RequestHandler. - // 3. At this point, the NavigationURLLoaderImpl can throttle the request, + // 2. At this point, the NavigationURLLoaderImpl can throttle the request, // and invoke the RequestHandler later with a possibly modified request. - // 4. StartRequest is invoked. This dispatches a FetchEvent. - // 5. DidDispatchFetchEvent() determines the request's final destination. If + // 3. StartRequest is invoked. This dispatches a FetchEvent. + // 4. DidDispatchFetchEvent() determines the request's final destination. If // it turns out we need to fallback to network, it calls // |fallback_callback|. - // 6. Otherwise if the SW returned a stream or blob as a response + // 5. Otherwise if the SW returned a stream or blob as a response // this job passes the response to the network::mojom::URLLoaderClientPtr // connected to NavigationURLLoaderImpl (for resource loading for // navigation), that was given to StartRequest. This forwards the @@ -91,20 +82,18 @@ // Loads for shared workers work similarly, except SharedWorkerScriptLoader // is used instead of NavigationURLLoaderImpl. ServiceWorkerNavigationLoader( - NavigationLoaderInterceptor::LoaderCallback loader_callback, NavigationLoaderInterceptor::FallbackCallback fallback_callback, Delegate* delegate, - const network::ResourceRequest& tentative_resource_request, base::WeakPtr<ServiceWorkerProviderHost> provider_host, scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter); ~ServiceWorkerNavigationLoader() override; - // Called via ServiceWorkerControlleeRequestHandler. - void FallbackToNetwork(); - void ForwardToServiceWorker(); - bool ShouldFallbackToNetwork(); - bool ShouldForwardToServiceWorker(); + // Passed as the RequestHandler for + // NavigationLoaderInterceptor::MaybeCreateLoader. + void StartRequest(const network::ResourceRequest& resource_request, + network::mojom::URLLoaderRequest request, + network::mojom::URLLoaderClientPtr client); // The navigation request that was holding this job is // going away. Calling this internally calls |DeleteIfNeeded()| @@ -132,10 +121,6 @@ kCompleted, }; - // For FORWARD_TO_SERVICE_WORKER case. - void StartRequest(const network::ResourceRequest& resource_request, - network::mojom::URLLoaderRequest request, - network::mojom::URLLoaderClientPtr client); void DidPrepareFetchEvent(scoped_refptr<ServiceWorkerVersion> version, EmbeddedWorkerStatus initial_worker_status); void DidDispatchFetchEvent( @@ -187,8 +172,6 @@ void TransitionToStatus(Status new_status); - ResponseType response_type_ = ResponseType::NOT_DETERMINED; - NavigationLoaderInterceptor::LoaderCallback loader_callback_; NavigationLoaderInterceptor::FallbackCallback fallback_callback_; // |delegate_| is non-null and owns |this| until DetachedFromRequest() is
diff --git a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc index 0b84ae8..72e82bc5 100644 --- a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc +++ b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
@@ -387,41 +387,24 @@ ServiceWorkerStorage* storage() { return helper_->context()->storage(); } - // Indicates whether ServiceWorkerNavigationLoader decided to handle a - // request, i.e., it returned a non-null RequestHandler for the request. - enum class LoaderResult { - kHandledRequest, - kDidNotHandleRequest, - }; - - // Starts a request. Returns whether ServiceWorkerNavigationLoader handled the - // request. If kHandledRequest was returned, the request is ongoing and the + // Starts a request. After calling this, the request is ongoing and the // caller can use functions like client_.RunUntilComplete() to wait for // completion. - LoaderResult StartRequest(std::unique_ptr<network::ResourceRequest> request) { + void StartRequest(std::unique_ptr<network::ResourceRequest> request) { provider_host_ = CreateProviderHostForWindow( helper_->mock_render_process_id(), true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(), &provider_endpoints_); - // Start a ServiceWorkerNavigationLoader. It should return a - // RequestHandler. - SingleRequestURLLoaderFactory::RequestHandler handler; + // Create a ServiceWorkerNavigationLoader. loader_ = std::make_unique<ServiceWorkerNavigationLoader>( - base::BindOnce(&ReceiveRequestHandler, &handler), base::BindOnce(&ServiceWorkerNavigationLoaderTest::Fallback, base::Unretained(this)), - this, *request, provider_host_, + this, provider_host_, base::WrapRefCounted<URLLoaderFactoryGetter>( helper_->context()->loader_factory_getter())); - loader_->ForwardToServiceWorker(); - base::RunLoop().RunUntilIdle(); - if (!handler) - return LoaderResult::kDidNotHandleRequest; - // Run the handler. It will load |request.url|. - std::move(handler).Run(*request, mojo::MakeRequest(&loader_ptr_), - client_.CreateInterfacePtr()); - - return LoaderResult::kHandledRequest; + // Load |request.url|. + loader_->StartRequest(*request, mojo::MakeRequest(&loader_ptr_), + client_.CreateInterfacePtr()); } // The |fallback_callback| passed to the ServiceWorkerNavigationLoader in @@ -514,9 +497,8 @@ TEST_F(ServiceWorkerNavigationLoaderTest, Basic) { base::HistogramTester histogram_tester; - // Perform the request - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + // Perform the request. + StartRequest(CreateRequest()); client_.RunUntilComplete(); EXPECT_EQ(net::OK, client_.completion_status().error_code); @@ -543,9 +525,7 @@ version_ = nullptr; // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); - + StartRequest(CreateRequest()); client_.RunUntilComplete(); EXPECT_EQ(net::ERR_FAILED, client_.completion_status().error_code); @@ -597,8 +577,7 @@ service_worker_->RespondWithBlob(std::move(blob)); // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); client_.RunUntilComplete(); const network::ResourceResponseHead& info = client_.response_head(); @@ -638,8 +617,7 @@ service_worker_->RespondWithBlob(std::move(blob)); // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); // We should get a valid response once the headers arrive. client_.RunUntilResponseReceived(); @@ -674,8 +652,7 @@ std::move(data_pipe.consumer_handle)); // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); client_.RunUntilResponseReceived(); const network::ResourceResponseHead& info = client_.response_head(); @@ -722,8 +699,7 @@ std::move(data_pipe.consumer_handle)); // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); client_.RunUntilResponseReceived(); const network::ResourceResponseHead& info = client_.response_head(); @@ -772,8 +748,7 @@ std::move(data_pipe.consumer_handle)); // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); client_.RunUntilResponseReceived(); const network::ResourceResponseHead& info = client_.response_head(); @@ -822,8 +797,7 @@ service_worker_->RespondWithFallback(); // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); // The fallback callback should be called. RunUntilFallbackCallback(); @@ -849,9 +823,7 @@ service_worker_->RespondWithError(); // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); - + StartRequest(CreateRequest()); client_.RunUntilComplete(); EXPECT_EQ(net::ERR_FAILED, client_.completion_status().error_code); @@ -871,8 +843,7 @@ service_worker_->FailToDispatchFetchEvent(); // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); // The fallback callback should be called. RunUntilFallbackCallback(); @@ -895,8 +866,7 @@ service_worker_->RespondEarly(); // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); client_.RunUntilComplete(); const network::ResourceResponseHead& info = client_.response_head(); @@ -910,41 +880,6 @@ EXPECT_FALSE(HasWorkInBrowser(version_.get())); } -// Test asking the loader to fallback to network. In production code, this -// happens when there is no active service worker for the URL, or it must be -// skipped, etc. -TEST_F(ServiceWorkerNavigationLoaderTest, FallbackToNetwork) { - base::HistogramTester histogram_tester; - - network::ResourceRequest request; - request.url = GURL("https://www.example.com/"); - request.method = "GET"; - request.mode = network::mojom::RequestMode::kNavigate; - request.credentials_mode = network::mojom::CredentialsMode::kInclude; - request.redirect_mode = network::mojom::RedirectMode::kManual; - - SingleRequestURLLoaderFactory::RequestHandler handler; - auto loader = std::make_unique<ServiceWorkerNavigationLoader>( - base::BindOnce(&ReceiveRequestHandler, &handler), - base::BindOnce(&ServiceWorkerNavigationLoaderTest::Fallback, - base::Unretained(this)), - this, request, nullptr /* provider_host */, - base::WrapRefCounted<URLLoaderFactoryGetter>( - helper_->context()->loader_factory_getter())); - // Ask the loader to fallback to network. In production code, - // ServiceWorkerControlleeRequestHandler calls FallbackToNetwork() to do this. - loader->FallbackToNetwork(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(handler); - - // No fetch event was dispatched. - histogram_tester.ExpectTotalCount(kHistogramMainResourceFetchEvent, 0); - histogram_tester.ExpectTotalCount( - "ServiceWorker.LoadTiming.MainFrame.MainResource." - "StartToForwardServiceWorker", - 0); -} - // Test responding to the fetch event with a redirect response. TEST_F(ServiceWorkerNavigationLoaderTest, Redirect) { base::HistogramTester histogram_tester; @@ -952,8 +887,7 @@ service_worker_->RespondWithRedirectResponse(new_url); // Perform the request. - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); client_.RunUntilRedirectReceived(); const network::ResourceResponseHead& info = client_.response_head(); @@ -969,9 +903,8 @@ blink::ServiceWorkerStatusCode::kOk, 1); } -TEST_F(ServiceWorkerNavigationLoaderTest, LifetimeAfterForwardToServiceWorker) { - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); +TEST_F(ServiceWorkerNavigationLoaderTest, Lifetime) { + StartRequest(CreateRequest()); base::WeakPtr<ServiceWorkerNavigationLoader> loader = loader_->AsWeakPtr(); ASSERT_TRUE(loader); @@ -992,40 +925,9 @@ // |loader_| is deleted here. LSan test will alert if it leaks. } -TEST_F(ServiceWorkerNavigationLoaderTest, LifetimeAfterFallbackToNetwork) { - network::ResourceRequest request; - request.url = GURL("https://www.example.com/"); - request.method = "GET"; - request.mode = network::mojom::RequestMode::kNavigate; - request.credentials_mode = network::mojom::CredentialsMode::kInclude; - request.redirect_mode = network::mojom::RedirectMode::kManual; - - SingleRequestURLLoaderFactory::RequestHandler handler; - auto loader = std::make_unique<ServiceWorkerNavigationLoader>( - base::BindOnce(&ReceiveRequestHandler, &handler), - base::BindOnce(&ServiceWorkerNavigationLoaderTest::Fallback, - base::Unretained(this)), - this, request, nullptr /* provider_host */, - base::WrapRefCounted<URLLoaderFactoryGetter>( - helper_->context()->loader_factory_getter())); - base::WeakPtr<ServiceWorkerNavigationLoader> loader_weakptr = - loader->AsWeakPtr(); - // Ask the loader to fallback to network. In production code, - // ServiceWorkerControlleeRequestHandler calls FallbackToNetwork() to do this. - loader->FallbackToNetwork(); - base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(handler); - EXPECT_TRUE(loader_weakptr); - - // DetachedFromRequest() deletes |loader_|. - loader.release()->DetachedFromRequest(); - EXPECT_FALSE(loader_weakptr); -} - TEST_F(ServiceWorkerNavigationLoaderTest, ConnectionErrorDuringFetchEvent) { service_worker_->DeferResponse(); - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); // Wait for the fetch event to be dispatched. service_worker_->RunUntilFetchEvent(); @@ -1045,8 +947,7 @@ } TEST_F(ServiceWorkerNavigationLoaderTest, DetachedDuringFetchEvent) { - LoaderResult result = StartRequest(CreateRequest()); - EXPECT_EQ(LoaderResult::kHandledRequest, result); + StartRequest(CreateRequest()); // Detach the loader immediately after it started. This results in // DidDispatchFetchEvent() being invoked later with null |delegate_|.
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc index 18eff1ad..036d2619 100644 --- a/content/browser/service_worker/service_worker_provider_host.cc +++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -689,6 +689,8 @@ void ServiceWorkerProviderHost::ClaimedByRegistration( scoped_refptr<ServiceWorkerRegistration> registration) { DCHECK(registration->active_version()); + DCHECK(is_execution_ready()); + // TODO(falken): This should just early return, or DCHECK. claim() should have // no effect on a page that's already using the registration. if (registration == controller_registration_) { @@ -696,11 +698,7 @@ return; } - // TODO(crbug.com/866353): It shouldn't be necesary to check - // |allow_set_controller_registration_|. See the comment for - // AllowSetControllerRegistration(). - if (allow_set_controller_registration_) - SetControllerRegistration(registration, true /* notify_controllerchange */); + SetControllerRegistration(registration, true /* notify_controllerchange */); } void ServiceWorkerProviderHost::OnBeginNavigationCommit(int render_process_id,
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h index 4f18627..c050626f 100644 --- a/content/browser/service_worker/service_worker_provider_host.h +++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -272,22 +272,6 @@ scoped_refptr<ServiceWorkerRegistration> controller_registration, bool notify_controllerchange); - // For use by the ServiceWorkerControlleeRequestHandler to disallow a - // registration claiming this host while its main resource request is - // occurring. - // - // TODO(crbug.com/866353): This should be unneccessary: registration code - // already avoids claiming clients that are not execution ready. However - // there may be edge cases with shared workers (pre-NetS13nServiceWorker) and - // about:blank iframes, since |is_execution_ready()| is initialized true for - // them. Try to remove this after S13nServiceWorker. - void AllowSetControllerRegistration(bool allow) { - allow_set_controller_registration_ = allow; - } - bool IsSetControllerRegistrationAllowed() { - return allow_set_controller_registration_; - } - // Returns an interceptor for a main resource request. May return nullptr if // the request doesn't require interception. std::unique_ptr<NavigationLoaderInterceptor> CreateLoaderInterceptor( @@ -410,8 +394,8 @@ bool is_response_committed() const; // For service worker clients. True if the client is execution ready and - // therefore can be exposed to JavaScript. Execution ready implies connected - // to renderer. + // therefore can be exposed to JavaScript. Execution ready implies response + // committed. // https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-execution-ready-flag bool is_execution_ready() const; @@ -677,7 +661,6 @@ // the provider host's controller is updated to match it. scoped_refptr<ServiceWorkerVersion> controller_; scoped_refptr<ServiceWorkerRegistration> controller_registration_; - bool allow_set_controller_registration_ = true; // For service worker execution contexts. The ServiceWorkerVersion of the // service worker this is a provider for.
diff --git a/content/browser/service_worker/service_worker_registration.cc b/content/browser/service_worker/service_worker_registration.cc index 290d6e3..afe28f1 100644 --- a/content/browser/service_worker/service_worker_registration.cc +++ b/content/browser/service_worker/service_worker_registration.cc
@@ -250,17 +250,40 @@ DCHECK(context_); DCHECK(active_version()); + // https://w3c.github.io/ServiceWorker/#clients-claim + // + // "For each service worker client client whose origin is the same as the + // service worker's origin: + const bool include_reserved_clients = false; for (std::unique_ptr<ServiceWorkerContextCore::ProviderHostIterator> it = - context_->GetClientProviderHostIterator( - scope_.GetOrigin(), false /* include_reserved_clients */); + context_->GetClientProviderHostIterator(scope_.GetOrigin(), + include_reserved_clients); !it->IsAtEnd(); it->Advance()) { ServiceWorkerProviderHost* host = it->GetProviderHost(); + // "1. If client’s execution ready flag is unset or client’s discarded flag + // is set, continue." + // |include_reserved_clients| ensures only execution ready clients are + // returned. + DCHECK(host->is_execution_ready()); + + // This is part of step 5 but performed here as an optimization. Do nothing + // if this version is already the controller. if (host->controller() == active_version()) continue; + + // "2. If client is not a secure context, continue." if (!host->IsContextSecureForServiceWorker()) continue; - if (host->MatchRegistration() == this) - host->ClaimedByRegistration(this); + + // "3. Let registration be the result of running Match Service Worker + // Registration algorithm passing client’s creation URL as the argument. + // 4. If registration is not the service worker's containing service worker + // registration, continue." + if (host->MatchRegistration() != this) + continue; + + // The remaining steps are performed here: + host->ClaimedByRegistration(this); } }
diff --git a/content/browser/service_worker/service_worker_response_type.h b/content/browser/service_worker/service_worker_response_type.h deleted file mode 100644 index 0d37b88..0000000 --- a/content/browser/service_worker/service_worker_response_type.h +++ /dev/null
@@ -1,21 +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 CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_RESPONSE_TYPE_H_ -#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_RESPONSE_TYPE_H_ - -namespace content { - -// Response handling type, used in URL {request,loader} jobs. -enum class ServiceWorkerResponseType { - NOT_DETERMINED, - FAIL_DUE_TO_LOST_CONTROLLER, - FALLBACK_TO_NETWORK, - FALLBACK_TO_RENDERER, // Use this when falling back with CORS check - FORWARD_TO_SERVICE_WORKER -}; - -} // namespace content - -#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_RESPONSE_TYPE_H_
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 24ea4bd..3cc697a 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -302,6 +302,24 @@ return a->frame_tree_node()->depth() < b->frame_tree_node()->depth(); } +bool AreValidRegisterProtocolHandlerArguments(const std::string& protocol, + const GURL& url, + const url::Origin& origin) { + ChildProcessSecurityPolicyImpl* policy = + ChildProcessSecurityPolicyImpl::GetInstance(); + if (policy->IsPseudoScheme(protocol)) + return false; + + if (!url.SchemeIsHTTPOrHTTPS()) + return false; + + url::Origin url_origin = url::Origin::Create(url); + if (!url_origin.IsSameOriginWith(origin)) + return false; + + return true; +} + } // namespace std::unique_ptr<WebContents> WebContents::Create( @@ -4832,10 +4850,12 @@ if (!delegate_) return; - ChildProcessSecurityPolicyImpl* policy = - ChildProcessSecurityPolicyImpl::GetInstance(); - if (policy->IsPseudoScheme(protocol)) + if (!AreValidRegisterProtocolHandlerArguments( + protocol, url, source->GetLastCommittedOrigin())) { + ReceivedBadMessage(source->GetProcess(), + bad_message::REGISTER_PROTOCOL_HANDLER_INVALID_URL); return; + } delegate_->RegisterProtocolHandler(this, protocol, url, user_gesture); } @@ -4849,10 +4869,12 @@ if (!delegate_) return; - ChildProcessSecurityPolicyImpl* policy = - ChildProcessSecurityPolicyImpl::GetInstance(); - if (policy->IsPseudoScheme(protocol)) + if (!AreValidRegisterProtocolHandlerArguments( + protocol, url, source->GetLastCommittedOrigin())) { + ReceivedBadMessage(source->GetProcess(), + bad_message::REGISTER_PROTOCOL_HANDLER_INVALID_URL); return; + } delegate_->UnregisterProtocolHandler(this, protocol, url, user_gesture); }
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc index 07a2e13..387385e 100644 --- a/content/browser/web_contents/web_contents_impl_unittest.cc +++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -3343,6 +3343,8 @@ public: MOCK_METHOD2(HandleContextMenu, bool(RenderFrameHost*, const ContextMenuParams&)); + MOCK_METHOD4(RegisterProtocolHandler, + void(WebContents*, const std::string&, const GURL&, bool)); }; } // namespace @@ -3361,4 +3363,86 @@ contents()->SetDelegate(nullptr); } +TEST_F(WebContentsImplTest, RegisterProtocolHandlerDifferentOrigin) { + MockWebContentsDelegate delegate; + contents()->SetDelegate(&delegate); + + GURL url("https://www.google.com"); + GURL handler_url1("https://www.google.com/handler/%s"); + GURL handler_url2("https://www.example.com/handler/%s"); + + contents()->NavigateAndCommit(url); + + // Only the first call to RegisterProtocolHandler should register because the + // other call has a handler from a different origin. + EXPECT_CALL(delegate, + RegisterProtocolHandler(contents(), "mailto", handler_url1, true)) + .Times(1); + + { + FrameHostMsg_RegisterProtocolHandler message( + main_test_rfh()->GetRoutingID(), "mailto", handler_url1, + base::string16(), /*user_gesture=*/true); + contents()->OnMessageReceived(main_test_rfh(), message); + } + + { + FrameHostMsg_RegisterProtocolHandler message( + main_test_rfh()->GetRoutingID(), "mailto", handler_url2, + base::string16(), /*user_gesture=*/true); + contents()->OnMessageReceived(main_test_rfh(), message); + } + + contents()->SetDelegate(nullptr); +} + +TEST_F(WebContentsImplTest, RegisterProtocolHandlerDataURL) { + MockWebContentsDelegate delegate; + contents()->SetDelegate(&delegate); + + GURL data("data:text/html,<html><body><b>hello world</b></body></html>"); + GURL data_handler(data.spec() + "%s"); + + contents()->NavigateAndCommit(data); + + // Data URLs should fail. + EXPECT_CALL(delegate, + RegisterProtocolHandler(contents(), "mailto", data_handler, true)) + .Times(0); + + { + FrameHostMsg_RegisterProtocolHandler message( + main_test_rfh()->GetRoutingID(), "mailto", data_handler, + base::string16(), /*user_gesture=*/true); + contents()->OnMessageReceived(main_test_rfh(), message); + } + + contents()->SetDelegate(nullptr); +} + +TEST_F(WebContentsImplTest, RegisterProtocolHandlerBlobURL) { + MockWebContentsDelegate delegate; + contents()->SetDelegate(&delegate); + + GURL url("https://www.google.com"); + GURL blob_handler( + "blob:https://www.google.com/f2d8c47d-17d0-4bf5-8f0a-76e42cbed3bf/%s"); + + contents()->NavigateAndCommit(url); + + // Blob URLs should fail. + EXPECT_CALL(delegate, + RegisterProtocolHandler(contents(), "mailto", blob_handler, true)) + .Times(0); + + { + FrameHostMsg_RegisterProtocolHandler message( + main_test_rfh()->GetRoutingID(), "mailto", blob_handler, + base::string16(), /*user_gesture=*/true); + contents()->OnMessageReceived(main_test_rfh(), message); + } + + contents()->SetDelegate(nullptr); +} + } // namespace content
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc index 979c895..31ee3932 100644 --- a/content/child/child_thread_impl.cc +++ b/content/child/child_thread_impl.cc
@@ -22,7 +22,6 @@ #include "base/message_loop/timer_slack.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram_macros.h" -#include "base/optional.h" #include "base/power_monitor/power_monitor.h" #include "base/process/process.h" #include "base/process/process_handle.h" @@ -179,7 +178,7 @@ #endif // OS(POSIX) -base::Optional<mojo::IncomingInvitation> InitializeMojoIPCChannel() { +mojo::IncomingInvitation InitializeMojoIPCChannel() { TRACE_EVENT0("startup", "InitializeMojoIPCChannel"); mojo::PlatformChannelEndpoint endpoint; #if defined(OS_WIN) @@ -200,12 +199,12 @@ auto* client = base::MachPortRendezvousClient::GetInstance(); if (!client) { LOG(ERROR) << "Mach rendezvous failed."; - return base::nullopt; + return {}; } auto receive = client->TakeReceiveRight('mojo'); if (!receive.is_valid()) { LOG(ERROR) << "Invalid PlatformChannel receive right"; - return base::nullopt; + return {}; } endpoint = mojo::PlatformChannelEndpoint(mojo::PlatformHandle(std::move(receive))); @@ -214,10 +213,6 @@ base::ScopedFD(base::GlobalDescriptors::GetInstance()->Get( service_manager::kMojoIPCChannel)))); #endif - // Mojo isn't supported on all child process types. - // TODO(crbug.com/604282): Support Mojo in the remaining processes. - if (!endpoint.is_valid()) - return base::nullopt; return mojo::IncomingInvitation::Accept(std::move(endpoint)); } @@ -425,15 +420,14 @@ if (!IsInBrowserProcess()) { mojo_ipc_support_.reset(new mojo::core::ScopedIPCSupport( GetIOTaskRunner(), mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST)); - base::Optional<mojo::IncomingInvitation> invitation = - InitializeMojoIPCChannel(); + mojo::IncomingInvitation invitation = InitializeMojoIPCChannel(); std::string service_request_token = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( service_manager::switches::kServiceRequestChannelToken); - if (!service_request_token.empty() && invitation) { + if (!service_request_token.empty()) { service_request_pipe = - invitation->ExtractMessagePipe(service_request_token); + invitation.ExtractMessagePipe(service_request_token); } } else { service_request_pipe = options.mojo_invitation->ExtractMessagePipe(
diff --git a/content/public/browser/child_process_security_policy.h b/content/public/browser/child_process_security_policy.h index e413d5b..bc256489 100644 --- a/content/public/browser/child_process_security_policy.h +++ b/content/public/browser/child_process_security_policy.h
@@ -293,11 +293,11 @@ // Semantically identical to the above, but accepts a string of comma // separated origins. |origins_to_add| can contain both wildcard and - // non-wildcard origins, e.g. "https://**.foo.com,https://bar.com". + // non-wildcard origins, e.g. "https://[*.]foo.com,https://bar.com". // // Wildcard origins provide a way to treat all subdomains under the specified // host and scheme as distinct isolated origins. For example, - // https://**.foo.com would isolate https://foo.com, https://bar.foo.com and + // https://[*.]foo.com would isolate https://foo.com, https://bar.foo.com and // https://qux.baz.foo.com all in separate processes. Adding a wildcard origin // implies breaking document.domain for all of its subdomains. //
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index e38f65d..9b8fcc28 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -31,10 +31,6 @@ "AllowSignedHTTPExchangeCertsWithoutExtension", base::FEATURE_DISABLED_BY_DEFAULT}; -// Accounts for resource padding when reporting AppCache usage in the quota API. -const base::Feature kAppCacheIncludePaddingInQuota{ - "AppCacheIncludePaddingInQuota", base::FEATURE_ENABLED_BY_DEFAULT}; - // Creates audio output and input streams using the audio service. const base::Feature kAudioServiceAudioStreams{"AudioServiceAudioStreams", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 1766d6f3..9c15a01f 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -21,7 +21,6 @@ kAllowContentInitiatedDataUrlNavigations; CONTENT_EXPORT extern const base::Feature kAllowSignedHTTPExchangeCertsWithoutExtension; -CONTENT_EXPORT extern const base::Feature kAppCacheIncludePaddingInQuota; CONTENT_EXPORT extern const base::Feature kAudioServiceAudioStreams; CONTENT_EXPORT extern const base::Feature kAudioServiceLaunchOnStartup; CONTENT_EXPORT extern const base::Feature kAudioServiceOutOfProcess;
diff --git a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt index 55aef2f..c00b1f6 100644 --- a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt +++ b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt
@@ -1,5 +1,5 @@ EVENT_OBJECT_FOCUS on <li#op1> role=ROLE_SYSTEM_LISTITEM name="Apple" SELECTED,FOCUSED,FOCUSABLE,SELECTABLE PosInSet=1 SetSize=1 -EVENT_OBJECT_HIDE on <body> role=BODY +EVENT_OBJECT_HIDE on <body> role=BODY INVISIBLE IA2_EVENT_ACTIVE_DESCENDANT_CHANGED on <input> role=ROLE_SYSTEM_COMBOBOX EXPANDED,FOCUSABLE,HASPOPUP IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE,IA2_STATE_SUPPORTS_AUTOCOMPLETION IA2_EVENT_TEXT_INSERTED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSABLE new_text={'<obj><obj>' start=0 end=2} IA2_EVENT_TEXT_REMOVED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSABLE old_text={'<obj>' start=0 end=1}
diff --git a/content/test/data/accessibility/event/aria-hidden-changed-expected-uia-win.txt b/content/test/data/accessibility/event/aria-hidden-changed-expected-uia-win.txt new file mode 100644 index 0000000..073c1f8 --- /dev/null +++ b/content/test/data/accessibility/event/aria-hidden-changed-expected-uia-win.txt
@@ -0,0 +1,3 @@ +AriaProperties changed on role=heading, name=Item2 +AriaProperties changed on role=heading, name=Item3 +AriaProperties changed on role=heading, name=Item4
diff --git a/content/test/data/accessibility/event/aria-hidden-changed.html b/content/test/data/accessibility/event/aria-hidden-changed.html new file mode 100644 index 0000000..dd97f6c --- /dev/null +++ b/content/test/data/accessibility/event/aria-hidden-changed.html
@@ -0,0 +1,28 @@ +<!-- +@UIA-WIN-DENY:* +@UIA-WIN-ALLOW:AriaProperties* +--> +<!DOCTYPE html> +<html> +<body> + <h4 id="d1">Item1</h4> + <h4 id="d2" aria-hidden="true">Item2</h4> + <h4 id="d3" aria-hidden="false">Item3</h4> + <h4 id="d4" aria-hidden="true">Item4</h4> + <script> + function go() { + // Set aria-hidden from [removed]->false; should not fire an event. + document.getElementById('d1').setAttribute('aria-hidden', 'false'); + + // Set aria-hidden from true->false; should fire an event. + document.getElementById('d2').setAttribute('aria-hidden', 'false'); + + // Set aria-hidden from false->true; should fire an event. + document.getElementById('d3').setAttribute('aria-hidden', 'true'); + + // Set aria-hidden from true->[removed]; should fire an event. + document.getElementById('d4').removeAttribute('aria-hidden'); + } + </script> +</body> +</html>
diff --git a/content/test/data/accessibility/event/css-visibility-expected-win.txt b/content/test/data/accessibility/event/css-visibility-expected-win.txt index a267f80..d522a9a 100644 --- a/content/test/data/accessibility/event/css-visibility-expected-win.txt +++ b/content/test/data/accessibility/event/css-visibility-expected-win.txt
@@ -1,4 +1,4 @@ -EVENT_OBJECT_HIDE on <div.a> role=DIV level=2 +EVENT_OBJECT_HIDE on <div.a> role=DIV INVISIBLE level=2 EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL EVENT_OBJECT_SHOW on <div.b> role=ROLE_SYSTEM_GROUPING name="Banner" IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL new_text={'<obj>' start=0 end=1}
diff --git a/content/test/data/accessibility/event/expanded-change-expected-uia-win.txt b/content/test/data/accessibility/event/expanded-change-expected-uia-win.txt index be21082..2bfcb1d 100644 --- a/content/test/data/accessibility/event/expanded-change-expected-uia-win.txt +++ b/content/test/data/accessibility/event/expanded-change-expected-uia-win.txt
@@ -1,2 +1,7 @@ AriaProperties changed on role=link, name=Toggle +AriaProperties changed on role=list +AriaProperties changed on role=listitem +AriaProperties changed on role=listitem +AriaProperties changed on role=listitem +AriaProperties changed on role=listitem ExpandCollapseExpandCollapseState changed on role=link, name=Toggle
diff --git a/content/test/data/accessibility/event/visibility-hidden-changed-expected-uia-win.txt b/content/test/data/accessibility/event/visibility-hidden-changed-expected-uia-win.txt new file mode 100644 index 0000000..b9eeffe --- /dev/null +++ b/content/test/data/accessibility/event/visibility-hidden-changed-expected-uia-win.txt
@@ -0,0 +1,4 @@ +AriaProperties changed on role=heading +AriaProperties changed on role=heading +AriaProperties changed on role=heading, name=Item2 +AriaProperties changed on role=heading, name=Item4
diff --git a/content/test/data/accessibility/event/visibility-hidden-changed.html b/content/test/data/accessibility/event/visibility-hidden-changed.html new file mode 100644 index 0000000..5084bb5 --- /dev/null +++ b/content/test/data/accessibility/event/visibility-hidden-changed.html
@@ -0,0 +1,28 @@ +<!-- +@UIA-WIN-DENY:* +@UIA-WIN-ALLOW:AriaProperties* +--> +<!DOCTYPE html> +<html> +<body> + <h4 id="d1">Item1</h4> + <h4 id="d2" style="visibility: hidden">Item2</h4> + <h4 id="d3" style="visibility: visible">Item3</h4> + <h4 id="d4" style="visibility: hidden">Item4</h4> + <script> + function go() { + // Set style from [none]->visibility: hidden; should fire an event. + document.getElementById('d1').setAttribute('style', 'visibility: hidden'); + + // Set style from visibility: hidden->visibility: visible; should fire an event. + document.getElementById('d2').setAttribute('style', 'visibility: visible'); + + // Set style from visibility: visible->visibility: hidden; should fire an event. + document.getElementById('d3').setAttribute('style', 'visibility: hidden'); + + // Remove style visibility; should fire an event. + document.getElementById('d4').removeAttribute('style'); + } + </script> +</body> +</html>
diff --git a/content/test/gpu/gpu_tests/gpu_helper.py b/content/test/gpu/gpu_tests/gpu_helper.py index d5a6d422..6123985 100644 --- a/content/test/gpu/gpu_tests/gpu_helper.py +++ b/content/test/gpu/gpu_tests/gpu_helper.py
@@ -111,8 +111,19 @@ for o in extra_browser_args: if "UseSkiaRenderer" in o: return 'skia-renderer' + if "--disable-vulkan-fallback-to-gl-for-testing" in o: + return 'skia-renderer' return 'no-skia-renderer' +# Used to parse additional options sent to the browser instance via +# '--extra-browser-args', looking for '--use-vulkan='. +def GetVulkan(extra_browser_args): + if extra_browser_args: + for o in extra_browser_args: + if "--use-vulkan=" in o: + return 'use-vulkan' + return 'no-use-vulkan' + # used by unittests to create a mock arguments object def GetMockArgs(is_asan=False, webgl_version='1.0.0'): args = mock.MagicMock()
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test.py b/content/test/gpu/gpu_tests/gpu_integration_test.py index a38886bf..5f0e15b7a 100644 --- a/content/test/gpu/gpu_tests/gpu_integration_test.py +++ b/content/test/gpu/gpu_tests/gpu_integration_test.py
@@ -315,6 +315,9 @@ skia_renderer = gpu_helper.GetSkiaRenderer(\ browser._browser_backend.browser_options.extra_browser_args) tags.extend([skia_renderer]) + use_vulkan = gpu_helper.GetVulkan(\ + browser._browser_backend.browser_options.extra_browser_args) + tags.extend([use_vulkan]) return tags @classmethod
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index 2229070..d193d56 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -1,6 +1,7 @@ # tags: [ android chromeos highsierra linux mac mojave win ] # tags: [ android-chromium android-webview-instrumentation debug ] # tags: [ skia-renderer no-skia-renderer ] +# tags: [ use-vulkan no-use-vulkan ] # tags: [ amd amd-0x6613 amd-0x679e amd-0x6821 intel intel-0xa2e intel-0x5912 # nvidia nvidia-0xfe9 qualcomm-adreno-(tm)-330 qualcomm-adreno-(tm)-418 # qualcomm-adreno-(tm)-420 qualcomm-adreno-(tm)-430 @@ -194,5 +195,27 @@ # Fails when the browser feature SkiaRenderer is enabled crbug.com/976370 [ skia-renderer ] Pixel_CSS3DBlueBox [ Skip ] +# Fails when the browser features SkiaRenderer & Vulkan are enabled on Android +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_2DCanvasWebGL [ Failure ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_BackgroundImage [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_Canvas2DRedBox [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_Canvas2DUntagged [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_CanvasDisplayLinearRGBAccelerated2D [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvas2DResizeOnWorker [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasAccelerated2D [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasAccelerated2DWorker [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasTransferAfterStyleResize [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasTransferBeforeStyleResize [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasTransferToImageBitmap [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasTransferToImageBitmapWorker [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasWebGLDefault [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasWebGLDefaultWorker [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasWebglResizeOnWorker [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_WebGLGreenTriangle_AA_Alpha [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_WebGLGreenTriangle_AA_NoAlpha [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_WebGLGreenTriangle_NoAA_Alpha [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_WebGLGreenTriangle_NoAA_NoAlpha [ Skip ] +crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_WebGLTransparentGreenTriangle_NoAlpha_ImplicitClear [ Skip ] + # Produces blank images on Intel HD 630 w/ Mesa 19.0.2 crbug.com/976861 [ linux intel-0x5912 ] Pixel_OffscreenCanvasTransferToImageBitmap [ Skip ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index 9454cee..80a8ef4 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -451,7 +451,8 @@ crbug.com/352645 [ android android-webview-instrumentation no-angle ] conformance/textures/misc/texture-npot-video.html [ Skip ] # These video tests appear to be flaky. -crbug.com/907512 [ android release ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ RetryOnFailure ] +crbug.com/834933 [ android android-chromium ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ] +crbug.com/907512 [ android android-chromium ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ RetryOnFailure ] crbug.com/733599 [ android ] conformance/textures/video/tex-2d-alpha-alpha-unsigned_byte.html [ RetryOnFailure ] crbug.com/733599 [ android no-angle ] conformance/textures/video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ RetryOnFailure ] crbug.com/733599 [ android no-angle ] conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html [ RetryOnFailure ] @@ -569,7 +570,6 @@ crbug.com/891456 [ android nvidia ] conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html [ RetryOnFailure ] crbug.com/891456 [ android nvidia ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_byte.html [ RetryOnFailure ] crbug.com/891456 [ android nvidia ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ RetryOnFailure ] -crbug.com/891456 [ android nvidia ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ RetryOnFailure ] # Flaky timeout on android_n5x_swarming_rel and # android-marshmallow-arm64-rel.
diff --git a/docs/README.md b/docs/README.md index ed8f04fd..e1f2150 100644 --- a/docs/README.md +++ b/docs/README.md
@@ -146,6 +146,8 @@ * [WebUI Explainer](webui_explainer.md) - An explanation of C++ and JavaScript infrastructural code for Chrome UIs implemented with web technologies (i.e. chrome:// URLs). +* [Watchlists](infra/watchlists.md) - Use watchlists to get notified of CLs + you are interested in. ### Testing * [Running and Debugging Web Tests](testing/web_tests.md)
diff --git a/docs/contributing.md b/docs/contributing.md index eb214d21..cf5924b 100644 --- a/docs/contributing.md +++ b/docs/contributing.md
@@ -279,6 +279,8 @@ ## Tips +### Review etiquette + During the lifetime of a review, you may want to rebase your change onto a newer source revision to minimize merge conflicts. The reviewer-friendly way to do this is to first address any unresolved comments and upload those changes as a @@ -292,6 +294,13 @@ read these guidelines on [minimizing review lag][review-lag] and take them in consideration both when writing reviews and responding to review feedback. +### Watchlists + +If you would like to be notified about changes to a set of files covering a +topic or an area of Chromium, you may use the [watchlists][watchlist-doc] +feature in order to receive email notifications. + + [//]: # (the reference link section should be alphabetically sorted) [checkout-and-build]: https://chromium.googlesource.com/chromium/src/+/master/docs/#checking-out-and-building [cl-footer-syntax]: https://dev.chromium.org/developers/contributing-code/-bug-syntax @@ -320,3 +329,4 @@ [skia-dev-guide]: https://skia.org/dev/contrib [try-job-access]: https://www.chromium.org/getting-involved/become-a-committer#TOC-Try-job-access [v8-dev-guide]: https://v8.dev/docs +[watchlist-doc]: infra/watchlists.md
diff --git a/docs/infra/watchlists.md b/docs/infra/watchlists.md new file mode 100644 index 0000000..6542a595 --- /dev/null +++ b/docs/infra/watchlists.md
@@ -0,0 +1,76 @@ +## What are watchlists? + +A watchlist is a mechanism that allows a developer (a "watcher") to watch over +portions of code that the watcher is interested in. A watcher will be cc-ed on +changes that modify that portion of code, thereby giving that watcher an +opportunity to make comments on codereview.chromium.org even before the change +is committed. + +**Important :** As watchlists are processed locally when uploading using `git cl +upload` it is not possible to define watchlists for Gerrit CLs generated by +tools such as the [Skia autoroller][skia-autoroller] (see +[crbug.com/982198][crbug-982198]). In order to be notified of autoroller +commits, find the [corresponding config file][roller-configs] and add email +addresses of people to be notified of roller commits in the `sheriff` field of +the autoroller config. + +## Syntax + +Watchlists are defined using a `WATCHLISTS` file, which resides at the root of a +repository. A typical `WATCHLISTS` file looks like: + +``` +{ + 'WATCHLIST_DEFINITIONS': { + 'valgrind': { + 'filepath': 'tools/valgrind/', + }, + 'mac': { + 'filepath': 'cocoa|\.mm$|(_mac|_posix)\.(cc|h)$', + }, + }, + 'WATCHLISTS': { + 'valgrind': ['nirnimesh@chromium.org', 'dank@chromium.org'], + }, +} +``` + +In this case, watchlists named `valgrind` and `mac` are defined in +`WATCHLIST_DEFINITIONS` and their corresponding watchers declared in +`WATCHLISTS`. + +In the example above, whenever a new changeset is created that refers to any +file in `tools/valgrind/`, the `'valgrind'` watchlist will be triggered and +`nirnimesh@chromium.org` & `dank@chromium.org` will be cc-ed to the changeset +for review. A regular expression can be used as the matching pattern. Matches +are determined using python's `re.search()` function call, so matching `A_WORD` +is the same as matching `.*A_WORD.*`. + +Each name in `WATCHLISTS` must be defined first in `WATCHLIST_DEFINITIONS`. + +Watchlist processing takes place during `git-cl upload` and are non-binding; +that is, an approval from that watcher is not needed for commit. It merely gives +the watcher an opportunity to make comments, if any. + +## Editing Watchlists + +You create new watchlists or add yourself to existing watchlists by editing the +WATCHLISTS file at the base of the repository. + +It's advisable to run `watchlists.py` to verify that your new rules work. + +Example (from src): + +``` +python ../depot_tools/watchlists.py PATH/TO/FILE1 PATH/TO/FILE2 .... +``` + + +## Override + +To override watchlist processing, use `git cl upload` with `--bypass-hooks`. + +[//]: # (the reference link section should be alphabetically sorted) +[skia-autoroller]: https://skia.googlesource.com/buildbot/+/master/autoroll/README.md +[crbug-982198]: https://bugs.chromium.org/p/chromium/issues/detail?id=982198 +[roller-configs]: https://skia.googlesource.com/buildbot/+/master/autoroll/config
diff --git a/docs/media/gpu/video_decoder_test_usage.md b/docs/media/gpu/video_decoder_test_usage.md index 6d091737..bfaba76 100644 --- a/docs/media/gpu/video_decoder_test_usage.md +++ b/docs/media/gpu/video_decoder_test_usage.md
@@ -66,7 +66,7 @@ --disable_validator disable frame validation, useful on old platforms that don't support import mode. --output_frames write all decoded video frames to the - "video_frames" folder. + "<testname>" folder. --output_folder overwrite the default output folder used when "--output_frames" is specified. --use_vd use the new VD-based video decoders, instead of
diff --git a/extensions/browser/content_verifier.cc b/extensions/browser/content_verifier.cc index ea89a51..0ae23ed 100644 --- a/extensions/browser/content_verifier.cc +++ b/extensions/browser/content_verifier.cc
@@ -417,7 +417,7 @@ hash_helper_.reset(); } -ContentVerifyJob* ContentVerifier::CreateJobFor( +scoped_refptr<ContentVerifyJob> ContentVerifier::CreateAndStartJobFor( const std::string& extension_id, const base::FilePath& extension_root, const base::FilePath& relative_path) { @@ -446,9 +446,11 @@ // TODO(asargent) - we can probably get some good performance wins by having // a cache of ContentHashReader's that we hold onto past the end of each job. - return new ContentVerifyJob( + scoped_refptr<ContentVerifyJob> job = base::MakeRefCounted<ContentVerifyJob>( extension_id, data->version, extension_root, normalized_unix_path, base::BindOnce(&ContentVerifier::VerifyFailed, this, extension_id)); + job->Start(this); + return job; } void ContentVerifier::GetContentHash(
diff --git a/extensions/browser/content_verifier.h b/extensions/browser/content_verifier.h index c2b5b91..1f7c893b 100644 --- a/extensions/browser/content_verifier.h +++ b/extensions/browser/content_verifier.h
@@ -52,11 +52,13 @@ void Start(); void Shutdown(); - // Call this before reading a file within an extension. The caller owns the - // returned job. - ContentVerifyJob* CreateJobFor(const std::string& extension_id, - const base::FilePath& extension_root, - const base::FilePath& relative_path); + // Call this before reading a file within an extension. Returns and starts a + // content verify job if the specified resource requires content verification, + // otherwise returns nullptr. + scoped_refptr<ContentVerifyJob> CreateAndStartJobFor( + const std::string& extension_id, + const base::FilePath& extension_root, + const base::FilePath& relative_path); // ExtensionRegistryObserver interface void OnExtensionLoaded(content::BrowserContext* browser_context,
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc index 01c94f01..a9cf702 100644 --- a/extensions/browser/extension_protocols.cc +++ b/extensions/browser/extension_protocols.cc
@@ -573,11 +573,9 @@ scoped_refptr<net::HttpResponseHeaders> response_headers) { scoped_refptr<ContentVerifyJob> verify_job; if (content_verifier) { - verify_job = content_verifier->CreateJobFor(resource.extension_id(), - resource.extension_root(), - resource.relative_path()); - if (verify_job) - verify_job->Start(content_verifier.get()); + verify_job = content_verifier->CreateAndStartJobFor( + resource.extension_id(), resource.extension_root(), + resource.relative_path()); } content::CreateFileURLLoader(
diff --git a/extensions/browser/extension_user_script_loader.cc b/extensions/browser/extension_user_script_loader.cc index 9d9e9b1b..bd9ab82 100644 --- a/extensions/browser/extension_user_script_loader.cc +++ b/extensions/browser/extension_user_script_loader.cc
@@ -68,11 +68,9 @@ void VerifyContent(const VerifyContentInfo& info) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK(info.verifier); - ContentVerifier* verifier = info.verifier.get(); - scoped_refptr<ContentVerifyJob> job(verifier->CreateJobFor( + scoped_refptr<ContentVerifyJob> job(info.verifier->CreateAndStartJobFor( info.extension_id, info.extension_root, info.relative_path)); if (job.get()) { - job->Start(verifier); job->BytesRead(info.content.size(), info.content.data()); job->DoneReading(); }
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index d6aefe5..a2b2219 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn
@@ -545,6 +545,7 @@ "ipc/service/gpu_channel_test_common.cc", "ipc/service/gpu_channel_test_common.h", "ipc/service/gpu_channel_unittest.cc", + "ipc/service/gpu_watchdog_thread_unittest.cc", ] if (is_chromeos) {
diff --git a/gpu/ipc/service/gpu_watchdog_thread_unittest.cc b/gpu/ipc/service/gpu_watchdog_thread_unittest.cc new file mode 100644 index 0000000..d27ed1f4 --- /dev/null +++ b/gpu/ipc/service/gpu_watchdog_thread_unittest.cc
@@ -0,0 +1,107 @@ +// Copyright (c) 2019 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 "gpu/ipc/service/gpu_watchdog_thread_v2.h" + +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gpu { + +namespace { +constexpr auto kGpuWatchdogTimeout = base::TimeDelta::FromMilliseconds(1000); + +// This task will run for duration_ms milliseconds. +void SimpleTask(base::TimeDelta duration) { + base::PlatformThread::Sleep(duration); +} +} // namespace + +class GpuWatchdogTest : public testing::Test { + public: + GpuWatchdogTest() {} + + void LongTaskWithReportProgress(base::TimeDelta duration, + base::TimeDelta report_delta); + + // Implements testing::Test + void SetUp() override; + + protected: + ~GpuWatchdogTest() override = default; + base::MessageLoop main_loop; + base::RunLoop run_loop; + std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread_; +}; + +void GpuWatchdogTest::SetUp() { + ASSERT_TRUE(base::ThreadTaskRunnerHandle::IsSet()); + ASSERT_TRUE(base::MessageLoopCurrent::IsSet()); + + // Set watchdog timeout to 1000 milliseconds + watchdog_thread_ = gpu::GpuWatchdogThreadImplV2::Create( + /*start_backgrounded*/ false, + /*timeout*/ kGpuWatchdogTimeout, + /*test_mode*/ true); +} + +// This task will run for duration_ms milliseconds. It will also call watchdog +// ReportProgress() every report_delta_ms milliseconds. +void GpuWatchdogTest::LongTaskWithReportProgress(base::TimeDelta duration, + base::TimeDelta report_delta) { + base::TimeTicks start = base::TimeTicks::Now(); + base::TimeTicks end; + + do { + base::PlatformThread::Sleep(report_delta); + watchdog_thread_->ReportProgress(); + end = base::TimeTicks::Now(); + } while (end - start <= duration); +} + +// GPU Hang In Initialization +TEST_F(GpuWatchdogTest, GpuInitializationHang) { + // Gpu init (2000 ms) takes longer than timeout (1000 ms). + SimpleTask(kGpuWatchdogTimeout + base::TimeDelta::FromMilliseconds(1000)); + + // Gpu hangs. OnInitComplete() is not called + + bool result = watchdog_thread_->IsGpuHangDetected(); + EXPECT_TRUE(result); +} + +// Normal GPU Initialization and Running Task +TEST_F(GpuWatchdogTest, GpuInitializationAndRunningTasks) { + // Assume GPU initialization takes 300 milliseconds. + SimpleTask(base::TimeDelta::FromMilliseconds(300)); + watchdog_thread_->OnInitComplete(); + + // Start running GPU tasks. Watchdog function WillProcessTask(), + // DidProcessTask() and ReportProgress() are tested. + main_loop.task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&SimpleTask, base::TimeDelta::FromMilliseconds(500))); + main_loop.task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&SimpleTask, base::TimeDelta::FromMilliseconds(500))); + + // This long task takes 2000 milliseconds to finish, longer than timeout. + // But it reports progress every 500 milliseconds + main_loop.task_runner()->PostTask( + FROM_HERE, + base::BindOnce( + &GpuWatchdogTest::LongTaskWithReportProgress, base::Unretained(this), + kGpuWatchdogTimeout + base::TimeDelta::FromMilliseconds(1000), + base::TimeDelta::FromMilliseconds(500))); + + main_loop.task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure()); + run_loop.Run(); + + // Everything should be fine. No GPU hang detected. + bool result = watchdog_thread_->IsGpuHangDetected(); + EXPECT_FALSE(result); +} + +} // namespace gpu
diff --git a/gpu/ipc/service/image_decode_accelerator_stub.cc b/gpu/ipc/service/image_decode_accelerator_stub.cc index e2701764..78fe94ce 100644 --- a/gpu/ipc/service/image_decode_accelerator_stub.cc +++ b/gpu/ipc/service/image_decode_accelerator_stub.cc
@@ -6,6 +6,7 @@ #include <stddef.h> +#include <algorithm> #include <new> #include <utility> #include <vector> @@ -17,6 +18,8 @@ #include "base/location.h" #include "base/logging.h" #include "base/numerics/checked_math.h" +#include "base/numerics/safe_conversions.h" +#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "build/build_config.h" #include "gpu/command_buffer/common/constants.h" @@ -26,6 +29,7 @@ #include "gpu/command_buffer/common/sync_token.h" #include "gpu/command_buffer/service/context_group.h" #include "gpu/command_buffer/service/decoder_context.h" +#include "gpu/command_buffer/service/gr_shader_cache.h" #include "gpu/command_buffer/service/image_factory.h" #include "gpu/command_buffer/service/scheduler.h" #include "gpu/command_buffer/service/service_transfer_cache.h" @@ -235,13 +239,18 @@ } std::vector<sk_sp<SkImage>> plane_sk_images; + base::Optional<base::ScopedClosureRunner> notify_gl_state_changed; #if defined(OS_CHROMEOS) - // Right now, we only support YUV 4:2:0 for the output of the decoder. + // Right now, we only support YUV 4:2:0 for the output of the decoder. Note + // that the we get the planes in YVU order, but we need them in YUV order to + // create the transfer cache entry. // // TODO(andrescj): change to gfx::BufferFormat::YUV_420 once // https://crrev.com/c/1573718 lands. DCHECK_EQ(gfx::BufferFormat::YVU_420, completed_decode->buffer_format); DCHECK_EQ(3u, completed_decode->handle.native_pixmap_handle.planes.size()); + std::swap(completed_decode->handle.native_pixmap_handle.planes[1], + completed_decode->handle.native_pixmap_handle.planes[2]); // Calculate the dimensions of each of the planes. const gfx::Size y_plane_size = completed_decode->visible_size; @@ -261,6 +270,18 @@ } gfx::Size uv_plane_size = gfx::Size(uv_width, uv_height); + // We should notify the SharedContextState that we or Skia may have modified + // the driver's GL state. We should also notify Skia that we may have modified + // the graphics API state outside of Skia. We put this in a + // ScopedClosureRunner so that if we return early, both the SharedContextState + // and Skia end up in a consistent state. + notify_gl_state_changed.emplace(base::BindOnce( + [](scoped_refptr<SharedContextState> scs) { + scs->set_need_context_state_reset(true); + scs->PessimisticallyResetGrContext(); + }, + shared_context_state)); + // Create a gl::GLImage for each plane and attach it to a texture. plane_sk_images.resize(3u); for (size_t plane = 0u; plane < 3u; plane++) { @@ -318,6 +339,9 @@ return; } + // Notify Skia that we have changed the driver's GL state outside of Skia. + shared_context_state->PessimisticallyResetGrContext(); + // Create a SkImage using the texture. const GrBackendTexture plane_backend_texture( plane_size.width(), plane_size.height(), GrMipMapped::kNo, @@ -368,22 +392,31 @@ OnError(); return; } - DCHECK(shared_context_state->transfer_cache()); - if (!shared_context_state->transfer_cache() - ->CreateLockedHardwareDecodedImageEntry( - command_buffer->decoder_context()->GetRasterDecoderId(), - params.transfer_cache_entry_id, - ServiceDiscardableHandle(std::move(handle_buffer), - params.discardable_handle_shm_offset, - params.discardable_handle_shm_id), - shared_context_state->gr_context(), std::move(plane_sk_images), - completed_decode->buffer_byte_size, params.needs_mips, - params.target_color_space.ToSkColorSpace())) { - DLOG(ERROR) << "Could not create and insert the transfer cache entry"; - OnError(); - return; + + { + auto* gr_shader_cache = channel_->gpu_channel_manager()->gr_shader_cache(); + base::Optional<raster::GrShaderCache::ScopedCacheUse> cache_use; + if (gr_shader_cache) + cache_use.emplace(gr_shader_cache, + base::strict_cast<int32_t>(channel_->client_id())); + DCHECK(shared_context_state->transfer_cache()); + if (!shared_context_state->transfer_cache() + ->CreateLockedHardwareDecodedImageEntry( + command_buffer->decoder_context()->GetRasterDecoderId(), + params.transfer_cache_entry_id, + ServiceDiscardableHandle(std::move(handle_buffer), + params.discardable_handle_shm_offset, + params.discardable_handle_shm_id), + shared_context_state->gr_context(), std::move(plane_sk_images), + completed_decode->buffer_byte_size, params.needs_mips, + params.target_color_space.ToSkColorSpace())) { + DLOG(ERROR) << "Could not create and insert the transfer cache entry"; + OnError(); + return; + } } - shared_context_state->set_need_context_state_reset(true); + DCHECK(notify_gl_state_changed); + notify_gl_state_changed->RunAndReset(); // All done! The decoded image can now be used for rasterization, so we can // release the decode sync token.
diff --git a/ios/build/bots/chromium.clang/ToTiOSDevice.json b/ios/build/bots/chromium.clang/ToTiOSDevice.json index 7ee7722..78a5a90 100644 --- a/ios/build/bots/chromium.clang/ToTiOSDevice.json +++ b/ios/build/bots/chromium.clang/ToTiOSDevice.json
@@ -37,87 +37,104 @@ { "app": "base_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "boringssl_crypto_tests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "boringssl_ssl_tests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "components_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "crypto_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "gfx_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "google_apis_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "ios_chrome_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "ios_net_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "ios_web_inttests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "ios_web_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "ios_web_view_inttests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "net_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "skia_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "sql_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "ui_base_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" }, { "app": "url_unittests", "device type": "iPhone 6s", - "os": "11.4.1" + "xcode build version": "10e1001", + "os": "12.3.1" } ], "expiration_time": 10800
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc index 8c0b776..74c734de 100644 --- a/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc +++ b/ios/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -43,7 +43,7 @@ protected: // Returns the collection of default datatypes. std::vector<syncer::ModelType> DefaultDatatypes() { - static_assert(45 == syncer::ModelType::NUM_ENTRIES, + static_assert(46 == syncer::ModelType::NUM_ENTRIES, "When adding a new type, you probably want to add it here as " "well (assuming it is already enabled).");
diff --git a/ios/chrome/browser/ui/authentication/cells/account_control_item.mm b/ios/chrome/browser/ui/authentication/cells/account_control_item.mm index 1048a4c4..9fd731b 100644 --- a/ios/chrome/browser/ui/authentication/cells/account_control_item.mm +++ b/ios/chrome/browser/ui/authentication/cells/account_control_item.mm
@@ -7,6 +7,7 @@ #include "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -35,9 +36,9 @@ cell.textLabel.textColor = UIColor.cr_labelColor; cell.detailTextLabel.text = self.detailText; - cell.detailTextLabel.textColor = self.shouldDisplayError - ? UIColor.redColor - : UIColor.cr_secondaryLabelColor; + cell.detailTextLabel.textColor = + self.shouldDisplayError ? [UIColor colorNamed:kDestructiveTintColor] + : UIColor.cr_secondaryLabelColor; } #pragma mark - Helper methods
diff --git a/ios/chrome/browser/ui/authentication/cells/account_control_item_unittest.mm b/ios/chrome/browser/ui/authentication/cells/account_control_item_unittest.mm index f10dcbb4..6288a33b 100644 --- a/ios/chrome/browser/ui/authentication/cells/account_control_item_unittest.mm +++ b/ios/chrome/browser/ui/authentication/cells/account_control_item_unittest.mm
@@ -8,6 +8,7 @@ #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #include "testing/gtest/include/gtest/gtest.h" #import "testing/gtest_mac.h" #include "testing/platform_test.h" @@ -82,5 +83,6 @@ EXPECT_NSEQ(mainText, accountCell.textLabel.text); EXPECT_NSEQ(detailText, accountCell.detailTextLabel.text); EXPECT_EQ(UITableViewCellAccessoryCheckmark, accountCell.accessoryType); - EXPECT_NSEQ(UIColor.redColor, accountCell.detailTextLabel.textColor); + EXPECT_NSEQ([UIColor colorNamed:kDestructiveTintColor], + accountCell.detailTextLabel.textColor); }
diff --git a/ios/chrome/browser/ui/authentication/cells/table_view_account_item.mm b/ios/chrome/browser/ui/authentication/cells/table_view_account_item.mm index 31fe0bb..3c6080f7 100644 --- a/ios/chrome/browser/ui/authentication/cells/table_view_account_item.mm +++ b/ios/chrome/browser/ui/authentication/cells/table_view_account_item.mm
@@ -9,6 +9,7 @@ #include "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -50,8 +51,10 @@ cell.textLabel.text = self.text; cell.detailTextLabel.text = self.detailText; if (self.shouldDisplayError) { - cell.errorIcon.image = [UIImage imageNamed:@"settings_error"]; - cell.detailTextLabel.textColor = UIColor.redColor; + cell.errorIcon.image = [[UIImage imageNamed:@"settings_error"] + imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.errorIcon.tintColor = [UIColor colorNamed:kDestructiveTintColor]; + cell.detailTextLabel.textColor = [UIColor colorNamed:kDestructiveTintColor]; } else { cell.errorIcon.image = nil; cell.detailTextLabel.textColor = UIColor.cr_secondaryLabelColor;
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn b/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn index 028423b..61cfa0a5d 100644 --- a/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn +++ b/ios/chrome/browser/ui/authentication/unified_consent/BUILD.gn
@@ -44,6 +44,7 @@ "//ios/chrome/browser/ui/util", "//ios/chrome/browser/ui/util", "//ios/chrome/common", + "//ios/chrome/common/colors", "//ios/chrome/common/ui_util", "//ios/third_party/material_components_ios", "//ui/base",
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/BUILD.gn b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/BUILD.gn index 79b99548..14769fb4 100644 --- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/BUILD.gn +++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/BUILD.gn
@@ -62,6 +62,7 @@ "//ios/chrome/browser/ui/util", "//ios/chrome/browser/ui/util", "//ios/chrome/common", + "//ios/chrome/common/colors", "//ios/chrome/common/ui_util", "//ios/third_party/material_components_ios", "//ui/base",
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_header_item.mm b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_header_item.mm index b224d024..50ded925 100644 --- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_header_item.mm +++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_header_item.mm
@@ -4,6 +4,7 @@ #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_header_item.h" +#import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h" #import "ios/chrome/common/ui_util/constraints_ui_util.h" #include "ios/chrome/grit/ios_strings.h" #import "ui/base/l10n/l10n_util.h" @@ -18,8 +19,6 @@ CGFloat kBottomMargin = 15; // Leading margin for the label. CGFloat kLeadingMargin = 24.; -// Label font color alpha. -CGFloat kFontAlpha = .87; } // namespace @interface IdentityChooserHeaderView : UITableViewHeaderFooterView @@ -36,7 +35,7 @@ label.text = l10n_util::GetNSString(IDS_IOS_ACCOUNT_IDENTITY_CHOOSER_CHOOSE_ACCOUNT); label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; - label.textColor = [UIColor colorWithWhite:0. alpha:kFontAlpha]; + label.textColor = UIColor.cr_labelColor; [self.contentView addSubview:label]; NSDictionary* views = @{ @"label" : label,
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_view_controller.mm b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_view_controller.mm index 48da05d..96cf42c 100644 --- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_view_controller.mm +++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_view_controller.mm
@@ -57,6 +57,7 @@ } - (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; [self.presentationDelegate identityChooserViewControllerDidDisappear:self]; }
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_view.mm b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_view.mm index 99dcebaf..8d5c670 100644 --- a/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_view.mm +++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_view.mm
@@ -6,6 +6,7 @@ #include "base/logging.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h" #import "ios/chrome/common/ui_util/constraints_ui_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -20,9 +21,6 @@ const CGFloat kTitleOffset = 4; const CGFloat kHorizontalAvatarMargin = 16.; const CGFloat kVerticalMargin = 12.; -// Colors -const CGFloat kTitleTextColorAlpha = .87; -const CGFloat kSubtitleTextColorAlpha = .54; } // namespace @@ -65,7 +63,7 @@ _title = [[UILabel alloc] init]; _title.translatesAutoresizingMaskIntoConstraints = NO; _title.numberOfLines = 0; - _title.textColor = [UIColor colorWithWhite:0 alpha:kTitleTextColorAlpha]; + _title.textColor = UIColor.cr_labelColor; _title.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]; [self addSubview:_title]; @@ -73,8 +71,7 @@ _subtitle = [[UILabel alloc] init]; _subtitle.translatesAutoresizingMaskIntoConstraints = NO; _subtitle.numberOfLines = 0; - _subtitle.textColor = - [UIColor colorWithWhite:0 alpha:kSubtitleTextColorAlpha]; + _subtitle.textColor = UIColor.cr_secondaryLabelColor; _subtitle.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1]; [self addSubview:_subtitle];
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm b/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm index af1c51f..6a4dbcaf 100644 --- a/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm +++ b/ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.mm
@@ -8,6 +8,7 @@ #import "ios/chrome/browser/ui/authentication/authentication_constants.h" #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_view.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h" #import "ios/chrome/common/ui_util/constraints_ui_util.h" #import "ios/third_party/material_components_ios/src/components/Ink/src/MaterialInk.h" @@ -25,8 +26,6 @@ const CGFloat kArrowDownSize = 24.; // Distances/margins. const CGFloat kArrowDownMargin = 12.; -// Colors -const int kHeaderBackgroundColor = 0xf1f3f4; } // namespace @@ -51,7 +50,7 @@ if (self) { self.accessibilityIdentifier = kIdentityPickerViewIdentifier; self.layer.cornerRadius = kIdentityPickerViewRadius; - self.backgroundColor = UIColorFromRGB(kHeaderBackgroundColor); + self.backgroundColor = UIColor.cr_secondarySystemBackgroundColor; // Adding view elements inside. // Ink view. _inkView = [[MDCInkView alloc] initWithFrame:CGRectZero];
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm index e8a28e5..96fe4b2 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
@@ -302,10 +302,6 @@ // Tests that the Password View Controller is not present when presenting UI. - (void)testPasswordControllerPauses { - // For the search bar to appear in password settings at least one password is - // needed. - SaveExamplePasswordForm(); - // Bring up the keyboard. [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] performAction:chrome_test_util::TapWebElement(kFormElementUsername)]; @@ -338,9 +334,6 @@ return; } - // For this test one password is needed. - SaveExamplePasswordForm(); - // Bring up the keyboard. [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] performAction:chrome_test_util::TapWebElement(kFormElementUsername)];
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm index 8814da3..2ccaeb83 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
@@ -34,6 +34,7 @@ #include "ios/chrome/browser/ui/util/rtl_geometry.h" #include "ios/chrome/browser/ui/util/ui_util.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #import "ios/chrome/common/ui_util/constraints_ui_util.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/public/provider/chrome/browser/chrome_browser_provider.h" @@ -71,9 +72,6 @@ ItemTypeInvalidURLFooter, }; -// The text color for the invalid URL label. -const CGFloat kInvalidURLTextColor = 0xEA4335; - // Estimated Table Row height. const CGFloat kEstimatedTableRowHeight = 50; // Estimated TableSection Footer height. @@ -257,7 +255,7 @@ target:nil action:nil]; - deleteButton.tintColor = UIColor.redColor; + deleteButton.tintColor = [UIColor colorNamed:kDestructiveTintColor]; // Setting the image to nil will cause the default shadowImage to be used, // we need to create a new one. [self.navigationController.toolbar setShadowImage:[UIImage new] @@ -541,7 +539,8 @@ base::mac::ObjCCastStrict<UITableViewHeaderFooterView>(footerView); headerFooterView.textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1]; - headerFooterView.textLabel.textColor = UIColorFromRGB(kInvalidURLTextColor); + headerFooterView.textLabel.textColor = + [UIColor colorNamed:kDestructiveTintColor]; } return footerView; }
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm index 20f10703..53429862 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
@@ -26,6 +26,7 @@ #import "ios/chrome/browser/ui/material_components/utils.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" #include "ios/chrome/browser/ui/util/rtl_geometry.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #import "ios/chrome/common/ui_util/constraints_ui_util.h" #include "ios/chrome/grit/ios_strings.h" #include "ui/base/l10n/l10n_util.h" @@ -472,7 +473,7 @@ initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; - deleteButton.tintColor = UIColor.redColor; + deleteButton.tintColor = [UIColor colorNamed:kDestructiveTintColor]; [self.navigationController.toolbar setShadowImage:[UIImage new] forToolbarPosition:UIBarPositionAny]; [self setToolbarItems:@[ spaceButton, deleteButton, spaceButton ]
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm index 8adb5fa7..3584db3 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -50,6 +50,7 @@ #import "ios/chrome/browser/url_loading/url_loading_params.h" #import "ios/chrome/browser/url_loading/url_loading_service.h" #import "ios/chrome/browser/url_loading/url_loading_service_factory.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #import "ios/chrome/common/favicon/favicon_attributes.h" #import "ios/chrome/common/favicon/favicon_view.h" #import "ios/chrome/common/ui_util/constraints_ui_util.h" @@ -1510,7 +1511,7 @@ style:UIBarButtonItemStylePlain target:self action:@selector(leadingButtonClicked)]; - self.deleteButton.tintColor = UIColor.redColor; + self.deleteButton.tintColor = [UIColor colorNamed:kDestructiveTintColor]; self.deleteButton.enabled = NO; self.deleteButton.accessibilityIdentifier = kBookmarkHomeLeadingButtonIdentifier;
diff --git a/ios/chrome/browser/ui/infobars/presentation/infobar_expand_banner_animator.mm b/ios/chrome/browser/ui/infobars/presentation/infobar_expand_banner_animator.mm index bf59fde7..22a4dad 100644 --- a/ios/chrome/browser/ui/infobars/presentation/infobar_expand_banner_animator.mm +++ b/ios/chrome/browser/ui/infobars/presentation/infobar_expand_banner_animator.mm
@@ -54,9 +54,9 @@ presentedViewFinalFrame = [transitionContext finalFrameForViewController:presentedViewController]; - CGRect initialFrame = [presentingViewController.view - convertRect:presentingViewController.view.frame - toView:nil]; + CGRect bannerFrame = presentingViewController.view.frame; + CGRect initialFrame = presentedView.frame; + initialFrame.size.height = bannerFrame.size.height; presentedView.frame = initialFrame; }
diff --git a/ios/chrome/browser/ui/settings/password/BUILD.gn b/ios/chrome/browser/ui/settings/password/BUILD.gn index 68636df..7d67fba 100644 --- a/ios/chrome/browser/ui/settings/password/BUILD.gn +++ b/ios/chrome/browser/ui/settings/password/BUILD.gn
@@ -39,6 +39,7 @@ "//ios/chrome/browser/ui/table_view", "//ios/chrome/browser/ui/table_view/cells", "//ios/chrome/browser/ui/util", + "//ios/chrome/common/colors", "//ios/chrome/common/ui_util", "//ios/third_party/material_components_ios", "//ui/base", @@ -86,6 +87,7 @@ "//ios/chrome/browser/ui/table_view/cells", "//ios/chrome/browser/ui/util", "//ios/chrome/browser/web:test_support", + "//ios/chrome/common/colors", "//ios/chrome/test/app:test_support", "//ios/web/public/test", "//ios/web/public/test",
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm index 0830a407..1bbdb22d 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -72,6 +72,7 @@ #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #include "ios/chrome/browser/voice/speech_input_locale_config.h" #import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #include "ios/chrome/grit/ios_chromium_strings.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/public/provider/chrome/browser/chrome_browser_provider.h" @@ -1039,7 +1040,8 @@ googleServicesItem.image = [UIImage imageNamed:kSyncAndGoogleServicesSyncOnImageName]; } else if (!IsTransientSyncError(syncSetupService->GetSyncServiceState())) { - googleServicesItem.detailTextColor = UIColor.redColor; + googleServicesItem.detailTextColor = + [UIColor colorNamed:kDestructiveTintColor]; googleServicesItem.detailText = GetSyncErrorDescriptionForSyncSetupService(syncSetupService); googleServicesItem.image =
diff --git a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm index 7ebddf1..925ecaa 100644 --- a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm +++ b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
@@ -29,6 +29,7 @@ #include "ios/chrome/browser/ui/ui_feature_flags.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" #import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #import "ios/public/provider/chrome/browser/chrome_browser_provider.h" #import "ios/public/provider/chrome/browser/signin/signin_resources_provider.h" #include "url/gurl.h" @@ -133,10 +134,10 @@ TableViewImageItem* textImageItem2 = [[TableViewImageItem alloc] initWithType:ItemTypeTextAccessoryImage]; textImageItem2.title = @"Image item without image, and disabled"; - textImageItem2.textColor = UIColor.redColor; + textImageItem2.textColor = [UIColor colorNamed:kDestructiveTintColor]; textImageItem2.detailText = @"Very very very long detail text for the image cell without image"; - textImageItem2.detailTextColor = UIColor.redColor; + textImageItem2.detailTextColor = [UIColor colorNamed:kDestructiveTintColor]; textImageItem2.enabled = NO; [model addItem:textImageItem2 toSectionWithIdentifier:SectionIdentifierText];
diff --git a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm index 673294d..8473165 100644 --- a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm +++ b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
@@ -70,8 +70,28 @@ [interaction performAction:grey_tap()]; } +// Removes all browsing data. +void RemoveBrowsingData() { + __block BOOL browsing_data_removed = NO; + [chrome_test_util::GetMainController() + removeBrowsingDataForBrowserState:chrome_test_util:: + GetOriginalBrowserState() + timePeriod:browsing_data::TimePeriod::ALL_TIME + removeMask:BrowsingDataRemoveMask::REMOVE_ALL + completionBlock:^{ + browsing_data_removed = YES; + }]; + GREYCondition* condition = + [GREYCondition conditionWithName:@"Wait for removing browsing data." + block:^BOOL { + return browsing_data_removed; + }]; + GREYAssert([condition waitWithTimeout:base::test::ios::kWaitForActionTimeout], + @"Browsing data was not removed."); } +} // namespace + // Sign-in interaction tests that work both with Unified Consent enabled or // disabled. @interface SigninInteractionControllerTestCase : ChromeTestCase @@ -79,6 +99,13 @@ @implementation SigninInteractionControllerTestCase +- (void)setUp { + [super setUp]; + // Remove closed tab history to make sure the sign-in promo is always visible + // in recent tabs. + RemoveBrowsingData(); +} + // Tests that opening the sign-in screen from the Settings and signing in works // correctly when there is already an identity on the device. - (void)testSignInOneUser { @@ -391,9 +418,7 @@ // Tests to dismiss sign-in by opening an URL from another app. // Sign-in opened from: tab switcher. // Interrupted at: user consent. -// TODO(crbug.com/976828): Test flaky based on the screen size and the number -// of recently closed tabs from the previous tests. -- (void)DISABLED_testDismissSigninFromTabSwitcher { +- (void)testDismissSigninFromTabSwitcher { [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromTabSwitcher tapSettingsLink:NO]; } @@ -401,9 +426,7 @@ // Tests to dismiss sign-in by opening an URL from another app. // Sign-in opened from: tab switcher. // Interrupted at: advanced sign-in. -// TODO(crbug.com/976828): Test flaky based on the screen size and the number -// of recently closed tabs from the previous tests. -- (void)DISABLED_testDismissSigninFromTabSwitcherFromAdvancedSigninSettings { +- (void)testDismissSigninFromTabSwitcherFromAdvancedSigninSettings { [self assertOpenURLWhenSigninFromView:OpenSigninMethodFromTabSwitcher tapSettingsLink:YES]; }
diff --git a/ios/chrome/common/colors/resources/BUILD.gn b/ios/chrome/common/colors/resources/BUILD.gn index 348478d..0e373a8 100644 --- a/ios/chrome/common/colors/resources/BUILD.gn +++ b/ios/chrome/common/colors/resources/BUILD.gn
@@ -6,11 +6,18 @@ group("resources") { deps = [ + ":destructive_tint_color", ":solid_button_text_color", ":tint_color", ] } +colorset("destructive_tint_color") { + sources = [ + "destructive_tint_color.colorset/Contents.json", + ] +} + colorset("solid_button_text_color") { sources = [ "solid_button_text_color.colorset/Contents.json",
diff --git a/ios/chrome/common/colors/resources/destructive_tint_color.colorset/Contents.json b/ios/chrome/common/colors/resources/destructive_tint_color.colorset/Contents.json new file mode 100644 index 0000000..f534a807 --- /dev/null +++ b/ios/chrome/common/colors/resources/destructive_tint_color.colorset/Contents.json
@@ -0,0 +1,38 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "display-p3", + "components" : { + "red" : "0xD9", + "alpha" : "1.000", + "blue" : "0x25", + "green" : "0x30" + } + } + }, + { + "idiom" : "universal", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "red" : "0xF2", + "alpha" : "1.000", + "blue" : "0x82", + "green" : "0x8B" + } + } + } + ] +} \ No newline at end of file
diff --git a/ios/chrome/common/colors/semantic_color_names.h b/ios/chrome/common/colors/semantic_color_names.h index e42f80d..b9168a0 100644 --- a/ios/chrome/common/colors/semantic_color_names.h +++ b/ios/chrome/common/colors/semantic_color_names.h
@@ -7,6 +7,7 @@ #import <UIKit/UIKit.h> +extern NSString* const kDestructiveTintColor; extern NSString* const kSolidButtonTextColor; extern NSString* const kTintColor;
diff --git a/ios/chrome/common/colors/semantic_color_names.mm b/ios/chrome/common/colors/semantic_color_names.mm index 1ea1587..46d5ebc 100644 --- a/ios/chrome/common/colors/semantic_color_names.mm +++ b/ios/chrome/common/colors/semantic_color_names.mm
@@ -8,5 +8,6 @@ #error "This file requires ARC support." #endif +NSString* const kDestructiveTintColor = @"destructive_tint_color"; NSString* const kSolidButtonTextColor = @"solid_button_text_color"; NSString* const kTintColor = @"tint_color";
diff --git a/ios/chrome/test/wpt/cwt_request_handler.mm b/ios/chrome/test/wpt/cwt_request_handler.mm index 33ea204..247a307 100644 --- a/ios/chrome/test/wpt/cwt_request_handler.mm +++ b/ios/chrome/test/wpt/cwt_request_handler.mm
@@ -4,6 +4,7 @@ #import "ios/chrome/test/wpt/cwt_request_handler.h" +#include "base/debug/stack_trace.h" #include "base/guid.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" @@ -81,6 +82,7 @@ const char kWebDriverErrorCodeValueField[] = "error"; const char kWebDriverErrorMessageValueField[] = "message"; const char kWebDriverSessionIdValueField[] = "sessionId"; +const char kWebDriverStackTraceValueField[] = "stacktrace"; // Field names for the "capabilities" struct that's included in the response // when creating a session. @@ -105,6 +107,8 @@ base::Value error_value(base::Value::Type::DICTIONARY); error_value.SetStringKey(kWebDriverErrorCodeValueField, error); error_value.SetStringKey(kWebDriverErrorMessageValueField, message); + error_value.SetStringKey(kWebDriverStackTraceValueField, + base::debug::StackTrace().ToString()); return error_value; }
diff --git a/ios/testing/earl_grey/base_earl_grey_test_case.mm b/ios/testing/earl_grey/base_earl_grey_test_case.mm index 8311c78..416311df 100644 --- a/ios/testing/earl_grey/base_earl_grey_test_case.mm +++ b/ios/testing/earl_grey/base_earl_grey_test_case.mm
@@ -22,6 +22,15 @@ GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(BaseEarlGreyTestCaseAppInterface) #endif // defined(CHROME_EARL_GREY_2) +namespace { + +// If true, +setUpForTestCase will be called from -setUp. This flag is used to +// ensure that +setUpForTestCase is called exactly once per unique XCTestCase +// and is reset in +tearDown. +bool g_needs_set_up_for_test_case = true; + +} // namespace + @implementation BaseEarlGreyTestCase + (void)setUpForTestCase { @@ -46,11 +55,16 @@ [self failIfSetUpIsOverridden]; #endif - static dispatch_once_t setupToken; - dispatch_once(&setupToken, ^{ + if (g_needs_set_up_for_test_case) { + g_needs_set_up_for_test_case = false; [CoverageUtils configureCoverageReportPath]; [[self class] setUpForTestCase]; - }); + } +} + ++ (void)tearDown { + g_needs_set_up_for_test_case = true; + [super tearDown]; } // Handles system alerts if any are present, closing them to unblock the UI.
diff --git a/ios/web/navigation/crw_web_view_navigation_observer.mm b/ios/web/navigation/crw_web_view_navigation_observer.mm index 1a0ca1c28..7fbd2d01 100644 --- a/ios/web/navigation/crw_web_view_navigation_observer.mm +++ b/ios/web/navigation/crw_web_view_navigation_observer.mm
@@ -124,9 +124,7 @@ // Called when WKWebView estimatedProgress has been changed. - (void)webViewEstimatedProgressDidChange { - if (![self.delegate webViewIsBeingDestroyed:self]) { - self.webStateImpl->SendChangeLoadProgress(self.webView.estimatedProgress); - } + self.webStateImpl->SendChangeLoadProgress(self.webView.estimatedProgress); } // Called when WKWebView loading state has been changed.
diff --git a/ios/web/navigation/crw_web_view_navigation_observer_delegate.h b/ios/web/navigation/crw_web_view_navigation_observer_delegate.h index 2577345..f70853f 100644 --- a/ios/web/navigation/crw_web_view_navigation_observer_delegate.h +++ b/ios/web/navigation/crw_web_view_navigation_observer_delegate.h
@@ -16,10 +16,6 @@ // Delegate for the NavigationObserver. @protocol CRWWebViewNavigationObserverDelegate -// Whether the the web view is being closed. -- (BOOL)webViewIsBeingDestroyed: - (CRWWebViewNavigationObserver*)navigationObserver; - // The WebState. - (web::WebStateImpl*)webStateImplForNavigationObserver: (CRWWebViewNavigationObserver*)navigationObserver;
diff --git a/ios/web/navigation/crw_wk_navigation_handler.h b/ios/web/navigation/crw_wk_navigation_handler.h index e24823a..0fbf866 100644 --- a/ios/web/navigation/crw_wk_navigation_handler.h +++ b/ios/web/navigation/crw_wk_navigation_handler.h
@@ -55,10 +55,6 @@ legacyNativeContentControllerForNavigationHandler: (CRWWKNavigationHandler*)navigationHandler; -// Returns YES if WKWebView was deallocated or is being deallocated. -- (BOOL)navigationHandlerWebViewBeingDestroyed: - (CRWWKNavigationHandler*)navigationHandler; - // Returns the actual URL of the document object (i.e., the last committed URL // of the main frame). - (GURL)navigationHandlerDocumentURL:(CRWWKNavigationHandler*)navigationHandler; @@ -164,6 +160,9 @@ // Returns the referrer for the current page. @property(nonatomic, readonly, assign) web::Referrer currentReferrer; +// Instructs this handler to close. +- (void)close; + // Instructs this handler to stop loading. - (void)stopLoading;
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm index a63ddbf7..0c71f0b 100644 --- a/ios/web/navigation/crw_wk_navigation_handler.mm +++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -120,6 +120,9 @@ @property(nonatomic, readonly, weak) CRWLegacyNativeContentController* legacyNativeContentController; +// Set to YES when [self close] is called. +@property(nonatomic, assign) BOOL beingDestroyed; + @end @implementation CRWWKNavigationHandler @@ -149,7 +152,7 @@ [self didReceiveWKNavigationDelegateCallback]; self.webProcessCrashed = NO; - if ([self.delegate navigationHandlerWebViewBeingDestroyed:self]) { + if (self.beingDestroyed) { decisionHandler(WKNavigationActionPolicyCancel); return; } @@ -243,7 +246,7 @@ (action.navigationType == WKNavigationTypeFormResubmitted)) { self.webStateImpl->ShowRepostFormWarningDialog( base::BindOnce(^(bool shouldContinue) { - if ([self.delegate navigationHandlerWebViewBeingDestroyed:self]) { + if (self.beingDestroyed) { decisionHandler(WKNavigationActionPolicyCancel); } else if (shouldContinue) { decisionHandler(WKNavigationActionPolicyAllow); @@ -340,7 +343,7 @@ allowLoad = self.webStateImpl->ShouldAllowRequest(action.request, requestInfo); // The WebState may have been closed in the ShouldAllowRequest callback. - if ([self.delegate navigationHandlerWebViewBeingDestroyed:self]) { + if (self.beingDestroyed) { decisionHandler(WKNavigationActionPolicyCancel); return; } @@ -379,7 +382,7 @@ context->ReleaseItem(); } - if (![self.delegate navigationHandlerWebViewBeingDestroyed:self] && + if (!self.beingDestroyed && [self shouldClosePageOnNativeApplicationLoad]) { // Loading was started for user initiated navigations and should be // stopped because no other WKWebView callbacks are called. @@ -392,7 +395,7 @@ } } - if (![self.delegate navigationHandlerWebViewBeingDestroyed:self]) { + if (!self.beingDestroyed) { // Loading was started for user initiated navigations and should be // stopped because no other WKWebView callbacks are called. // TODO(crbug.com/767092): Loading should not start until webView.loading @@ -1214,7 +1217,7 @@ // this point it's too late for a SafeBrowsing warning to be displayed for the // navigation for which the timer was started. - (void)didReceiveWKNavigationDelegateCallback { - if ([self.delegate navigationHandlerWebViewBeingDestroyed:self]) { + if (self.beingDestroyed) { UMA_HISTOGRAM_BOOLEAN("Renderer.WKWebViewCallbackAfterDestroy", true); } _safeBrowsingWarningDetectionTimer.Stop(); @@ -2033,6 +2036,10 @@ #pragma mark - Public methods +- (void)close { + self.beingDestroyed = YES; +} + - (void)stopLoading { _stoppedWKNavigation = [self.navigationStates lastAddedNavigation]; self.pendingNavigationInfo.cancelled = YES; @@ -2045,7 +2052,7 @@ // TODO(crbug.com/821995): Check if this function should be removed. if (self.navigationState != web::WKNavigationState::FINISHED) { self.navigationState = web::WKNavigationState::FINISHED; - if (![self.delegate navigationHandlerWebViewBeingDestroyed:self]) { + if (!self.beingDestroyed) { self.webStateImpl->SetIsLoading(false); } }
diff --git a/ios/web/web_state/ui/controller/crw_legacy_native_content_controller.mm b/ios/web/web_state/ui/controller/crw_legacy_native_content_controller.mm index f5fbf490..bec50847 100644 --- a/ios/web/web_state/ui/controller/crw_legacy_native_content_controller.mm +++ b/ios/web/web_state/ui/controller/crw_legacy_native_content_controller.mm
@@ -28,6 +28,9 @@ @property(nonatomic, assign, readonly) web::NavigationManagerImpl* navigationManagerImpl; @property(nonatomic, assign, readonly) web::NavigationItemImpl* currentNavItem; +// Set to YES when [self close] is called. +@property(nonatomic, assign) BOOL beingDestroyed; + @end @implementation CRWLegacyNativeContentController @@ -194,6 +197,7 @@ } - (void)close { + self.beingDestroyed = YES; self.nativeProvider = nil; if ([self.nativeController respondsToSelector:@selector(close)]) [self.nativeController close]; @@ -234,7 +238,7 @@ - (void)nativeContent:(id)content handleContextMenu:(const web::ContextMenuParams&)params { - if ([self.delegate legacyNativeContentControllerIsBeingDestroyed:self]) { + if (self.beingDestroyed) { return; } self.webStateImpl->HandleContextMenu(params);
diff --git a/ios/web/web_state/ui/controller/crw_legacy_native_content_controller_delegate.h b/ios/web/web_state/ui/controller/crw_legacy_native_content_controller_delegate.h index d373f74..30a54a2d 100644 --- a/ios/web/web_state/ui/controller/crw_legacy_native_content_controller_delegate.h +++ b/ios/web/web_state/ui/controller/crw_legacy_native_content_controller_delegate.h
@@ -22,10 +22,6 @@ - (BOOL)legacyNativeContentControllerWebUsageEnabled: (CRWLegacyNativeContentController*)contentController; -// Whether the delegate is being destroyed. -- (BOOL)legacyNativeContentControllerIsBeingDestroyed: - (CRWLegacyNativeContentController*)contentController; - // Asks the delegate to remove the web view. - (void)legacyNativeContentControllerRemoveWebView: (CRWLegacyNativeContentController*)contentController;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index b6db826d..c1f6950 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -416,26 +416,40 @@ DCHECK_NE(_webView, webView); // Unwind the old web view. - CRWWKScriptMessageRouter* messageRouter = - [self webViewConfigurationProvider].GetScriptMessageRouter(); - web::WebFramesManagerImpl::FromWebState(self.webStateImpl) - ->OnWebViewUpdated(_webView, webView, messageRouter); - if (_webView) { - // TODO(crbug.com/956516): Use removeScriptMessageHandlerForName:webView: - // for |kScriptMessageName| and let CRWContextMenuController unregister its - // own callback. - [messageRouter removeAllScriptMessageHandlersForWebView:_webView]; - } + + // Remove KVO and WK*Delegate before calling methods on WKWebView so that + // handlers won't receive unnecessary callbacks. [_webView setNavigationDelegate:nil]; [_webView setUIDelegate:nil]; for (NSString* keyPath in self.WKWebViewObservers) { [_webView removeObserver:self forKeyPath:keyPath]; } + CRWWKScriptMessageRouter* messageRouter = + [self webViewConfigurationProvider].GetScriptMessageRouter(); + web::WebFramesManagerImpl::FromWebState(self.webStateImpl) + ->OnWebViewUpdated(_webView, webView, messageRouter); + + if (_webView) { + // TODO(crbug.com/956516): Use removeScriptMessageHandlerForName:webView: + // for |kScriptMessageName| and let CRWContextMenuController unregister its + // own callback. + [messageRouter removeAllScriptMessageHandlersForWebView:_webView]; + + [_webView stopLoading]; + [_webView removeFromSuperview]; + } + // Set up the new web view. _webView = webView; if (_webView) { + [_webView setNavigationDelegate:self.navigationHandler]; + [_webView setUIDelegate:self.UIHandler]; + for (NSString* keyPath in self.WKWebViewObservers) { + [_webView addObserver:self forKeyPath:keyPath options:0 context:nullptr]; + } + __weak CRWWebController* weakSelf = self; [messageRouter setScriptMessageHandler:^(WKScriptMessage* message) { @@ -443,16 +457,13 @@ } name:kScriptMessageName webView:_webView]; + + _webView.allowsBackForwardNavigationGestures = + _allowsBackForwardNavigationGestures; } [_jsInjector setWebView:_webView]; - [_webView setNavigationDelegate:self.navigationHandler]; - [_webView setUIDelegate:self.UIHandler]; - for (NSString* keyPath in self.WKWebViewObservers) { - [_webView addObserver:self forKeyPath:keyPath options:0 context:nullptr]; - } self.webViewNavigationObserver.webView = _webView; - _webView.allowsBackForwardNavigationGestures = - _allowsBackForwardNavigationGestures; + [self setDocumentURL:_defaultURL context:nullptr]; } @@ -598,8 +609,10 @@ self.webStateImpl->CancelDialogs(); _SSLStatusUpdater = nil; + [self.navigationHandler close]; [self.UIHandler close]; [self.JSNavigationHandler close]; + [self.requestController close]; _faviconManager.reset(); _jsWindowErrorManager.reset(); self.swipeRecognizerProvider = nil; @@ -1255,11 +1268,6 @@ return [self webUsageEnabled]; } -- (BOOL)legacyNativeContentControllerIsBeingDestroyed: - (CRWLegacyNativeContentController*)contentController { - return _isBeingDestroyed; -} - - (void)legacyNativeContentControllerRemoveWebView: (CRWLegacyNativeContentController*)contentController { [self removeWebView]; @@ -1812,11 +1820,9 @@ self.webStateImpl->CancelDialogs(); self.navigationManagerImpl->DetachFromWebView(); - [self.webView stopLoading]; - [self.webView removeFromSuperview]; + [self setWebView:nil]; [self.navigationHandler stopLoading]; [_containerView resetContent]; - [self setWebView:nil]; // webView:didFailProvisionalNavigation:withError: may never be called after // resetting WKWebView, so it is important to clear pending navigations now. @@ -1986,11 +1992,6 @@ #pragma mark - CRWWebViewNavigationObserverDelegate -- (BOOL)webViewIsBeingDestroyed: - (CRWWebViewNavigationObserver*)navigationObserver { - return _isBeingDestroyed; -} - - (web::WebStateImpl*)webStateImplForNavigationObserver: (CRWWebViewNavigationObserver*)navigationObserver { return self.webStateImpl; @@ -2149,11 +2150,6 @@ #pragma mark - CRWWKNavigationHandlerDelegate -- (BOOL)navigationHandlerWebViewBeingDestroyed: - (CRWWKNavigationHandler*)navigationHandler { - return _isBeingDestroyed; -} - - (web::WebStateImpl*)webStateImplForNavigationHandler: (CRWWKNavigationHandler*)navigationHandler { return self.webStateImpl; @@ -2276,11 +2272,6 @@ #pragma mark - CRWWebRequestControllerDelegate -- (BOOL)webRequestControllerIsBeingDestroyed: - (CRWWebRequestController*)requestController { - return _isBeingDestroyed; -} - - (void)webRequestControllerStopLoading: (CRWWebRequestController*)requestController { [self stopLoading];
diff --git a/ios/web/web_state/ui/crw_web_request_controller.h b/ios/web/web_state/ui/crw_web_request_controller.h index 5895958..fec8ea1c 100644 --- a/ios/web/web_state/ui/crw_web_request_controller.h +++ b/ios/web/web_state/ui/crw_web_request_controller.h
@@ -28,10 +28,6 @@ - (void)webRequestControllerStopLoading: (CRWWebRequestController*)requestController; -// Whether the delegate is being destroyed. -- (BOOL)webRequestControllerIsBeingDestroyed: - (CRWWebRequestController*)requestController; - // Asks proxy to disconnect scroll proxy if needed. - (void)webRequestControllerDisconnectScrollViewProxy: (CRWWebRequestController*)requestController; @@ -75,6 +71,11 @@ - (instancetype)init NS_UNAVAILABLE; +// Instructs the receiver to close. This should be called when the receiver's +// owner is being destroyed. The state of the receiver will be set to +// "isBeingDestroyed" after this is called. +- (void)close; + // Checks if a load request of the current navigation item should proceed. If // this returns |YES|, caller should create a webView and call // |loadRequestForCurrentNavigationItem|. Otherwise this will set the request
diff --git a/ios/web/web_state/ui/crw_web_request_controller.mm b/ios/web/web_state/ui/crw_web_request_controller.mm index f9901fa..9cce397 100644 --- a/ios/web/web_state/ui/crw_web_request_controller.mm +++ b/ios/web/web_state/ui/crw_web_request_controller.mm
@@ -66,6 +66,9 @@ // Returns The WKNavigationDelegate handler class from delegate. @property(nonatomic, readonly) CRWWKNavigationHandler* navigationHandler; +// Set to YES when [self close] is called. +@property(nonatomic, assign) BOOL beingDestroyed; + @end @implementation CRWWebRequestController @@ -78,6 +81,10 @@ return self; } +- (void)close { + self.beingDestroyed = YES; +} + - (BOOL)maybeLoadRequestForCurrentNavigationItem { web::NavigationItem* item = self.currentNavItem; GURL targetURL = item ? item->GetVirtualURL() : GURL::EmptyGURL(); @@ -275,7 +282,7 @@ DCHECK(!web::GetWebClient()->IsSlimNavigationManagerEnabled()); self.webState->ShowRepostFormWarningDialog( base::BindOnce(^(bool shouldContinue) { - if ([_delegate webRequestControllerIsBeingDestroyed:self]) + if (self.beingDestroyed) return; if (shouldContinue)
diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn index cb7a5305..d8ae83c 100644 --- a/media/audio/BUILD.gn +++ b/media/audio/BUILD.gn
@@ -219,8 +219,6 @@ sources += [ "android/audio_manager_android.cc", "android/audio_manager_android.h", - "android/audio_record_input.cc", - "android/audio_record_input.h", "android/audio_track_output_stream.cc", "android/audio_track_output_stream.h", "android/muteable_audio_output_stream.h",
diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc index a9feab6..79bebf1 100644 --- a/media/audio/android/audio_manager_android.cc +++ b/media/audio/android/audio_manager_android.cc
@@ -13,7 +13,6 @@ #include "base/bind.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" -#include "media/audio/android/audio_record_input.h" #include "media/audio/android/audio_track_output_stream.h" #include "media/audio/android/opensles_input.h" #include "media/audio/android/opensles_output.h"
diff --git a/media/audio/android/audio_record_input.cc b/media/audio/android/audio_record_input.cc deleted file mode 100644 index 5194301..0000000 --- a/media/audio/android/audio_record_input.cc +++ /dev/null
@@ -1,144 +0,0 @@ -// Copyright 2013 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 "media/audio/android/audio_record_input.h" - -#include "base/logging.h" -#include "media/audio/android/audio_manager_android.h" -#include "media/base/android/media_jni_headers/AudioRecordInput_jni.h" -#include "media/base/audio_bus.h" - -using base::android::JavaParamRef; - -namespace media { - -constexpr SampleFormat kSampleFormat = kSampleFormatS16; - -AudioRecordInputStream::AudioRecordInputStream( - AudioManagerAndroid* audio_manager, - const AudioParameters& params) - : audio_manager_(audio_manager), - callback_(NULL), - direct_buffer_address_(NULL), - audio_bus_(media::AudioBus::Create(params)), - bytes_per_sample_(SampleFormatToBytesPerChannel(kSampleFormat)) { - DVLOG(2) << __PRETTY_FUNCTION__; - DCHECK(params.IsValid()); - j_audio_record_.Reset(Java_AudioRecordInput_createAudioRecordInput( - base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this), - params.sample_rate(), params.channels(), bytes_per_sample_ * 8, - params.GetBytesPerBuffer(kSampleFormat), - params.effects() & AudioParameters::ECHO_CANCELLER)); -} - -AudioRecordInputStream::~AudioRecordInputStream() { - DVLOG(2) << __PRETTY_FUNCTION__; - DCHECK(thread_checker_.CalledOnValidThread()); -} - -void AudioRecordInputStream::CacheDirectBufferAddress( - JNIEnv* env, - const JavaParamRef<jobject>& obj, - const JavaParamRef<jobject>& byte_buffer) { - DCHECK(thread_checker_.CalledOnValidThread()); - direct_buffer_address_ = - static_cast<uint8_t*>(env->GetDirectBufferAddress(byte_buffer)); -} - -void AudioRecordInputStream::OnData(JNIEnv* env, - const JavaParamRef<jobject>& obj, - jint size, - jint hardware_delay_ms) { - DCHECK(direct_buffer_address_); - DCHECK_EQ(size, - audio_bus_->frames() * audio_bus_->channels() * bytes_per_sample_); - // Passing zero as the volume parameter indicates there is no access to a - // hardware volume slider. - audio_bus_->FromInterleaved(direct_buffer_address_, audio_bus_->frames(), - bytes_per_sample_); - callback_->OnData(audio_bus_.get(), - base::TimeTicks::Now() - - base::TimeDelta::FromMilliseconds(hardware_delay_ms), - 0.0); -} - -bool AudioRecordInputStream::Open() { - DVLOG(2) << __PRETTY_FUNCTION__; - DCHECK(thread_checker_.CalledOnValidThread()); - return Java_AudioRecordInput_open(base::android::AttachCurrentThread(), - j_audio_record_); -} - -void AudioRecordInputStream::Start(AudioInputCallback* callback) { - DVLOG(2) << __PRETTY_FUNCTION__; - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(callback); - - if (callback_) { - // Start() was already called. - DCHECK_EQ(callback_, callback); - return; - } - // The Java thread has not yet started, so we are free to set |callback_|. - callback_ = callback; - - Java_AudioRecordInput_start(base::android::AttachCurrentThread(), - j_audio_record_); -} - -void AudioRecordInputStream::Stop() { - DVLOG(2) << __PRETTY_FUNCTION__; - DCHECK(thread_checker_.CalledOnValidThread()); - if (!callback_) { - // Start() was never called, or Stop() was already called. - return; - } - - Java_AudioRecordInput_stop(base::android::AttachCurrentThread(), - j_audio_record_); - - // The Java thread must have been stopped at this point, so we are free to - // clear |callback_|. - callback_ = NULL; -} - -void AudioRecordInputStream::Close() { - DVLOG(2) << __PRETTY_FUNCTION__; - DCHECK(thread_checker_.CalledOnValidThread()); - Stop(); - DCHECK(!callback_); - Java_AudioRecordInput_close(base::android::AttachCurrentThread(), - j_audio_record_); - audio_manager_->ReleaseInputStream(this); -} - -double AudioRecordInputStream::GetMaxVolume() { - return 0.0; -} - -void AudioRecordInputStream::SetVolume(double volume) { -} - -double AudioRecordInputStream::GetVolume() { - return 0.0; -} - -bool AudioRecordInputStream::SetAutomaticGainControl(bool enabled) { - return false; -} - -bool AudioRecordInputStream::GetAutomaticGainControl() { - return false; -} - -bool AudioRecordInputStream::IsMuted() { - return false; -} - -void AudioRecordInputStream::SetOutputDeviceForAec( - const std::string& output_device_id) { - // Do nothing. This is handled at a different layer on Android. -} - -} // namespace media
diff --git a/media/audio/android/audio_record_input.h b/media/audio/android/audio_record_input.h deleted file mode 100644 index f5d544b..0000000 --- a/media/audio/android/audio_record_input.h +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2013 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 MEDIA_AUDIO_ANDROID_AUDIO_RECORD_INPUT_H_ -#define MEDIA_AUDIO_ANDROID_AUDIO_RECORD_INPUT_H_ - -#include <stdint.h> - -#include <memory> - -#include "base/android/jni_android.h" -#include "base/macros.h" -#include "base/threading/thread_checker.h" -#include "media/audio/audio_io.h" -#include "media/base/audio_parameters.h" - -namespace media { - -class AudioBus; -class AudioManagerAndroid; - -// Implements PCM audio input support for Android using the Java AudioRecord -// interface. Most of the work is done by its Java counterpart in -// AudioRecordInput.java. This class is created and lives on the Audio Manager -// thread but recorded audio buffers are delivered on a thread managed by -// the Java class. -class MEDIA_EXPORT AudioRecordInputStream : public AudioInputStream { - public: - AudioRecordInputStream(AudioManagerAndroid* manager, - const AudioParameters& params); - - ~AudioRecordInputStream() override; - - // Implementation of AudioInputStream. - bool Open() override; - void Start(AudioInputCallback* callback) override; - void Stop() override; - void Close() override; - double GetMaxVolume() override; - void SetVolume(double volume) override; - double GetVolume() override; - bool SetAutomaticGainControl(bool enabled) override; - bool GetAutomaticGainControl() override; - bool IsMuted() override; - void SetOutputDeviceForAec(const std::string& output_device_id) override; - - // Called from Java when data is available. - void OnData(JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - jint size, - jint hardware_delay_ms); - - // Called from Java so that we can cache the address of the Java-managed - // |byte_buffer| in |direct_buffer_address_|. - void CacheDirectBufferAddress( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - const base::android::JavaParamRef<jobject>& byte_buffer); - - private: - base::ThreadChecker thread_checker_; - AudioManagerAndroid* audio_manager_; - - // Java AudioRecordInput instance. - base::android::ScopedJavaGlobalRef<jobject> j_audio_record_; - - // This is the only member accessed by both the Audio Manager and Java - // threads. Explanations for why we do not require explicit synchronization - // are given in the implementation. - AudioInputCallback* callback_; - - // Owned by j_audio_record_. - uint8_t* direct_buffer_address_; - - std::unique_ptr<media::AudioBus> audio_bus_; - int bytes_per_sample_; - - DISALLOW_COPY_AND_ASSIGN(AudioRecordInputStream); -}; - -} // namespace media - -#endif // MEDIA_AUDIO_ANDROID_AUDIO_RECORD_INPUT_H_
diff --git a/media/base/android/BUILD.gn b/media/base/android/BUILD.gn index 2eab73a..b0e3a87 100644 --- a/media/base/android/BUILD.gn +++ b/media/base/android/BUILD.gn
@@ -131,7 +131,6 @@ generate_jni("media_jni_headers") { sources = [ "java/src/org/chromium/media/AudioManagerAndroid.java", - "java/src/org/chromium/media/AudioRecordInput.java", "java/src/org/chromium/media/AudioTrackOutputStream.java", "java/src/org/chromium/media/CodecProfileLevelList.java", "java/src/org/chromium/media/HdrMetadata.java", @@ -178,7 +177,6 @@ ] java_files = [ "java/src/org/chromium/media/AudioManagerAndroid.java", - "java/src/org/chromium/media/AudioRecordInput.java", "java/src/org/chromium/media/AudioTrackOutputStream.java", "java/src/org/chromium/media/BitrateAdjuster.java", "java/src/org/chromium/media/CodecProfileLevelList.java",
diff --git a/media/base/android/java/src/org/chromium/media/AudioRecordInput.java b/media/base/android/java/src/org/chromium/media/AudioRecordInput.java deleted file mode 100644 index e2c5c5f..0000000 --- a/media/base/android/java/src/org/chromium/media/AudioRecordInput.java +++ /dev/null
@@ -1,246 +0,0 @@ -// Copyright 2013 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.media; - -import android.annotation.SuppressLint; -import android.media.AudioFormat; -import android.media.AudioRecord; -import android.media.MediaRecorder.AudioSource; -import android.media.audiofx.AcousticEchoCanceler; -import android.media.audiofx.AudioEffect; -import android.media.audiofx.AudioEffect.Descriptor; -import android.os.Process; - -import org.chromium.base.Log; -import org.chromium.base.annotations.CalledByNative; -import org.chromium.base.annotations.JNINamespace; - -import java.nio.ByteBuffer; - -// Owned by its native counterpart declared in audio_record_input.h. Refer to -// that class for general comments. -@JNINamespace("media") -class AudioRecordInput { - private static final String TAG = "cr.media"; - // Set to true to enable debug logs. Always check in as false. - private static final boolean DEBUG = false; - // We are unable to obtain a precise measurement of the hardware delay on - // Android. This is a conservative lower-bound based on measurments. It - // could surely be tightened with further testing. - // TODO(dalecurtis): This should use AudioRecord.getTimestamp() in API 24+. - private static final int HARDWARE_DELAY_MS = 100; - - private final long mNativeAudioRecordInputStream; - private final int mSampleRate; - private final int mChannels; - private final int mBitsPerSample; - private final boolean mUsePlatformAEC; - private ByteBuffer mBuffer; - private AudioRecord mAudioRecord; - private AudioRecordThread mAudioRecordThread; - private AcousticEchoCanceler mAEC; - - private class AudioRecordThread extends Thread { - // The "volatile" synchronization technique is discussed here: - // http://stackoverflow.com/a/106787/299268 - // and more generally in this article: - // https://www.ibm.com/developerworks/java/library/j-jtp06197/ - private volatile boolean mKeepAlive = true; - - @Override - public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO); - try { - mAudioRecord.startRecording(); - } catch (IllegalStateException e) { - Log.e(TAG, "startRecording failed", e); - return; - } - - while (mKeepAlive) { - int bytesRead = mAudioRecord.read(mBuffer, mBuffer.capacity()); - if (bytesRead > 0) { - nativeOnData(mNativeAudioRecordInputStream, bytesRead, HARDWARE_DELAY_MS); - } else { - Log.e(TAG, "read failed: %d", bytesRead); - if (bytesRead == AudioRecord.ERROR_INVALID_OPERATION) { - // This can happen if there is already an active - // AudioRecord (e.g. in another tab). - mKeepAlive = false; - } - } - } - - try { - mAudioRecord.stop(); - } catch (IllegalStateException e) { - Log.e(TAG, "stop failed", e); - } - } - - public void joinRecordThread() { - mKeepAlive = false; - while (isAlive()) { - try { - join(); - } catch (InterruptedException e) { - // Ignore. - } - } - } - } - - @CalledByNative - private static AudioRecordInput createAudioRecordInput(long nativeAudioRecordInputStream, - int sampleRate, int channels, int bitsPerSample, int bytesPerBuffer, - boolean usePlatformAEC) { - return new AudioRecordInput(nativeAudioRecordInputStream, sampleRate, channels, - bitsPerSample, bytesPerBuffer, usePlatformAEC); - } - - private AudioRecordInput(long nativeAudioRecordInputStream, int sampleRate, int channels, - int bitsPerSample, int bytesPerBuffer, boolean usePlatformAEC) { - mNativeAudioRecordInputStream = nativeAudioRecordInputStream; - mSampleRate = sampleRate; - mChannels = channels; - mBitsPerSample = bitsPerSample; - mUsePlatformAEC = usePlatformAEC; - - // We use a direct buffer so that the native class can have access to - // the underlying memory address. This avoids the need to copy from a - // jbyteArray to native memory. More discussion of this here: - // http://developer.android.com/training/articles/perf-jni.html - mBuffer = ByteBuffer.allocateDirect(bytesPerBuffer); - // Rather than passing the ByteBuffer with every OnData call (requiring - // the potentially expensive GetDirectBufferAddress) we simply have the - // the native class cache the address to the memory once. - // - // Unfortunately, profiling with traceview was unable to either confirm - // or deny the advantage of this approach, as the values for - // nativeOnData() were not stable across runs. - nativeCacheDirectBufferAddress(mNativeAudioRecordInputStream, mBuffer); - } - - @SuppressLint("NewApi") - @CalledByNative - private boolean open() { - if (mAudioRecord != null) { - Log.e(TAG, "open() called twice without a close()"); - return false; - } - int channelConfig; - if (mChannels == 1) { - channelConfig = AudioFormat.CHANNEL_IN_MONO; - } else if (mChannels == 2) { - channelConfig = AudioFormat.CHANNEL_IN_STEREO; - } else { - Log.e(TAG, "Unsupported number of channels: %d", mChannels); - return false; - } - - int audioFormat; - if (mBitsPerSample == 8) { - audioFormat = AudioFormat.ENCODING_PCM_8BIT; - } else if (mBitsPerSample == 16) { - audioFormat = AudioFormat.ENCODING_PCM_16BIT; - } else { - Log.e(TAG, "Unsupported bits per sample: %d", mBitsPerSample); - return false; - } - - // TODO(ajm): Do we need to make this larger to avoid underruns? The - // Android documentation notes "this size doesn't guarantee a smooth - // recording under load". - int minBufferSize = AudioRecord.getMinBufferSize(mSampleRate, channelConfig, audioFormat); - if (minBufferSize < 0) { - Log.e(TAG, "getMinBufferSize error: %d", minBufferSize); - return false; - } - - // We will request mBuffer.capacity() with every read call. The - // underlying AudioRecord buffer should be at least this large. - int audioRecordBufferSizeInBytes = Math.max(mBuffer.capacity(), minBufferSize); - try { - // TODO(ajm): Allow other AudioSource types to be requested? - mAudioRecord = new AudioRecord(AudioSource.VOICE_COMMUNICATION, - mSampleRate, - channelConfig, - audioFormat, - audioRecordBufferSizeInBytes); - } catch (IllegalArgumentException e) { - Log.e(TAG, "AudioRecord failed", e); - return false; - } - - if (AcousticEchoCanceler.isAvailable()) { - mAEC = AcousticEchoCanceler.create(mAudioRecord.getAudioSessionId()); - if (mAEC == null) { - Log.e(TAG, "AcousticEchoCanceler.create failed"); - return false; - } - int ret = mAEC.setEnabled(mUsePlatformAEC); - if (ret != AudioEffect.SUCCESS) { - Log.e(TAG, "setEnabled error: %d", ret); - return false; - } - - if (DEBUG) { - Descriptor descriptor = mAEC.getDescriptor(); - Log.d(TAG, "AcousticEchoCanceler name: %s, implementor: %s, uuid: %s", - descriptor.name, descriptor.implementor, descriptor.uuid); - } - } - return true; - } - - @CalledByNative - private void start() { - if (mAudioRecord == null) { - Log.e(TAG, "start() called before open()."); - return; - } - if (mAudioRecordThread != null) { - // start() was already called. - return; - } - mAudioRecordThread = new AudioRecordThread(); - mAudioRecordThread.start(); - } - - @CalledByNative - private void stop() { - if (mAudioRecordThread == null) { - // start() was never called, or stop() was already called. - return; - } - mAudioRecordThread.joinRecordThread(); - mAudioRecordThread = null; - } - - @SuppressLint("NewApi") - @CalledByNative - private void close() { - if (mAudioRecordThread != null) { - Log.e(TAG, "close() called before stop()."); - return; - } - if (mAudioRecord == null) { - // open() was not called. - return; - } - - if (mAEC != null) { - mAEC.release(); - mAEC = null; - } - mAudioRecord.release(); - mAudioRecord = null; - } - - private native void nativeCacheDirectBufferAddress(long nativeAudioRecordInputStream, - ByteBuffer buffer); - private native void nativeOnData( - long nativeAudioRecordInputStream, int size, int hardwareDelayMs); -}
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn index d4e634c..301c581 100644 --- a/media/capture/BUILD.gn +++ b/media/capture/BUILD.gn
@@ -337,7 +337,10 @@ deps = [ "//base", "//build/config/linux/libdrm", + "//gpu/command_buffer/client", "//third_party/minigbm", + "//ui/gfx:memory_buffer", + "//ui/gfx/geometry", ] } }
diff --git a/media/capture/video/OWNERS b/media/capture/video/OWNERS index 0448766..0a386e7 100644 --- a/media/capture/video/OWNERS +++ b/media/capture/video/OWNERS
@@ -1,5 +1,6 @@ chfremer@chromium.org tommi@chromium.org +guidou@chromium.org # Original (legacy) owner. emircan@chromium.org
diff --git a/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc b/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc index 27a6a7c..7b02bbb7 100644 --- a/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc +++ b/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc
@@ -5,11 +5,18 @@ #include "media/capture/video/chromeos/local_gpu_memory_buffer_manager.h" #include <drm_fourcc.h> +#include <gbm.h> +#include <stddef.h> +#include <stdint.h> #include <xf86drm.h> -#include <memory> +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" #include "base/trace_event/memory_allocator_dump_guid.h" #include "base/trace_event/process_memory_dump.h" +#include "ui/gfx/buffer_format_util.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/native_pixmap_handle.h" namespace media { @@ -56,6 +63,8 @@ switch (gfx_format) { case gfx::BufferFormat::R_8: return DRM_FORMAT_R8; + case gfx::BufferFormat::YVU_420: + return DRM_FORMAT_YVU420; case gfx::BufferFormat::YUV_420_BIPLANAR: return DRM_FORMAT_NV12; // Add more formats when needed. @@ -251,4 +260,46 @@ gfx::GpuMemoryBuffer* buffer, const gpu::SyncToken& sync_token) {} +std::unique_ptr<gfx::GpuMemoryBuffer> LocalGpuMemoryBufferManager::ImportDmaBuf( + const gfx::NativePixmapHandle& handle, + const gfx::Size& size, + gfx::BufferFormat format) { + if (handle.planes.size() != gfx::NumberOfPlanesForBufferFormat(format)) { + // This could happen if e.g., we get a compressed RGBA buffer where one + // plane is for metadata. We don't support this case. + LOG(ERROR) << "Cannot import " << gfx::BufferFormatToString(format) + << " with " << handle.planes.size() << " plane(s) (expected " + << gfx::NumberOfPlanesForBufferFormat(format) << " plane(s))"; + return nullptr; + } + const uint32_t drm_format = GetDrmFormat(format); + if (!drm_format) { + LOG(ERROR) << "Unsupported format " << gfx::BufferFormatToString(format); + return nullptr; + } + gbm_import_fd_modifier_data import_data{ + base::checked_cast<uint32_t>(size.width()), + base::checked_cast<uint32_t>(size.height()), drm_format, + base::checked_cast<uint32_t>(handle.planes.size())}; + for (size_t plane = 0; plane < handle.planes.size(); plane++) { + if (!handle.planes[plane].fd.is_valid()) { + LOG(ERROR) << "Invalid file descriptor for plane " << plane; + return nullptr; + } + import_data.fds[plane] = handle.planes[plane].fd.get(); + import_data.strides[plane] = + base::checked_cast<int>(handle.planes[plane].stride); + import_data.offsets[plane] = + base::checked_cast<int>(handle.planes[plane].offset); + } + import_data.modifier = handle.modifier; + gbm_bo* buffer_object = gbm_bo_import(gbm_device_, GBM_BO_IMPORT_FD_MODIFIER, + &import_data, GBM_BO_USE_SW_READ_OFTEN); + if (!buffer_object) { + PLOG(ERROR) << "Could not import the DmaBuf into gbm"; + return nullptr; + } + return std::make_unique<GpuMemoryBufferImplGbm>(format, buffer_object); +} + } // namespace media
diff --git a/media/capture/video/chromeos/local_gpu_memory_buffer_manager.h b/media/capture/video/chromeos/local_gpu_memory_buffer_manager.h index 56643f3..b7a1552 100644 --- a/media/capture/video/chromeos/local_gpu_memory_buffer_manager.h +++ b/media/capture/video/chromeos/local_gpu_memory_buffer_manager.h
@@ -5,10 +5,19 @@ #ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_LOCAL_GPU_MEMORY_BUFFER_MANAGER_H_ #define MEDIA_CAPTURE_VIDEO_CHROMEOS_LOCAL_GPU_MEMORY_BUFFER_MANAGER_H_ -#include <gbm.h> +#include <memory> #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" #include "media/capture/capture_export.h" +#include "ui/gfx/buffer_types.h" + +struct gbm_device; + +namespace gfx { +class GpuMemoryBuffer; +struct NativePixmapHandle; +class Size; +} // namespace gfx namespace media { @@ -16,6 +25,8 @@ // gfx::GpuMemoryBufferManager which interacts with the DRM render node device // directly. The LocalGpuMemoryBufferManager is only for testing purposes and // should not be used in production. +// +// TODO(crbug.com/974437): consider moving this to //media/gpu/test. class CAPTURE_EXPORT LocalGpuMemoryBufferManager : public gpu::GpuMemoryBufferManager { public: @@ -31,6 +42,15 @@ void SetDestructionSyncToken(gfx::GpuMemoryBuffer* buffer, const gpu::SyncToken& sync_token) override; + // Imports a DmaBuf as a GpuMemoryBuffer to be able to map it. The + // GBM_BO_USE_SW_READ_OFTEN usage is specified so that the user of the + // returned GpuMemoryBuffer is guaranteed to have a linear view when mapping + // it. + std::unique_ptr<gfx::GpuMemoryBuffer> ImportDmaBuf( + const gfx::NativePixmapHandle& handle, + const gfx::Size& size, + gfx::BufferFormat format); + private: gbm_device* gbm_device_;
diff --git a/media/capture/video/win/video_capture_device_factory_win.cc b/media/capture/video/win/video_capture_device_factory_win.cc index 0fbac5c..8f899b6e 100644 --- a/media/capture/video/win/video_capture_device_factory_win.cc +++ b/media/capture/video/win/video_capture_device_factory_win.cc
@@ -92,7 +92,7 @@ // also https://crbug.com/924528 "04ca:7047", "04ca:7048", // HP Elitebook 840 G1 - "04f2:b3ed"}; + "04f2:b3ed", "04f2:b3ca"}; const std::pair<VideoCaptureApi, std::vector<std::pair<GUID, GUID>>> kMfAttributes[] = {{VideoCaptureApi::WIN_MEDIA_FOUNDATION,
diff --git a/media/gpu/test/video_player/frame_renderer_thumbnail.cc b/media/gpu/test/video_player/frame_renderer_thumbnail.cc index 100be1fc..7672654 100644 --- a/media/gpu/test/video_player/frame_renderer_thumbnail.cc +++ b/media/gpu/test/video_player/frame_renderer_thumbnail.cc
@@ -27,8 +27,8 @@ // Size of the individual thumbnails that will be rendered. constexpr gfx::Size kThumbnailSize(160, 120); -// Default file path used to store the thumbnail image. -constexpr const base::FilePath::CharType* kDefaultOutputPath = +// Default filename used to store the thumbnails image. +constexpr const base::FilePath::CharType* kThumbnailFilename = FILE_PATH_LITERAL("thumbnail.png"); // Vertex shader used to render thumbnails. @@ -110,13 +110,15 @@ bool FrameRendererThumbnail::gl_initialized_ = false; FrameRendererThumbnail::FrameRendererThumbnail( - const std::vector<std::string>& thumbnail_checksums) + const std::vector<std::string>& thumbnail_checksums, + const base::FilePath& output_folder) : frame_count_(0), thumbnail_checksums_(thumbnail_checksums), thumbnails_fbo_id_(0), thumbnails_texture_id_(0), vertex_buffer_(0), - program_(0) { + program_(0), + output_folder_(output_folder) { DETACH_FROM_SEQUENCE(renderer_sequence_checker_); } @@ -133,25 +135,26 @@ // static std::unique_ptr<FrameRendererThumbnail> FrameRendererThumbnail::Create( - const std::vector<std::string> thumbnail_checksums) { - auto frame_renderer = - base::WrapUnique(new FrameRendererThumbnail(thumbnail_checksums)); + const std::vector<std::string> thumbnail_checksums, + const base::FilePath& output_folder) { + base::FilePath resolved_output_folder = + base::MakeAbsoluteFilePath(output_folder); + auto frame_renderer = base::WrapUnique( + new FrameRendererThumbnail(thumbnail_checksums, resolved_output_folder)); frame_renderer->Initialize(); return frame_renderer; } // static std::unique_ptr<FrameRendererThumbnail> FrameRendererThumbnail::Create( - const base::FilePath& video_file_path) { + const base::FilePath& video_file_path, + const base::FilePath& output_folder) { // Read thumbnail checksums from file. std::vector<std::string> thumbnail_checksums = media::test::ReadGoldenThumbnailMD5s( video_file_path.AddExtension(FILE_PATH_LITERAL(".md5"))); - auto frame_renderer = - base::WrapUnique(new FrameRendererThumbnail(thumbnail_checksums)); - frame_renderer->Initialize(); - return frame_renderer; + return FrameRendererThumbnail::Create(thumbnail_checksums, output_folder); } void FrameRendererThumbnail::AcquireGLContext() { @@ -246,6 +249,10 @@ void FrameRendererThumbnail::SaveThumbnail() { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); + // Create the directory tree if it doesn't exist yet. + if (!DirectoryExists(output_folder_)) + base::CreateDirectory(output_folder_); + const std::vector<uint8_t> rgba = ConvertThumbnailToRGBA(); // Convert raw RGBA into PNG for export. @@ -254,9 +261,11 @@ kThumbnailsPageSize, kThumbnailsPageSize.width() * 4, true, std::vector<gfx::PNGCodec::Comment>(), &png); - base::FilePath filepath(kDefaultOutputPath); + base::FilePath filepath = output_folder_.Append(kThumbnailFilename); + base::File thumbnail_file( + filepath, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); int num_bytes = - base::WriteFile(filepath, reinterpret_cast<char*>(&png[0]), png.size()); + thumbnail_file.Write(0u, reinterpret_cast<char*>(&png[0]), png.size()); ASSERT_NE(-1, num_bytes); EXPECT_EQ(static_cast<size_t>(num_bytes), png.size()); }
diff --git a/media/gpu/test/video_player/frame_renderer_thumbnail.h b/media/gpu/test/video_player/frame_renderer_thumbnail.h index fc70f9ea..d44cf63a 100644 --- a/media/gpu/test/video_player/frame_renderer_thumbnail.h +++ b/media/gpu/test/video_player/frame_renderer_thumbnail.h
@@ -40,13 +40,15 @@ // Create an instance of the thumbnail frame renderer. static std::unique_ptr<FrameRendererThumbnail> Create( - const std::vector<std::string> thumbnail_checksums); + const std::vector<std::string> thumbnail_checksums, + const base::FilePath& output_folder); // Create an instance of the thumbnail frame renderer. The |video_file_path| // should point to a file containing all golden thumbnail hashes for the video // being rendered. static std::unique_ptr<FrameRendererThumbnail> Create( - const base::FilePath& video_file_path); + const base::FilePath& video_file_path, + const base::FilePath& output_folder); // FrameRenderer implementation // Acquire the active GL context. This will claim |gl_context_lock_|. @@ -67,7 +69,8 @@ private: explicit FrameRendererThumbnail( - const std::vector<std::string>& thumbnail_checksums); + const std::vector<std::string>& thumbnail_checksums, + const base::FilePath& output_folder); // Initialize the frame renderer, performs all rendering-related setup. void Initialize(); @@ -123,6 +126,9 @@ // Whether GL was initialized, as it should only happen once. static bool gl_initialized_; + // Output folder the thumbnails image will be written to by SaveThumbnail(). + const base::FilePath output_folder_; + SEQUENCE_CHECKER(client_sequence_checker_); SEQUENCE_CHECKER(renderer_sequence_checker_);
diff --git a/media/gpu/test/video_player/video_player_test_environment.cc b/media/gpu/test/video_player/video_player_test_environment.cc index 895b2999..90b14a8 100644 --- a/media/gpu/test/video_player/video_player_test_environment.cc +++ b/media/gpu/test/video_player/video_player_test_environment.cc
@@ -6,6 +6,11 @@ #include <utility> +#include "base/system/sys_info.h" +#include "media/base/video_types.h" +#if defined(OS_CHROMEOS) +#include "media/gpu/chromeos/platform_video_frame_utils.h" +#endif // defined(OS_CHROMEOS) #include "media/gpu/test/video_player/video.h" namespace media { @@ -49,6 +54,25 @@ VideoPlayerTestEnvironment::~VideoPlayerTestEnvironment() = default; +void VideoPlayerTestEnvironment::SetUp() { + VideoTestEnvironment::SetUp(); + + // TODO(dstaessens): Remove this check once all platforms support import mode. + // Some older platforms do not support importing buffers, but need to allocate + // buffers internally in the decoder. +#if defined(OS_CHROMEOS) + constexpr const char* kImportModeBlacklist[] = {"nyan_big", "nyan_blaze", + "nyan_kitty"}; + const std::string board = base::SysInfo::GetLsbReleaseBoard(); + import_supported_ = (std::find(std::begin(kImportModeBlacklist), + std::end(kImportModeBlacklist), + board) == std::end(kImportModeBlacklist)); +#endif // defined(OS_CHROMEOS) + + // VideoDecoders always require import mode to be supported. + DCHECK(!use_vd_ || import_supported_); +} + const media::test::Video* VideoPlayerTestEnvironment::Video() const { return video_.get(); } @@ -69,5 +93,9 @@ return use_vd_; } +bool VideoPlayerTestEnvironment::ImportSupported() const { + return import_supported_; +} + } // namespace test } // namespace media
diff --git a/media/gpu/test/video_player/video_player_test_environment.h b/media/gpu/test/video_player/video_player_test_environment.h index 5507c8d..746a7b29 100644 --- a/media/gpu/test/video_player/video_player_test_environment.h +++ b/media/gpu/test/video_player/video_player_test_environment.h
@@ -28,6 +28,9 @@ bool use_vd); ~VideoPlayerTestEnvironment() override; + // Set up video test environment, called once for entire test run. + void SetUp() override; + // Get the video the tests will be ran on. const media::test::Video* Video() const; // Check whether frame validation is enabled. @@ -38,6 +41,8 @@ const base::FilePath& OutputFolder() const; // Check whether we should use VD-based video decoders instead of VDA-based. bool UseVD() const; + // Whether import mode is supported, valid after SetUp() has been called. + bool ImportSupported() const; private: VideoPlayerTestEnvironment(std::unique_ptr<media::test::Video> video, @@ -51,6 +56,8 @@ const bool output_frames_; const base::FilePath output_folder_; const bool use_vd_; + // TODO(dstaessens): Remove this once all allocate-only platforms reached EOL. + bool import_supported_ = false; }; } // namespace test } // namespace media
diff --git a/media/gpu/vaapi/BUILD.gn b/media/gpu/vaapi/BUILD.gn index 0e96548..72f7a34 100644 --- a/media/gpu/vaapi/BUILD.gn +++ b/media/gpu/vaapi/BUILD.gn
@@ -168,9 +168,11 @@ ":vaapi_utils_unittest", "//base", "//media:test_support", + "//media/capture:chromeos_test_utils", "//media/parsers", "//testing/gtest", "//third_party/libyuv:libyuv", + "//ui/gfx:memory_buffer", "//ui/gfx/codec", "//ui/gfx/geometry", ]
diff --git a/media/gpu/vaapi/va.sigs b/media/gpu/vaapi/va.sigs index 1145ee5..f333cb33 100644 --- a/media/gpu/vaapi/va.sigs +++ b/media/gpu/vaapi/va.sigs
@@ -20,6 +20,7 @@ int vaDisplayIsValid(VADisplay dpy); VAStatus vaEndPicture(VADisplay dpy, VAContextID context); const char *vaErrorStr(VAStatus error_status); +VAStatus vaExportSurfaceHandle(VADisplay dpy, VASurfaceID surface_id, uint32_t mem_type, uint32_t flags, void *descriptor); VAStatus vaGetConfigAttributes(VADisplay dpy, VAProfile profile, VAEntrypoint entrypoint, VAConfigAttrib *attrib_list, int num_attribs); VAStatus vaGetImage(VADisplay dpy, VASurfaceID surface, int x, int y, unsigned int width, unsigned int height, VAImageID image); VAStatus vaInitialize(VADisplay dpy, int *major_version, int *minor_version);
diff --git a/media/gpu/vaapi/vaapi_image_decoder.cc b/media/gpu/vaapi/vaapi_image_decoder.cc index 8e35bce..a8f7e7fb 100644 --- a/media/gpu/vaapi/vaapi_image_decoder.cc +++ b/media/gpu/vaapi/vaapi_image_decoder.cc
@@ -6,7 +6,10 @@ #include "base/logging.h" #include "media/gpu/macros.h" +#include "media/gpu/vaapi/va_surface.h" #include "media/gpu/vaapi/vaapi_wrapper.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/linux/native_pixmap_dmabuf.h" namespace media { @@ -49,4 +52,38 @@ return profile; } +scoped_refptr<gfx::NativePixmapDmaBuf> +VaapiImageDecoder::ExportAsNativePixmapDmaBuf(VaapiImageDecodeStatus* status) { + DCHECK(status); + + // We need to take ownership of the VASurface so that the next decode doesn't + // attempt to use the same VASurface. Otherwise, it could overwrite the result + // of the current decode before it's used by the caller. This VASurface will + // self-clean at the end of this scope, but the underlying buffer should stay + // alive because of the exported FDs. + scoped_refptr<VASurface> va_surface = ReleaseVASurface(); + if (!va_surface) { + DVLOGF(1) << "No decoded image available"; + *status = VaapiImageDecodeStatus::kInvalidState; + return nullptr; + } + + DCHECK_NE(VA_INVALID_ID, va_surface->id()); + scoped_refptr<gfx::NativePixmapDmaBuf> pixmap = + vaapi_wrapper_->ExportVASurfaceAsNativePixmapDmaBuf(va_surface->id()); + if (!pixmap) { + *status = VaapiImageDecodeStatus::kCannotExportSurface; + return nullptr; + } + + // In Intel's iHD driver the size requested for the surface may be different + // than the buffer size of the NativePixmap because of additional alignment. + // See https://git.io/fj6nA. + DCHECK_LE(va_surface->size().width(), pixmap->GetBufferSize().width()); + DCHECK_LE(va_surface->size().height(), pixmap->GetBufferSize().height()); + + *status = VaapiImageDecodeStatus::kSuccess; + return pixmap; +} + } // namespace media
diff --git a/media/gpu/vaapi/vaapi_image_decoder.h b/media/gpu/vaapi/vaapi_image_decoder.h index 18924695..5a073da 100644 --- a/media/gpu/vaapi/vaapi_image_decoder.h +++ b/media/gpu/vaapi/vaapi_image_decoder.h
@@ -15,6 +15,10 @@ #include "base/memory/scoped_refptr.h" #include "gpu/config/gpu_info.h" +namespace gfx { +class NativePixmapDmaBuf; +} // namespace gfx + namespace media { class VASurface; @@ -30,6 +34,7 @@ kExecuteDecodeFailed, kUnsupportedSurfaceFormat, kCannotGetImage, + kCannotExportSurface, kInvalidState, }; @@ -63,6 +68,13 @@ // Returns the image profile supported by this decoder. gpu::ImageDecodeAcceleratorSupportedProfile GetSupportedProfile() const; + // Exports the decoded data from the last Decode() call as a + // gfx::NativePixmapDmaBuf. Returns nullptr on failure and sets *|status| to + // the reason for failure. On success, the image decoder gives up ownership of + // the buffer underlying the NativePixmapDmaBuf. + scoped_refptr<gfx::NativePixmapDmaBuf> ExportAsNativePixmapDmaBuf( + VaapiImageDecodeStatus* status); + protected: explicit VaapiImageDecoder(VAProfile va_profile);
diff --git a/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc b/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc index bbd5e41a..55c59185 100644 --- a/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc +++ b/media/gpu/vaapi/vaapi_jpeg_decoder_unittest.cc
@@ -5,6 +5,7 @@ #include <stddef.h> #include <stdint.h> +#include <algorithm> #include <memory> #include <string> #include <vector> @@ -27,6 +28,7 @@ #include "base/strings/string_util.h" #include "media/base/test_data_util.h" #include "media/base/video_types.h" +#include "media/capture/video/chromeos/local_gpu_memory_buffer_manager.h" #include "media/gpu/vaapi/va_surface.h" #include "media/gpu/vaapi/vaapi_image_decoder.h" #include "media/gpu/vaapi/vaapi_jpeg_decoder.h" @@ -38,8 +40,13 @@ #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkPixmap.h" #include "third_party/skia/include/encode/SkJpegEncoder.h" +#include "ui/gfx/buffer_format_util.h" +#include "ui/gfx/buffer_types.h" #include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/gpu_memory_buffer.h" +#include "ui/gfx/linux/native_pixmap_dmabuf.h" +#include "ui/gfx/native_pixmap_handle.h" namespace media { namespace { @@ -138,8 +145,12 @@ base::strict_cast<int>(parse_result.frame_header.coded_width); const int coded_height = base::strict_cast<int>(parse_result.frame_header.coded_height); - if (coded_width != decoded_image.coded_size.width() || - coded_height != decoded_image.coded_size.height()) { + // Note the use of > instead of !=. This is to handle the case in the Intel + // iHD driver where the coded size we compute for one of the images is + // 1280x720 while the size of the VAAPI surface is 1280x736 because of + // additional alignment. See https://git.io/fj6nA. + if (coded_width > decoded_image.coded_size.width() || + coded_height > decoded_image.coded_size.height()) { DLOG(ERROR) << "Wrong expected decoded JPEG coded size, " << coded_width << "x" << coded_height << " versus VaAPI provided " << decoded_image.coded_size.width() << "x" @@ -352,6 +363,10 @@ base::span<const uint8_t> encoded_image, VaapiImageDecodeStatus* status = nullptr); + scoped_refptr<gfx::NativePixmapDmaBuf> DecodeToNativePixmapDmaBuf( + base::span<const uint8_t> encoded_image, + VaapiImageDecodeStatus* status = nullptr); + protected: std::string test_data_path_; VaapiJpegDecoder decoder_; @@ -386,7 +401,7 @@ scoped_image = decoder_.GetImage(preferred_fourcc, &image_status); EXPECT_EQ(!!scoped_image, image_status == VaapiImageDecodeStatus::kSuccess); - // Record the first fail status. + // Return the first fail status. if (status) { *status = decode_status != VaapiImageDecodeStatus::kSuccess ? decode_status : image_status; @@ -400,6 +415,29 @@ return Decode(encoded_image, VA_FOURCC_I420, status); } +scoped_refptr<gfx::NativePixmapDmaBuf> +VaapiJpegDecoderTest::DecodeToNativePixmapDmaBuf( + base::span<const uint8_t> encoded_image, + VaapiImageDecodeStatus* status) { + VaapiImageDecodeStatus decode_status; + scoped_refptr<VASurface> surface = + decoder_.Decode(encoded_image, &decode_status); + EXPECT_EQ(!!surface, decode_status == VaapiImageDecodeStatus::kSuccess); + + // Still try to get the pixmap when decode fails. + VaapiImageDecodeStatus pixmap_status; + scoped_refptr<gfx::NativePixmapDmaBuf> pixmap = + decoder_.ExportAsNativePixmapDmaBuf(&pixmap_status); + EXPECT_EQ(!!pixmap, pixmap_status == VaapiImageDecodeStatus::kSuccess); + + // Return the first fail status. + if (status) { + *status = decode_status != VaapiImageDecodeStatus::kSuccess ? decode_status + : pixmap_status; + } + return pixmap; +} + // The intention of this test is to ensure that the workarounds added in // VaapiWrapper::GetJpegDecodeSuitableImageFourCC() don't result in an // unsupported image format. @@ -588,6 +626,82 @@ } } +// TODO(andrescj): test other JPEG formats besides YUV 4:2:0. +TEST_F(VaapiJpegDecoderTest, DecodeAndExportAsNativePixmapDmaBuf) { + if (base::StartsWith(VaapiWrapper::GetVendorStringForTesting(), + "Mesa Gallium driver", base::CompareCase::SENSITIVE)) { + // TODO(crbug.com/974438): until we support surfaces with multiple buffer + // objects, the AMD driver fails this test. + GTEST_SKIP(); + } + if (base::StartsWith(VaapiWrapper::GetVendorStringForTesting(), + "Intel i965 driver", base::CompareCase::SENSITIVE)) { + // TODO(b/135705575): until the correct offsets are exported, the Intel i965 + // driver fails this test. + GTEST_SKIP(); + } + + base::FilePath input_file = FindTestDataFilePath(kYuv420Filename); + std::string jpeg_data; + ASSERT_TRUE(base::ReadFileToString(input_file, &jpeg_data)) + << "failed to read input data from " << input_file.value(); + const auto encoded_image = base::make_span<const uint8_t>( + reinterpret_cast<const uint8_t*>(jpeg_data.data()), jpeg_data.size()); + VaapiImageDecodeStatus status; + scoped_refptr<gfx::NativePixmapDmaBuf> pixmap = + DecodeToNativePixmapDmaBuf(encoded_image, &status); + ASSERT_EQ(VaapiImageDecodeStatus::kSuccess, status); + ASSERT_TRUE(pixmap); + + // After exporting the surface, we should not be able to obtain a VAImage with + // the decoded data. + VAImageFormat i420_format{}; + i420_format.fourcc = VA_FOURCC_I420; + EXPECT_TRUE(VaapiWrapper::IsImageFormatSupported(i420_format)); + EXPECT_FALSE(decoder_.GetImage(i420_format.fourcc, &status)); + EXPECT_EQ(VaapiImageDecodeStatus::kInvalidState, status); + + // Workaround: in order to import and map the pixmap using minigbm when the + // format is gfx::BufferFormat::YVU_420, we need to reorder the planes so that + // the offsets are in increasing order as assumed in https://bit.ly/2NLubNN. + // Otherwise, we get a validation error. In essence, we're making minigbm + // think that it is mapping a YVU_420, but it's actually mapping a YUV_420. + // + // TODO(andrescj): revisit this once crrev.com/c/1573718 lands. + gfx::NativePixmapHandle handle = pixmap->ExportHandle(); + if (pixmap->GetBufferFormat() == gfx::BufferFormat::YVU_420) + std::swap(handle.planes[1], handle.planes[2]); + + LocalGpuMemoryBufferManager gpu_memory_buffer_manager; + std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer = + gpu_memory_buffer_manager.ImportDmaBuf(handle, pixmap->GetBufferSize(), + pixmap->GetBufferFormat()); + ASSERT_TRUE(gpu_memory_buffer); + ASSERT_TRUE(gpu_memory_buffer->Map()); + DecodedVAImage decoded_image{}; + const gfx::BufferFormat format = gpu_memory_buffer->GetFormat(); + if (format == gfx::BufferFormat::YVU_420) { + decoded_image.va_fourcc = VA_FOURCC_I420; + decoded_image.number_of_planes = 3u; + } else if (format == gfx::BufferFormat::YUV_420_BIPLANAR) { + decoded_image.va_fourcc = VA_FOURCC_NV12; + decoded_image.number_of_planes = 2u; + } else { + ASSERT_TRUE(false) << "Unsupported format " + << gfx::BufferFormatToString(format); + } + decoded_image.coded_size = gpu_memory_buffer->GetSize(); + for (size_t plane = 0u; + plane < base::strict_cast<size_t>(decoded_image.number_of_planes); + plane++) { + decoded_image.planes[plane].data = + static_cast<uint8_t*>(gpu_memory_buffer->memory(plane)); + decoded_image.planes[plane].stride = gpu_memory_buffer->stride(plane); + } + EXPECT_TRUE(CompareImages(encoded_image, decoded_image)); + gpu_memory_buffer->Unmap(); +} + // Make sure that JPEGs whose size is below the supported size range are // rejected. //
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc index b07af1b..bcc5286a 100644 --- a/media/gpu/vaapi/vaapi_wrapper.cc +++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -4,11 +4,13 @@ #include "media/gpu/vaapi/vaapi_wrapper.h" -#include <algorithm> -#include <type_traits> - #include <dlfcn.h> #include <string.h> +#include <unistd.h> + +#include <algorithm> +#include <type_traits> +#include <utility> #include <va/va.h> #include <va/va_drm.h> @@ -19,11 +21,14 @@ #include "base/bind_helpers.h" #include "base/callback_helpers.h" #include "base/environment.h" +#include "base/files/scoped_file.h" #include "base/logging.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/no_destructor.h" +#include "base/numerics/checked_math.h" #include "base/numerics/safe_conversions.h" +#include "base/posix/eintr_wrapper.h" #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/system/sys_info.h" @@ -41,7 +46,10 @@ #include "media/gpu/vaapi/vaapi_utils.h" #include "third_party/libyuv/include/libyuv.h" #include "ui/gfx/buffer_format_util.h" +#include "ui/gfx/buffer_types.h" +#include "ui/gfx/linux/native_pixmap_dmabuf.h" #include "ui/gfx/native_pixmap.h" +#include "ui/gfx/native_pixmap_handle.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_implementation.h" @@ -1400,6 +1408,87 @@ base::BindOnce(&VaapiWrapper::DestroySurface, this)); } +scoped_refptr<gfx::NativePixmapDmaBuf> +VaapiWrapper::ExportVASurfaceAsNativePixmapDmaBuf(VASurfaceID va_surface_id) { + VADRMPRIMESurfaceDescriptor descriptor; + { + base::AutoLock auto_lock(*va_lock_); + VAStatus va_res = vaSyncSurface(va_display_, va_surface_id); + VA_SUCCESS_OR_RETURN(va_res, "Cannot sync VASurface", nullptr); + va_res = vaExportSurfaceHandle( + va_display_, va_surface_id, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, + VA_EXPORT_SURFACE_READ_ONLY | VA_EXPORT_SURFACE_SEPARATE_LAYERS, + &descriptor); + VA_SUCCESS_OR_RETURN(va_res, "Failed to export VASurface", nullptr); + } + + // We only support one bo containing all the planes. The fd should be owned by + // us: per va/va.h, "the exported handles are owned by the caller." + // + // TODO(crbug.com/974438): support multiple buffer objects so that this can + // work in AMD. + if (descriptor.num_objects != 1u) { + DVLOG(1) << "Only surface descriptors with one bo are supported"; + return nullptr; + } + base::ScopedFD bo_fd(descriptor.objects[0].fd); + const uint64_t bo_modifier = descriptor.objects[0].drm_format_modifier; + + // Translate the pixel format to a gfx::BufferFormat. + gfx::BufferFormat buffer_format; + switch (descriptor.fourcc) { + case VA_FOURCC_IMC3: + // IMC3 is like I420 but all the planes have the same stride. This is used + // for decoding 4:2:0 JPEGs in the Intel i965 driver. We don't currently + // have a gfx::BufferFormat for YUV420. Instead, we reuse YVU_420 and + // later swap the U and V planes. + // + // TODO(andrescj): revisit this once crrev.com/c/1573718 lands. + buffer_format = gfx::BufferFormat::YVU_420; + break; + case VA_FOURCC_NV12: + buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR; + break; + default: + LOG(ERROR) << "Cannot export a surface with FOURCC " + << FourccToString(descriptor.fourcc); + return nullptr; + } + + gfx::NativePixmapHandle handle{}; + handle.modifier = bo_modifier; + for (uint32_t layer = 0; layer < descriptor.num_layers; layer++) { + // According to va/va_drmcommon.h, if VA_EXPORT_SURFACE_SEPARATE_LAYERS is + // specified, each layer should contain one plane. + DCHECK_EQ(1u, descriptor.layers[layer].num_planes); + + // Strictly speaking, we only have to dup() the fd for the planes after the + // first one since we already own the first one, but we dup() regardless for + // simplicity: |bo_fd| will be closed at the end of this method anyway. + base::ScopedFD plane_fd(HANDLE_EINTR(dup(bo_fd.get()))); + PCHECK(plane_fd.is_valid()); + constexpr uint64_t kZeroSizeToPreventMapping = 0u; + handle.planes.emplace_back( + base::checked_cast<int>(descriptor.layers[layer].pitch[0]), + base::checked_cast<int>(descriptor.layers[layer].offset[0]), + kZeroSizeToPreventMapping, + base::ScopedFD(HANDLE_EINTR(dup(bo_fd.get())))); + } + + if (descriptor.fourcc == VA_FOURCC_IMC3) { + // Recall that for VA_FOURCC_IMC3, we will return a format of + // gfx::BufferFormat::YVU_420, so we need to swap the U and V planes to keep + // the semantics. + DCHECK_EQ(3u, handle.planes.size()); + std::swap(handle.planes[1], handle.planes[2]); + } + + return base::MakeRefCounted<gfx::NativePixmapDmaBuf>( + gfx::Size(base::checked_cast<int>(descriptor.width), + base::checked_cast<int>(descriptor.height)), + buffer_format, std::move(handle)); +} + bool VaapiWrapper::SubmitBuffer(VABufferType va_buffer_type, size_t size, const void* buffer) {
diff --git a/media/gpu/vaapi/vaapi_wrapper.h b/media/gpu/vaapi/vaapi_wrapper.h index 3d6fe96..8253cfa6 100644 --- a/media/gpu/vaapi/vaapi_wrapper.h +++ b/media/gpu/vaapi/vaapi_wrapper.h
@@ -23,6 +23,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" #include "base/synchronization/lock.h" #include "base/thread_annotations.h" #include "media/gpu/media_gpu_export.h" @@ -36,7 +37,9 @@ #endif // USE_X11 namespace gfx { +enum class BufferFormat; class NativePixmap; +class NativePixmapDmaBuf; } namespace media { @@ -188,6 +191,25 @@ scoped_refptr<VASurface> CreateVASurfaceForPixmap( const scoped_refptr<gfx::NativePixmap>& pixmap); + // Syncs and exports the VA surface identified by |va_surface_id| as a + // gfx::NativePixmapDmaBuf. Currently, the only VAAPI surface pixel formats + // supported are VA_FOURCC_IMC3 and VA_FOURCC_NV12. + // + // Notes: + // + // - For VA_FOURCC_IMC3, the format of the returned NativePixmapDmaBuf is + // gfx::BufferFormat::YVU_420 because we don't have a YUV_420 format. The + // planes are flipped accordingly, i.e., + // gfx::NativePixmapDmaBuf::GetDmaBufOffset(1) refers to the V plane. + // TODO(andrescj): revisit once crrev.com/c/1573718 lands. + // + // - For VA_FOURCC_NV12, the format of the returned NativePixmapDmaBuf is + // gfx::BufferFormat::YUV_420_BIPLANAR. + // + // Returns nullptr on failure. + scoped_refptr<gfx::NativePixmapDmaBuf> ExportVASurfaceAsNativePixmapDmaBuf( + VASurfaceID va_surface_id); + // Submit parameters or slice data of |va_buffer_type|, copying them from // |buffer| of size |size|, into HW codec. The data in |buffer| is no // longer needed and can be freed after this method returns.
diff --git a/media/gpu/video_decode_accelerator_tests.cc b/media/gpu/video_decode_accelerator_tests.cc index 265185f..a4dda81 100644 --- a/media/gpu/video_decode_accelerator_tests.cc +++ b/media/gpu/video_decode_accelerator_tests.cc
@@ -42,7 +42,7 @@ " --disable_validator disable frame validation, useful on old\n" " platforms that don't support import mode.\n" " --output_frames write all decoded video frames to the\n" - " \"video_frames\" folder.\n" + " \"<testname>\" folder.\n" " --output_folder overwrite the default output folder used when\n" " \"--output_frames\" is specified.\n" " --use_vd use the new VD-based video decoders, instead of\n" @@ -52,10 +52,6 @@ media::test::VideoPlayerTestEnvironment* g_env; -// Default output folder used to store video frames. -constexpr const base::FilePath::CharType* kDefaultOutputFolder = - FILE_PATH_LITERAL("video_frames"); - // Video decode test class. Performs setup and teardown for each single test. class VideoDecoderTest : public ::testing::Test { public: @@ -73,7 +69,7 @@ media::test::VideoFrameValidator::Create(video->FrameChecksums())); } - // Write decoded video frames to the 'video_frames/<test_name/>' folder. + // Write decoded video frames to the '<testname>' folder. if (g_env->IsFramesOutputEnabled()) { base::FilePath output_folder = base::FilePath(g_env->OutputFolder()) @@ -85,6 +81,10 @@ // Use the new VD-based video decoders if requested. config.use_vd = g_env->UseVD(); + // Force allocate mode if import mode is not supported. + if (!g_env->ImportSupported()) + config.allocation_mode = AllocationMode::kAllocate; + return VideoPlayer::Create(video, std::move(frame_renderer), std::move(frame_processors), config); } @@ -265,11 +265,16 @@ if (g_env->IsValidatorEnabled()) GTEST_SKIP(); + base::FilePath output_folder = + base::FilePath(g_env->OutputFolder()) + .Append(base::FilePath(g_env->GetTestName())); + VideoDecoderClientConfig config; config.allocation_mode = AllocationMode::kAllocate; auto tvp = CreateVideoPlayer( g_env->Video(), config, - FrameRendererThumbnail::Create(g_env->Video()->ThumbnailChecksums())); + FrameRendererThumbnail::Create(g_env->Video()->ThumbnailChecksums(), + output_folder)); tvp->Play(); EXPECT_TRUE(tvp->WaitForFlushDone()); @@ -308,7 +313,7 @@ // Parse command line arguments. bool enable_validator = true; bool output_frames = false; - base::FilePath::StringType output_folder = media::test::kDefaultOutputFolder; + base::FilePath::StringType output_folder = base::FilePath::kCurrentDirectory; bool use_vd = false; base::CommandLine::SwitchMap switches = cmd_line->GetSwitches(); for (base::CommandLine::SwitchMap::const_iterator it = switches.begin();
diff --git a/mojo/public/tools/bindings/generators/js_templates/lite/test/BUILD.gn b/mojo/public/tools/bindings/generators/js_templates/lite/test/BUILD.gn index ec085c5..b2263ccf 100644 --- a/mojo/public/tools/bindings/generators/js_templates/lite/test/BUILD.gn +++ b/mojo/public/tools/bindings/generators/js_templates/lite/test/BUILD.gn
@@ -10,10 +10,20 @@ sources = [ "test.test-mojom", ] + + use_old_js_lite_bindings_names = false +} + +mojom("mojo_old_names_bindings") { + testonly = true + sources = [ + "test_old_names.test-mojom", + ] } js_type_check("closure_compile") { deps = [ + ":old_names_test", ":test", ] } @@ -21,5 +31,12 @@ js_library("test") { deps = [ ":mojo_bindings_js_library_for_compile", + ":mojo_old_names_bindings_js_library_for_compile", + ] +} + +js_library("old_names_test") { + deps = [ + ":mojo_old_names_bindings_js_library_for_compile", ] }
diff --git a/mojo/public/tools/bindings/generators/js_templates/lite/test/old_names_test.js b/mojo/public/tools/bindings/generators/js_templates/lite/test/old_names_test.js new file mode 100644 index 0000000..816e733 --- /dev/null +++ b/mojo/public/tools/bindings/generators/js_templates/lite/test/old_names_test.js
@@ -0,0 +1,43 @@ +// Copyright 2018 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. + +(() => { + async function testFunction() { + /** @type {oldNameTest.mojom.TestPageHandlerProxy} */ + let proxy = oldNameTest.mojom.TestPageHandler.getProxy() + + // Type infers {?{values: !Array<!string>}} from Promise return type. + let result = await proxy.method1(' ', 5); + + /** @type {Array<string>} */ + let values = result.values; + + /** @type {oldNameTest.mojom.TestStruct} */ + let testStruct = result.ts + } + + /** @implements {oldNameTest.mojom.TestPageInterface} */ + class TestPageImpl { + /** @override */ + onEvent1(s) { + /** @type {oldNameTest.mojom.TestStruct} */ let t = s; + /** @type {string} */ let id = t.id; + /** @type {string|undefined} */ let title = t.title; + /** @type {oldNameTest.mojom.TestEnum} */ let enumValue = t.enums[0]; + + /** @type {string} */ let numberToStringMapValue = t.numberToStringMap[5]; + + /** @type {oldNameTest.mojom.Message} */ + let messageToMessageArrayValue = + t.messageToArrayMap.get({message: 'asdf'})[0]; + + /** @type {oldNameTest.mojom.TestEnum} */ let enumToMapMapValue = + t.enumToMapMap[oldNameTest.mojom.TestEnum.FIRST] + [oldNameTest.mojom.TestEnum.SECOND]; + /** @type {oldNameTest.mojom.TestPageInterface} */ + let handler = t.numberToInterfaceProxyMap[3]; + handler.onEvent1(t); + } + } +})();
diff --git a/mojo/public/tools/bindings/generators/js_templates/lite/test/test.js b/mojo/public/tools/bindings/generators/js_templates/lite/test/test.js index 0ba0164d..31d12f8 100644 --- a/mojo/public/tools/bindings/generators/js_templates/lite/test/test.js +++ b/mojo/public/tools/bindings/generators/js_templates/lite/test/test.js
@@ -3,11 +3,11 @@ // found in the LICENSE file. async function testFunction() { - /** @type {test.mojom.TestPageHandlerProxy} */ - let proxy = test.mojom.TestPageHandler.getProxy() + /** @type {test.mojom.TestPageHandlerRemote} */ + let remote = test.mojom.TestPageHandler.getRemote() // Type infers {?{values: !Array<!string>}} from Promise return type. - let result = await proxy.method1(' ', 5); + let result = await remote.method1(' ', 5); /** @type {Array<string>} */ let values = result.values;
diff --git a/mojo/public/tools/bindings/generators/js_templates/lite/test/test_old_names.test-mojom b/mojo/public/tools/bindings/generators/js_templates/lite/test/test_old_names.test-mojom new file mode 100644 index 0000000..09fc6b08 --- /dev/null +++ b/mojo/public/tools/bindings/generators/js_templates/lite/test/test_old_names.test-mojom
@@ -0,0 +1,32 @@ +// Copyright 2018 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. + +module old_name_test.mojom; + +enum TestEnum { + FIRST, + SECOND, +}; + +struct Message { + string message; +}; + +struct TestStruct { + string id; + string? title; + array<TestEnum> enums; + map<uint32, string> numberToStringMap; + map<Message, array<Message>> messageToArrayMap; + map<TestEnum, map<TestEnum, TestEnum>> enumToMapMap; + map<uint32, TestPage> numberToInterfaceProxyMap; +}; + +interface TestPageHandler { + Method1(string p1, int32 p2) => (array<string> values, TestStruct ts); +}; + +interface TestPage { + OnEvent1(TestStruct s); +};
diff --git a/net/cert/cert_verify_proc_builtin.cc b/net/cert/cert_verify_proc_builtin.cc index 4a911e2..b5ef8e7 100644 --- a/net/cert/cert_verify_proc_builtin.cc +++ b/net/cert/cert_verify_proc_builtin.cc
@@ -40,6 +40,9 @@ // TODO(https://crbug.com/634470): Make this smaller. constexpr uint32_t kPathBuilderIterationLimit = 25000; +constexpr base::TimeDelta kMaxVerificationTime = + base::TimeDelta::FromSeconds(60); + DEFINE_CERT_ERROR_ID(kPathLacksEVPolicy, "Path does not have an EV policy"); RevocationPolicy NoRevocationChecking() { @@ -422,6 +425,7 @@ CertIssuerSourceStatic* intermediates, SystemTrustStore* ssl_trust_store, base::Time verification_time, + base::TimeTicks deadline, VerificationType verification_type, SimplePathBuilderDelegate::DigestPolicy digest_policy, int flags, @@ -475,6 +479,7 @@ } path_builder.SetIterationLimit(kPathBuilderIterationLimit); + path_builder.SetDeadline(deadline); path_builder.Run(); } @@ -584,6 +589,7 @@ // VerifyInternal() is expected to carry out verifications using the current // time stamp. base::Time verification_time = base::Time::Now(); + base::TimeTicks deadline = base::TimeTicks::Now() + kMaxVerificationTime; // Parse the target certificate. scoped_refptr<ParsedCertificate> target = @@ -647,12 +653,12 @@ // Run the attempt through the path builder. TryBuildPath(target, &intermediates, ssl_trust_store.get(), - verification_time, cur_attempt.verification_type, + verification_time, deadline, cur_attempt.verification_type, cur_attempt.digest_policy, flags, ocsp_response, crl_set, net_fetcher_.get(), ev_metadata, &result, &checked_revocation_for_some_path); - if (result.HasValidPath()) + if (result.HasValidPath() || result.exceeded_deadline) break; // If this path building attempt (may have) failed due to the chain using a
diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc index b04dfdb..e81d485 100644 --- a/net/cert/internal/path_builder.cc +++ b/net/cert/internal/path_builder.cc
@@ -372,6 +372,7 @@ // returns false. bool GetNextPath(ParsedCertificateList* out_certs, CertificateTrust* out_last_cert_trust, + const base::TimeTicks deadline, uint32_t* iteration_count, const uint32_t max_iteration_count); @@ -405,9 +406,13 @@ bool CertPathIter::GetNextPath(ParsedCertificateList* out_certs, CertificateTrust* out_last_cert_trust, + const base::TimeTicks deadline, uint32_t* iteration_count, const uint32_t max_iteration_count) { while (true) { + if (!deadline.is_null() && base::TimeTicks::Now() > deadline) + return false; + if (!next_issuer_.cert) { if (cur_path_.Empty()) { DVLOG(1) << "CertPathIter exhausted all paths..."; @@ -565,6 +570,10 @@ max_iteration_count_ = limit; } +void CertPathBuilder::SetDeadline(base::TimeTicks deadline) { + deadline_ = deadline; +} + void CertPathBuilder::Run() { uint32_t iteration_count = 0; @@ -573,12 +582,15 @@ std::make_unique<CertPathBuilderResultPath>(); if (!cert_path_iter_->GetNextPath(&result_path->certs, - &result_path->last_cert_trust, + &result_path->last_cert_trust, deadline_, &iteration_count, max_iteration_count_)) { // No more paths to check. if (max_iteration_count_ > 0 && iteration_count > max_iteration_count_) { out_result_->exceeded_iteration_limit = true; } + if (!deadline_.is_null() && base::TimeTicks::Now() > deadline_) { + out_result_->exceeded_deadline = true; + } return; }
diff --git a/net/cert/internal/path_builder.h b/net/cert/internal/path_builder.h index ec09517..5562c4e 100644 --- a/net/cert/internal/path_builder.h +++ b/net/cert/internal/path_builder.h
@@ -133,6 +133,10 @@ // configured with |SetIterationLimit|. bool exceeded_iteration_limit = false; + // True if the search stopped because it exceeded the deadline configured + // with |SetDeadline|. + bool exceeded_deadline = false; + private: DISALLOW_COPY_AND_ASSIGN(Result); }; @@ -177,6 +181,12 @@ // new intermediate over all potential paths. void SetIterationLimit(uint32_t limit); + // Sets a deadline for completing path building. If |deadline| has passed and + // path building has not completed, path building will stop. Note that this + // is not a hard limit, there is no guarantee how far past |deadline| time + // will be when path building is aborted. + void SetDeadline(base::TimeTicks deadline); + // Executes verification of the target certificate. // // Upon return results are written to the |result| object passed into the @@ -196,6 +206,7 @@ const InitialPolicyMappingInhibit initial_policy_mapping_inhibit_; const InitialAnyPolicyInhibit initial_any_policy_inhibit_; uint32_t max_iteration_count_ = 0; + base::TimeTicks deadline_; Result* out_result_;
diff --git a/net/cert/internal/path_builder_unittest.cc b/net/cert/internal/path_builder_unittest.cc index a2bba7fd..87840cd 100644 --- a/net/cert/internal/path_builder_unittest.cc +++ b/net/cert/internal/path_builder_unittest.cc
@@ -488,6 +488,45 @@ } } +TEST_F(PathBuilderMultiRootTest, TestTrivialDeadline) { + // C(D) is the trust root. + TrustStoreInMemory trust_store; + trust_store.AddTrustAnchor(c_by_d_); + + // Cert B(C) is supplied. + CertIssuerSourceStatic sync_certs; + sync_certs.AddCert(b_by_c_); + + for (const bool insufficient_limit : {true, false}) { + SCOPED_TRACE(insufficient_limit); + + CertPathBuilder::Result result; + CertPathBuilder path_builder( + a_by_b_, &trust_store, &delegate_, time_, KeyPurpose::ANY_EKU, + initial_explicit_policy_, user_initial_policy_set_, + initial_policy_mapping_inhibit_, initial_any_policy_inhibit_, &result); + path_builder.AddCertIssuerSource(&sync_certs); + + if (insufficient_limit) { + // Set a deadline one millisecond in the past. Path building should fail + // since the deadline is already past. + path_builder.SetDeadline(base::TimeTicks::Now() - + base::TimeDelta::FromMilliseconds(1)); + } else { + // The other tests in this file exercise the case that |SetDeadline| + // isn't called. Therefore set a sufficient limit for the path to be + // found. + path_builder.SetDeadline(base::TimeTicks::Now() + + base::TimeDelta::FromDays(1)); + } + + path_builder.Run(); + + EXPECT_EQ(!insufficient_limit, result.HasValidPath()); + EXPECT_EQ(insufficient_limit, result.exceeded_deadline); + } +} + class PathBuilderKeyRolloverTest : public ::testing::Test { public: PathBuilderKeyRolloverTest()
diff --git a/net/nqe/network_congestion_analyzer.cc b/net/nqe/network_congestion_analyzer.cc index 0401585..462a7aa 100644 --- a/net/nqe/network_congestion_analyzer.cc +++ b/net/nqe/network_congestion_analyzer.cc
@@ -2,8 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> + #include <net/nqe/network_congestion_analyzer.h> +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" + namespace net { namespace nqe { @@ -12,6 +17,7 @@ NetworkCongestionAnalyzer::NetworkCongestionAnalyzer() : recent_active_hosts_count_(0u) {} + NetworkCongestionAnalyzer::~NetworkCongestionAnalyzer() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } @@ -21,6 +27,51 @@ return recent_active_hosts_count_; } +void NetworkCongestionAnalyzer::NotifyStartTransaction( + const URLRequest& request) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Starts tracking the peak queueing delay after |request| starts. + TrackPeakQueueingDelayBegin(&request); +} + +void NetworkCongestionAnalyzer::NotifyRequestCompleted( + const URLRequest& request) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Ends tracking of the peak queueing delay. + base::Optional<base::TimeDelta> peak_observed_delay = + TrackPeakQueueingDelayEnd(&request); + if (peak_observed_delay.has_value()) { + UMA_HISTOGRAM_MEDIUM_TIMES("ResourceScheduler.PeakObservedQueueingDelay", + peak_observed_delay.value()); + } +} + +void NetworkCongestionAnalyzer::TrackPeakQueueingDelayBegin( + const URLRequest* request) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // Returns if |request| has already been tracked. + if (request_peak_delay_.find(request) != request_peak_delay_.end()) + return; + + request_peak_delay_[request] = base::nullopt; +} + +base::Optional<base::TimeDelta> +NetworkCongestionAnalyzer::TrackPeakQueueingDelayEnd( + const URLRequest* request) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + auto request_delay = request_peak_delay_.find(request); + if (request_delay == request_peak_delay_.end()) + return base::nullopt; + + base::Optional<base::TimeDelta> peak_delay = request_delay->second; + request_peak_delay_.erase(request_delay); + return peak_delay; +} + void NetworkCongestionAnalyzer::ComputeRecentQueueingDelay( const std::map<nqe::internal::IPHash, nqe::internal::CanonicalStats>& recent_rtt_stats, @@ -63,6 +114,16 @@ int32_t delay_ms = delay_sample_sum / static_cast<int>(recent_active_hosts_count_); recent_queueing_delay_ = base::TimeDelta::FromMilliseconds(delay_ms); + + // Updates the peak queueing delay for all tracked in-flight requests. + for (auto& it : request_peak_delay_) { + if (it.second.has_value()) { + it.second = std::max(it.second.value(), recent_queueing_delay_); + } else { + it.second = recent_queueing_delay_; + } + } + if (recent_downlink_per_packet_time_ms_ != base::nullopt) { recent_queue_length_ = static_cast<float>(delay_ms) / recent_downlink_per_packet_time_ms_.value();
diff --git a/net/nqe/network_congestion_analyzer.h b/net/nqe/network_congestion_analyzer.h index f00fbcb..0985baf 100644 --- a/net/nqe/network_congestion_analyzer.h +++ b/net/nqe/network_congestion_analyzer.h
@@ -17,6 +17,7 @@ #include "net/nqe/network_quality.h" #include "net/nqe/network_quality_estimator_util.h" #include "net/nqe/observation_buffer.h" +#include "net/nqe/throughput_analyzer.h" namespace net { @@ -36,6 +37,12 @@ // computing the recent queueing delay. These hosts are recent active hosts. size_t GetActiveHostsCount() const; + // Notifies |this| that the headers of |request| are about to be sent. + void NotifyStartTransaction(const URLRequest& request); + + // Notifies |this| that the response body of |request| has been received. + void NotifyRequestCompleted(const URLRequest& request); + // Computes the recent queueing delay. Records the observed queueing delay // samples for all recent active hosts. The mean queueing delay is recorded in // |recent_queueing_delay_|. |recent_rtt_stats| has all canonical statistic @@ -61,6 +68,15 @@ } private: + // Starts tracking the peak queueing delay for |request|. + void TrackPeakQueueingDelayBegin(const URLRequest* request); + + // Returns the peak queueing delay observed by |request|. Also removes the + // record that belongs to |request| in the map. If the result is unavailable, + // returns nullopt. + base::Optional<base::TimeDelta> TrackPeakQueueingDelayEnd( + const URLRequest* request); + // Sets the |recent_downlink_throughput_kbps_| with the estimated downlink // throughput in kbps. Also, computes the time frame (in millisecond) to // transmit one TCP packet (1500 Bytes) under this downlink throughput. @@ -83,6 +99,15 @@ // The estimate of queueing delay induced by packet queue. base::TimeDelta recent_queueing_delay_; + // Mapping between URL requests to the observed queueing delay observations. + // The default value is nullopt. + typedef std::unordered_map<const URLRequest*, base::Optional<base::TimeDelta>> + RequestPeakDelay; + + // This map maintains the mapping from in-flight URL requests to the peak + // queueing delay observed by requests. + RequestPeakDelay request_peak_delay_; + // Counts the number of hosts involved in the last attempt of computing the // recent queueing delay. size_t recent_active_hosts_count_;
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc index 5ac9dbc..4c2af1d3 100644 --- a/net/nqe/network_quality_estimator.cc +++ b/net/nqe/network_quality_estimator.cc
@@ -276,6 +276,7 @@ MaybeComputeEffectiveConnectionType(); } throughput_analyzer_->NotifyStartTransaction(request); + network_congestion_analyzer_.NotifyStartTransaction(request); } bool NetworkQualityEstimator::IsHangingRequest( @@ -390,6 +391,7 @@ return; throughput_analyzer_->NotifyRequestCompleted(request); + network_congestion_analyzer_.NotifyRequestCompleted(request); } void NetworkQualityEstimator::NotifyURLRequestDestroyed(
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index f5b83e7..810b0f2 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc
@@ -2666,11 +2666,6 @@ // Verify that if a QUIC connection RTOs, the QuicHttpStream will // return QUIC_PROTOCOL_ERROR. TEST_P(QuicNetworkTransactionTest, TooManyRtosAfterHandshakeConfirmed) { - if (version_.transport_version == quic::QUIC_VERSION_99) { - // TODO(rch): Re-enable. - return; - } - session_params_.retry_without_alt_svc_on_quic_errors = false; session_params_.quic_connection_options.push_back(quic::k5RTO); @@ -2688,37 +2683,64 @@ priority, GetRequestHeaders("GET", "https", "/"), 0, nullptr)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); - quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(2)); - // TLP 1 - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(1, 3, true)); - // TLP 2 - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 4, true)); - // RTO 1 - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(1, 5, true)); - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 6, true)); - // RTO 2 - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(1, 7, true)); - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 8, true)); - // RTO 3 - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(1, 9, true)); - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 10, true)); - // RTO 4 - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(1, 11, true)); - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 12, true)); - // RTO 5 - quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectionClosePacket( - 13, true, quic::QUIC_TOO_MANY_RTOS, - "5 consecutive retransmission timeouts")); + if (version_.transport_version != quic::QUIC_VERSION_99) { + quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(2)); + // TLP 1 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 3, true)); + // TLP 2 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(2, 4, true)); + // RTO 1 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 5, true)); + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(2, 6, true)); + // RTO 2 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 7, true)); + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(2, 8, true)); + // RTO 3 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 9, true)); + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(2, 10, true)); + // RTO 4 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 11, true)); + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(2, 12, true)); + // RTO 5 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeConnectionClosePacket( + 13, true, quic::QUIC_TOO_MANY_RTOS, + "5 consecutive retransmission timeouts")); + } else { + // TLP 1 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 2, true)); + // TLP 2 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 3, true)); + // RTO 1 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 4, true)); + // RTO 2 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 5, true)); + // RTO 3 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 6, true)); + // RTO 4 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeRetransmissionPacket(1, 7, true)); + // RTO 5 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeConnectionClosePacket( + 8, true, quic::QUIC_TOO_MANY_RTOS, + "5 consecutive retransmission timeouts")); + } quic_data.AddRead(ASYNC, OK); quic_data.AddSocketDataToFactory(&socket_factory_); @@ -2764,11 +2786,6 @@ // QUIC will not be marked as broken. TEST_P(QuicNetworkTransactionTest, TooManyRtosAfterHandshakeConfirmedAndStreamReset) { - if (version_.transport_version == quic::QUIC_VERSION_99) { - // TODO(rch): Re-enable. - return; - } - session_params_.quic_connection_options.push_back(quic::k5RTO); // The request will initially go out over QUIC. @@ -2785,42 +2802,55 @@ priority, GetRequestHeaders("GET", "https", "/"), 0, nullptr)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); - quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(2)); + if (version_.transport_version != quic::QUIC_VERSION_99) { + quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(2)); + } - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRstPacket( - 3, true, GetNthClientInitiatedBidirectionalStreamId(0), - quic::QUIC_STREAM_CANCELLED)); if (quic::VersionUsesQpack(version_.transport_version)) { + quic_data.AddWrite( + SYNCHRONOUS, client_maker_.MakeRstPacket( + 2, true, GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED)); // Since the headers are sent on the data stream, when the stream is reset // the headers are no longer retransmitted. + client_maker_.RemoveSavedStreamFrames( + GetNthClientInitiatedBidirectionalStreamId(0)); // TLP 1 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 4, true)); + client_maker_.MakeRetransmissionPacket(1, 3, true)); // TLP 2 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(3, 5, true)); + client_maker_.MakeRetransmissionPacket(2, 4, true)); // RTO 1 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 6, true)); + client_maker_.MakeRetransmissionPacket(1, 5, true)); quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(3, 7, true)); + client_maker_.MakeRetransmissionPacket(2, 6, true)); // RTO 2 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 8, true)); + client_maker_.MakeRetransmissionPacket(1, 7, true)); quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(3, 9, true)); + client_maker_.MakeRetransmissionPacket(2, 8, true)); // RTO 3 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 10, true)); + client_maker_.MakeRetransmissionPacket(1, 9, true)); quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(3, 11, true)); + client_maker_.MakeRetransmissionPacket(2, 10, true)); // RTO 4 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 12, true)); + client_maker_.MakeRetransmissionPacket(1, 11, true)); quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(3, 13, true)); + client_maker_.MakeRetransmissionPacket(2, 12, true)); + // RTO 5 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeConnectionClosePacket( + 13, true, quic::QUIC_TOO_MANY_RTOS, + "5 consecutive retransmission timeouts")); } else { + quic_data.AddWrite( + SYNCHRONOUS, client_maker_.MakeRstPacket( + 3, true, GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED)); // TLP 1 quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeRetransmissionPacket(1, 4, true)); @@ -2847,11 +2877,11 @@ client_maker_.MakeRetransmissionPacket(3, 12, true)); quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeRetransmissionPacket(1, 13, true)); - } // RTO 5 quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectionClosePacket( 14, true, quic::QUIC_TOO_MANY_RTOS, "5 consecutive retransmission timeouts")); + } quic_data.AddRead(ASYNC, OK); quic_data.AddSocketDataToFactory(&socket_factory_); @@ -2900,11 +2930,6 @@ // Verify that if a QUIC protocol error occurs after the handshake is confirmed // the request fails with QUIC_PROTOCOL_ERROR. TEST_P(QuicNetworkTransactionTest, ProtocolErrorAfterHandshakeConfirmed) { - if (version_.transport_version == quic::QUIC_VERSION_99) { - // TODO(rch): Re-enable. - return; - } - session_params_.retry_without_alt_svc_on_quic_errors = false; // The request will initially go out over QUIC. MockQuicData quic_data(version_); @@ -2919,6 +2944,7 @@ quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket(packet_number++)); } + quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause // Peer sending data from an non-existing stream causes this end to raise // error and close connection. quic_data.AddRead( @@ -2957,6 +2983,7 @@ quic::QuicSession::HANDSHAKE_CONFIRMED); ASSERT_FALSE(quic_data.AllReadDataConsumed()); + quic_data.Resume(); // Run the QUIC session to completion. base::RunLoop().RunUntilIdle(); @@ -3548,11 +3575,6 @@ // QUIC will be marked as broken. TEST_P(QuicNetworkTransactionTest, TooManyRtosAfterHandshakeConfirmedAndStreamResetThenBroken) { - if (version_.transport_version == quic::QUIC_VERSION_99) { - // TODO(rch): Re-enable. - return; - } - session_params_.mark_quic_broken_when_network_blackholes = true; session_params_.quic_connection_options.push_back(quic::k5RTO); @@ -3570,42 +3592,53 @@ priority, GetRequestHeaders("GET", "https", "/"), 0, nullptr)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); - quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(2)); - quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRstPacket( - 3, true, GetNthClientInitiatedBidirectionalStreamId(0), - quic::QUIC_STREAM_CANCELLED)); if (quic::VersionUsesQpack(version_.transport_version)) { + quic_data.AddWrite( + SYNCHRONOUS, client_maker_.MakeRstPacket( + 2, true, GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED)); // Since the headers are sent on the data stream, when the stream is reset // the headers are no longer retransmitted. + client_maker_.RemoveSavedStreamFrames( + GetNthClientInitiatedBidirectionalStreamId(0)); // TLP 1 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 4, true)); + client_maker_.MakeRetransmissionPacket(1, 3, true)); // TLP 2 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(3, 5, true)); + client_maker_.MakeRetransmissionPacket(2, 4, true)); // RTO 1 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 6, true)); + client_maker_.MakeRetransmissionPacket(1, 5, true)); quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(3, 7, true)); + client_maker_.MakeRetransmissionPacket(2, 6, true)); // RTO 2 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 8, true)); + client_maker_.MakeRetransmissionPacket(1, 7, true)); quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(3, 9, true)); + client_maker_.MakeRetransmissionPacket(2, 8, true)); // RTO 3 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 10, true)); + client_maker_.MakeRetransmissionPacket(1, 9, true)); quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(3, 11, true)); + client_maker_.MakeRetransmissionPacket(2, 10, true)); // RTO 4 quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(2, 12, true)); + client_maker_.MakeRetransmissionPacket(1, 11, true)); quic_data.AddWrite(SYNCHRONOUS, - client_maker_.MakeRetransmissionPacket(3, 13, true)); + client_maker_.MakeRetransmissionPacket(2, 12, true)); + // RTO 5 + quic_data.AddWrite(SYNCHRONOUS, + client_maker_.MakeConnectionClosePacket( + 13, true, quic::QUIC_TOO_MANY_RTOS, + "5 consecutive retransmission timeouts")); } else { + quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(2)); + quic_data.AddWrite( + SYNCHRONOUS, client_maker_.MakeRstPacket( + 3, true, GetNthClientInitiatedBidirectionalStreamId(0), + quic::QUIC_STREAM_CANCELLED)); // TLP 1 quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeRetransmissionPacket(1, 4, true)); @@ -3632,12 +3665,11 @@ client_maker_.MakeRetransmissionPacket(3, 12, true)); quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeRetransmissionPacket(1, 13, true)); - } - // RTO 5 quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeConnectionClosePacket( 14, true, quic::QUIC_TOO_MANY_RTOS, "5 consecutive retransmission timeouts")); + } quic_data.AddRead(ASYNC, OK); quic_data.AddSocketDataToFactory(&socket_factory_); @@ -3688,11 +3720,6 @@ // retried over TCP and the QUIC will be marked as broken. TEST_P(QuicNetworkTransactionTest, ProtocolErrorAfterHandshakeConfirmedThenBroken) { - if (version_.transport_version == quic::QUIC_VERSION_99) { - // TODO(rch): Re-enable. - return; - } - session_params_.quic_idle_connection_timeout_seconds = 5; // The request will initially go out over QUIC. @@ -3703,7 +3730,13 @@ 1, GetNthClientInitiatedBidirectionalStreamId(0), true, true, GetRequestHeaders("GET", "https", "/"))); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); - quic_data.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket(2)); + uint64_t packet_number = 2; + if (version_.transport_version != quic::QUIC_VERSION_99) { + quic_data.AddWrite(SYNCHRONOUS, + ConstructInitialSettingsPacket(packet_number++)); + } + quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause + // Peer sending data from an non-existing stream causes this end to raise // error and close connection. quic_data.AddRead( @@ -3711,10 +3744,10 @@ 1, false, GetNthClientInitiatedBidirectionalStreamId(47), quic::QUIC_STREAM_LAST_ERROR)); std::string quic_error_details = "Data for nonexistent stream"; - quic_data.AddWrite(SYNCHRONOUS, - ConstructClientAckAndConnectionClosePacket( - 3, quic::QuicTime::Delta::Zero(), 1, 1, 1, - quic::QUIC_INVALID_STREAM_ID, quic_error_details)); + quic_data.AddWrite( + SYNCHRONOUS, ConstructClientAckAndConnectionClosePacket( + packet_number++, quic::QuicTime::Delta::Zero(), 1, 1, 1, + quic::QUIC_INVALID_STREAM_ID, quic_error_details)); quic_data.AddSocketDataToFactory(&socket_factory_); // After that fails, it will be resent via TCP. @@ -3754,6 +3787,7 @@ // Explicitly confirm the handshake. crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( quic::QuicSession::HANDSHAKE_CONFIRMED); + quic_data.Resume(); // Run the QUIC session to completion. base::RunLoop().RunUntilIdle(); @@ -3779,11 +3813,6 @@ // request is reset from, then QUIC will be marked as broken and the request // retried over TCP. TEST_P(QuicNetworkTransactionTest, ResetAfterHandshakeConfirmedThenBroken) { - if (version_.transport_version == quic::QUIC_VERSION_99) { - // TODO(rch): Re-enable. - return; - } - // The request will initially go out over QUIC. MockQuicData quic_data(version_); spdy::SpdyPriority priority = @@ -3797,7 +3826,10 @@ priority, GetRequestHeaders("GET", "https", "/"), 0, nullptr)); client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE); - quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(2)); + if (version_.transport_version != quic::QUIC_VERSION_99) { + quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(2)); + } + quic_data.AddRead(ASYNC, ERR_IO_PENDING); // Pause quic_data.AddRead(ASYNC, ConstructServerRstPacket( @@ -3844,6 +3876,7 @@ // Explicitly confirm the handshake. crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent( quic::QuicSession::HANDSHAKE_CONFIRMED); + quic_data.Resume(); // Run the QUIC session to completion. ASSERT_TRUE(quic_data.AllWriteDataConsumed());
diff --git a/net/quic/quic_test_packet_maker.cc b/net/quic/quic_test_packet_maker.cc index b09dbc0c..9c1f15f 100644 --- a/net/quic/quic_test_packet_maker.cc +++ b/net/quic/quic_test_packet_maker.cc
@@ -1455,6 +1455,21 @@ nullptr); } +void QuicTestPacketMaker::RemoveSavedStreamFrames( + quic::QuicStreamId stream_id) { + for (auto& kv : saved_frames_) { + auto it = kv.second.begin(); + while (it != kv.second.end()) { + if (it->type == quic::STREAM_FRAME && + it->stream_frame.stream_id == stream_id) { + it = kv.second.erase(it); + } else { + ++it; + } + } + } +} + void QuicTestPacketMaker::SetEncryptionLevel(quic::EncryptionLevel level) { encryption_level_ = level; switch (level) {
diff --git a/net/quic/quic_test_packet_maker.h b/net/quic/quic_test_packet_maker.h index 1518270..7b18e4e 100644 --- a/net/quic/quic_test_packet_maker.h +++ b/net/quic/quic_test_packet_maker.h
@@ -309,6 +309,9 @@ uint64_t new_packet_number, bool should_include_version); + // Removes all stream frames associated with |stream_id|. + void RemoveSavedStreamFrames(quic::QuicStreamId stream_id); + void SetEncryptionLevel(quic::EncryptionLevel level); spdy::SpdyHeaderBlock GetRequestHeaders(const std::string& method,
diff --git a/remoting/protocol/webrtc_audio_stream.cc b/remoting/protocol/webrtc_audio_stream.cc index 1f198be8..703ecda 100644 --- a/remoting/protocol/webrtc_audio_stream.cc +++ b/remoting/protocol/webrtc_audio_stream.cc
@@ -22,12 +22,7 @@ const char kAudioTrackLabel[] = "system_audio"; WebrtcAudioStream::WebrtcAudioStream() = default; - -WebrtcAudioStream::~WebrtcAudioStream() { - if (audio_sender_) { - peer_connection_->RemoveTrack(audio_sender_.get()); - } -} +WebrtcAudioStream::~WebrtcAudioStream() = default; void WebrtcAudioStream::Start( scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner, @@ -47,13 +42,15 @@ peer_connection_factory->CreateAudioTrack(kAudioTrackLabel, source_adapter_.get()); - // value() DCHECKs if AddTrack() fails, which only happens if a track was - // already added with the stream label. - audio_sender_ = - peer_connection_->AddTrack(audio_track.get(), {kAudioStreamLabel}) - .value(); + webrtc::RtpTransceiverInit init; + init.stream_ids = {kAudioStreamLabel}; - webrtc_transport->OnAudioSenderCreated(audio_sender_); + // value() DCHECKs if AddTransceiver() fails, which only happens if a track + // was already added with the stream label. + auto transceiver = + peer_connection_->AddTransceiver(audio_track, init).value(); + + webrtc_transport->OnAudioTransceiverCreated(transceiver); } void WebrtcAudioStream::Pause(bool pause) {
diff --git a/remoting/protocol/webrtc_audio_stream.h b/remoting/protocol/webrtc_audio_stream.h index 13baf221..0865f01 100644 --- a/remoting/protocol/webrtc_audio_stream.h +++ b/remoting/protocol/webrtc_audio_stream.h
@@ -18,7 +18,6 @@ namespace webrtc { class PeerConnectionInterface; -class RtpSenderInterface; } // namespace webrtc namespace remoting { @@ -44,7 +43,6 @@ scoped_refptr<WebrtcAudioSourceAdapter> source_adapter_; scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_; - rtc::scoped_refptr<webrtc::RtpSenderInterface> audio_sender_; DISALLOW_COPY_AND_ASSIGN(WebrtcAudioStream); };
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc index cbea8e8..1e4275a5 100644 --- a/remoting/protocol/webrtc_transport.cc +++ b/remoting/protocol/webrtc_transport.cc
@@ -576,14 +576,12 @@ } } -void WebrtcTransport::OnAudioSenderCreated( - rtc::scoped_refptr<webrtc::RtpSenderInterface> sender) {} +void WebrtcTransport::OnAudioTransceiverCreated( + rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) {} -void WebrtcTransport::OnVideoSenderCreated( - rtc::scoped_refptr<webrtc::RtpSenderInterface> sender) { - // TODO(lambroslambrou): Store the VideoSender here, instead of looping over - // all Senders in GetVideoSender(). - DCHECK_EQ(GetVideoSender(), sender); +void WebrtcTransport::OnVideoTransceiverCreated( + rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) { + video_transceiver_ = transceiver; SetSenderBitrates(MaxBitrateForConnection()); } @@ -956,13 +954,7 @@ rtc::scoped_refptr<webrtc::RtpSenderInterface> WebrtcTransport::GetVideoSender() { - auto senders = peer_connection()->GetSenders(); - for (rtc::scoped_refptr<webrtc::RtpSenderInterface> sender : senders) { - if (sender->media_type() == cricket::MediaType::MEDIA_TYPE_VIDEO) { - return sender; - } - } - return nullptr; + return video_transceiver_ ? video_transceiver_->sender() : nullptr; } } // namespace protocol
diff --git a/remoting/protocol/webrtc_transport.h b/remoting/protocol/webrtc_transport.h index b58c6684..d3a98f1 100644 --- a/remoting/protocol/webrtc_transport.h +++ b/remoting/protocol/webrtc_transport.h
@@ -87,15 +87,13 @@ void ApplySessionOptions(const SessionOptions& options); - // Called when a new AudioSender has been created from - // PeerConnection::AddTrack(). - void OnAudioSenderCreated( - rtc::scoped_refptr<webrtc::RtpSenderInterface> sender); + // Called when a new audio transceiver has been created by the PeerConnection. + void OnAudioTransceiverCreated( + rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver); - // Called when a new VideoSender has been created from - // PeerConnection::AddTrack(). - void OnVideoSenderCreated( - rtc::scoped_refptr<webrtc::RtpSenderInterface> sender); + // Called when a new video transceiver has been created by the PeerConnection. + void OnVideoTransceiverCreated( + rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver); private: // PeerConnectionWrapper is responsible for PeerConnection creation, @@ -184,6 +182,8 @@ std::string preferred_video_codec_; + rtc::scoped_refptr<webrtc::RtpTransceiverInterface> video_transceiver_; + base::WeakPtrFactory<WebrtcTransport> weak_factory_; DISALLOW_COPY_AND_ASSIGN(WebrtcTransport);
diff --git a/remoting/protocol/webrtc_video_stream.cc b/remoting/protocol/webrtc_video_stream.cc index 6e4331d..b5503a9e 100644 --- a/remoting/protocol/webrtc_video_stream.cc +++ b/remoting/protocol/webrtc_video_stream.cc
@@ -100,9 +100,6 @@ WebrtcVideoStream::~WebrtcVideoStream() { DCHECK(thread_checker_.CalledOnValidThread()); - if (video_sender_) { - peer_connection_->RemoveTrack(video_sender_.get()); - } } void WebrtcVideoStream::Start( @@ -135,12 +132,15 @@ rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track = peer_connection_factory->CreateVideoTrack(kVideoLabel, src); - // value() DCHECKs if AddTrack() fails, which only happens if a track was - // already added with the stream label. - video_sender_ = - peer_connection_->AddTrack(video_track.get(), {kStreamLabel}).value(); + webrtc::RtpTransceiverInit init; + init.stream_ids = {kStreamLabel}; - webrtc_transport_->OnVideoSenderCreated(video_sender_); + // value() DCHECKs if AddTransceiver() fails, which only happens if a track + // was already added with the stream label. + auto transceiver = + peer_connection_->AddTransceiver(video_track, init).value(); + + webrtc_transport_->OnVideoTransceiverCreated(transceiver); scheduler_.reset(new WebrtcFrameSchedulerSimple(session_options_)); scheduler_->Start(
diff --git a/remoting/protocol/webrtc_video_stream.h b/remoting/protocol/webrtc_video_stream.h index 07a3cfc..40457e0 100644 --- a/remoting/protocol/webrtc_video_stream.h +++ b/remoting/protocol/webrtc_video_stream.h
@@ -27,7 +27,6 @@ namespace webrtc { class PeerConnectionInterface; -class RtpSenderInterface; } // namespace webrtc namespace remoting { @@ -88,7 +87,6 @@ scoped_refptr<InputEventTimestampsSource> event_timestamps_source_; scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_; - rtc::scoped_refptr<webrtc::RtpSenderInterface> video_sender_; HostVideoStatsDispatcher video_stats_dispatcher_;
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index 98dc151..6bb9205 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -6993,6 +6993,54 @@ }, "test": "content_browsertests" } + ], + "isolated_scripts": [ + { + "args": [ + "pixel", + "--show-stdout", + "--browser=android-chromium", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc \"--use-vulkan=native --disable-vulkan-fallback-to-gl-for-testing --enable-features=UseSkiaRenderer\"", + "--dont-restore-color-profile-after-test", + "--refimg-cloud-storage-bucket", + "chromium-gpu-archive/reference-images", + "--os-type", + "android", + "--build-revision", + "${got_revision}", + "--test-machine-name", + "${buildername}" + ], + "isolate_name": "telemetry_gpu_integration_test", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "pixel_test", + "non_precommit_args": [ + "--upload-refimg-to-cloud-storage" + ], + "precommit_args": [ + "--download-refimg-from-cloud-storage" + ], + "should_retry_with_patch": false, + "swarming": { + "can_use_on_swarming_builders": true, + "containment_type": "AUTO", + "dimension_sets": [ + { + "device_os": "P", + "device_os_type": "userdebug", + "device_type": "walleye", + "os": "Android", + "pool": "Chrome-GPU" + } + ], + "idempotent": false + } + } ] }, "Android FYI dEQP Release (Nexus 5X)": {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index f292e3a7..d2ad2615 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -3600,6 +3600,30 @@ }, }, + 'gpu_skia_renderer_vulkan_telemetry_tests': { + 'pixel': { + 'name': 'pixel_test', + 'args': [ + '--dont-restore-color-profile-after-test', + '--refimg-cloud-storage-bucket', + 'chromium-gpu-archive/reference-images', + '--os-type', + '${os_type}', + '--build-revision', + '${got_revision}', + '--test-machine-name', + '${buildername}', + '--extra-browser-args="--use-vulkan=native --disable-vulkan-fallback-to-gl-for-testing --enable-features=UseSkiaRenderer"', + ], + 'non_precommit_args': [ + '--upload-refimg-to-cloud-storage', + ], + 'precommit_args': [ + '--download-refimg-from-cloud-storage', + ], + }, + }, + 'gpu_swiftshader_gtests': { 'swiftshader_unittests': { },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index b1bc2cb..45f6389 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -2477,6 +2477,7 @@ ], 'test_suites': { 'gtest_tests': 'gpu_skia_renderer_vulkan_gtests', + 'gpu_telemetry_tests': 'gpu_skia_renderer_vulkan_telemetry_tests', }, }, 'Android FYI dEQP Release (Nexus 5X)': {
diff --git a/third_party/blink/public/mojom/use_counter/OWNERS b/third_party/blink/public/mojom/use_counter/OWNERS index 0dbbfa1..7f417e2 100644 --- a/third_party/blink/public/mojom/use_counter/OWNERS +++ b/third_party/blink/public/mojom/use_counter/OWNERS
@@ -1,6 +1,12 @@ -loonybear@chromium.org +dcheng@chromium.org # COMPONENT: Blink>UseCounter per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS + +# Changes in css_property_id.mojom are always just mechanical updates to +# kMaximumCSSSampleId, hence we allow all committers to review this file. +# See also UseCounterHelperTest.MaximumCSSSampleId, which verifies the +# correctness of kMaximumCSSSampleId. +per-file css_property_id.mojom=*
diff --git a/third_party/blink/renderer/bindings/scripts/generate_web_idl_collection.py b/third_party/blink/renderer/bindings/scripts/generate_web_idl_collection.py index 323d0f9c..4b31740 100644 --- a/third_party/blink/renderer/bindings/scripts/generate_web_idl_collection.py +++ b/third_party/blink/renderer/bindings/scripts/generate_web_idl_collection.py
@@ -11,6 +11,7 @@ import optparse import utilities from web_idl.collector import Collector +from web_idl.collection import Collection _VALID_COMPONENTS = ("core", "modules") @@ -42,7 +43,7 @@ parser = blink_idl_parser.BlinkIDLParser() collector = Collector(component=options.component, parser=parser) collector.collect_from_idl_files(idl_file_names) - utilities.write_pickle_file(options.output, collector.get_collection()) + Collection.write_to_file(collector.get_collection(), options.output) if __name__ == '__main__':
diff --git a/third_party/blink/renderer/bindings/scripts/scripts.gni b/third_party/blink/renderer/bindings/scripts/scripts.gni index de96ea8a..31e7e2f 100644 --- a/third_party/blink/renderer/bindings/scripts/scripts.gni +++ b/third_party/blink/renderer/bindings/scripts/scripts.gni
@@ -61,6 +61,7 @@ "web_idl/argument.py", "web_idl/attribute.py", "web_idl/callback_function.py", + "web_idl/collection.py", "web_idl/common.py", "web_idl/constant.py", "web_idl/dictionary.py",
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/collection.py b/third_party/blink/renderer/bindings/scripts/web_idl/collection.py index 751e630..2fc705d 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/collection.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/collection.py
@@ -2,6 +2,10 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import pickle +import idl_parser +from .common import Component + class Collection(object): """ @@ -10,14 +14,29 @@ """ def __init__(self, component=None): + assert component is None or isinstance(component, Component) self._asts = [] self._component = component def add_ast(self, ast): + assert isinstance(ast, idl_parser.idl_node.IDLNode) assert ast.GetClass() == 'File', ( 'Root node of an AST must be a File node., but is %s.' % ast.GetClass()) self._asts.append(ast) + @staticmethod + def load_from_file(filepath): + with open(filepath, 'r') as pickle_file: + collection = pickle.load(pickle_file) + assert isinstance(collection, Collection) + return collection + + @staticmethod + def write_to_file(collection, filepath): + assert isinstance(collection, Collection) + with open(filepath, 'w') as pickle_file: + pickle.dump(collection, pickle_file) + @property def asts(self): return self._asts
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/common.py b/third_party/blink/renderer/bindings/scripts/web_idl/common.py index 97f6da7..d17d109 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/common.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/common.py
@@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import exceptions +import copy from .extended_attribute import ExtendedAttributes from .exposure import Exposure @@ -47,7 +47,9 @@ return self._extended_attributes -CodeGeneratorInfo = dict +class CodeGeneratorInfo(dict): + def make_copy(self): + return copy.deepcopy(self) class WithCodeGeneratorInfo(object): @@ -102,9 +104,22 @@ fragments that are involved into this object. """ - def __init__(self, component): - assert isinstance(component, Component) - self._components = [component] + def __init__(self, component=None, components=None): + """ + Args: + component: + components: Either of |component| or |components| must be given. + """ + assert component is None or isinstance(component, Component) + assert components is None or (isinstance(components, (list, tuple)) + and all( + isinstance(component, Component) + for component in components)) + assert (component or components) and not (component and components) + if components: + self._components = list(components) + else: + self._components = [component] @property def components(self): @@ -114,6 +129,13 @@ """ return tuple(self._components) + def add_components(self, components): + assert isinstance(components, (list, tuple)) and all( + isinstance(component, Component) for component in components) + for component in components: + if component not in self.components: + self._components.append(component) + class DebugInfo(object): """Provides information useful for debugging.""" @@ -136,6 +158,12 @@ text += ':{}'.format(self._column_number) return text + def make_copy(self): + return DebugInfo.Location( + filepath=self._filepath, + line_number=self._line_number, + column_number=self._column_number) + @property def filepath(self): return self._filepath @@ -148,13 +176,24 @@ def column_number(self): return self._column_number - def __init__(self, location=None): + def __init__(self, location=None, locations=None): assert location is None or isinstance(location, DebugInfo.Location) - location = location or DebugInfo.Location() + assert locations is None or (isinstance( + locations, (list, tuple)) and all( + isinstance(location, DebugInfo.Location) + for location in locations)) + assert not (location and locations) # The first entry is the primary location, e.g. location of non-partial # interface. The rest is secondary locations, e.g. location of partial # interfaces and mixins. - self._locations = [location] + if locations: + self._locations = locations + else: + self._locations = [location or DebugInfo.Location()] + + def make_copy(self): + return DebugInfo( + locations=map(DebugInfo.Location.make_copy, self._locations)) @property def location(self): @@ -173,6 +212,11 @@ """ return tuple(self._locations) + def add_locations(self, locations): + assert isinstance(locations, (list, tuple)) and all( + isinstance(location, DebugInfo.Location) for location in locations) + self._locations.extend(locations) + class WithDebugInfo(object): """WithDebugInfo class is an interface that its inheritances can have
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py b/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py index ad35a13..3e871e8 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/dictionary.py
@@ -10,6 +10,7 @@ from .common import WithIdentifier from .identifier_ir_map import IdentifierIRMap from .idl_member import IdlMember +from .idl_reference_proxy import RefByIdFactory from .idl_types import IdlType from .user_defined_type import UserDefinedType from .values import DefaultValue @@ -24,12 +25,15 @@ def __init__(self, identifier, is_partial, + inherited=None, own_members=None, extended_attributes=None, code_generator_info=None, component=None, + components=None, debug_info=None): assert isinstance(is_partial, bool) + assert inherited is None or RefByIdFactory.is_reference(inherited) assert isinstance(own_members, (list, tuple)) and all( isinstance(member, DictionaryMember.IR) for member in own_members) @@ -39,11 +43,26 @@ IdentifierIRMap.IR.__init__(self, identifier=identifier, kind=kind) WithExtendedAttributes.__init__(self, extended_attributes) WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__(self, component) + WithComponent.__init__( + self, component=component, components=components) WithDebugInfo.__init__(self, debug_info) + self.is_partial = is_partial + self.inherited = inherited self.own_members = own_members + def make_copy(self): + return Dictionary.IR( + identifier=self.identifier, + is_partial=self.is_partial, + inherited=self.inherited, + own_members=map(DictionaryMember.IR.make_copy, + self.own_members), + extended_attributes=self.extended_attributes.make_copy(), + code_generator_info=self.code_generator_info.make_copy(), + components=self.components, + debug_info=self.debug_info.make_copy()) + @property def inherited_dictionary(self): """ @@ -86,6 +105,7 @@ extended_attributes=None, code_generator_info=None, component=None, + components=None, debug_info=None): assert isinstance(idl_type, IdlType) assert isinstance(is_required, bool) @@ -95,13 +115,25 @@ WithIdentifier.__init__(self, identifier) WithExtendedAttributes.__init__(self, extended_attributes) WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__(self, component) + WithComponent.__init__( + self, component=component, components=components) WithDebugInfo.__init__(self, debug_info) self.idl_type = idl_type self.is_required = is_required self.default_value = default_value + def make_copy(self): + return DictionaryMember.IR( + identifier=self.identifier, + idl_type=self.idl_type, + is_required=self.is_required, + default_value=self.default_value, + extended_attributes=self.extended_attributes.make_copy(), + code_generator_info=self.code_generator_info.make_copy(), + components=self.components, + debug_info=self.debug_info.make_copy()) + @property def idl_type(self): """
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py b/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py index 3e2b834..f7c240d 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py
@@ -73,6 +73,13 @@ # Should not reach here. assert False, 'Unknown format: {}'.format(self._format) + def make_copy(self): + return ExtendedAttribute( + key=self._key, + values=self._values, + arguments=self._arguments, + name=self._name) + @property def key(self): """ @@ -175,6 +182,9 @@ attrs = [str(attr) for attr in self] return '[{}]'.format(', '.join(attrs)) + def make_copy(self): + return ExtendedAttributes(map(ExtendedAttribute.make_copy, self)) + def get(self, key): """ Returns an exnteded attribute whose key is |key|.
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py index 898e5067..d7a5170 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from .identifier_ir_map import IdentifierIRMap + class IdlCompiler(object): """ @@ -45,9 +47,30 @@ """ Merges partial definitions with corresponding non-partial definitions. """ - self._ir_map.move_to_new_phase() + self._merge_partial_dictionaries() # TODO(peria): Implement this. http:///crbug.com/839389 + def _merge_partial_dictionaries(self): + old_dictionaries = self._ir_map.find_by_kind( + IdentifierIRMap.IR.Kind.DICTIONARY) + old_partial_dictionaries = self._ir_map.find_by_kind( + IdentifierIRMap.IR.Kind.PARTIAL_DICTIONARY) + + self._ir_map.move_to_new_phase() + + for identifier, old_dictionary in old_dictionaries.iteritems(): + new_dictionary = old_dictionary.make_copy() + for partial_dictionary in old_partial_dictionaries.get( + identifier, []): + new_dictionary.add_components(partial_dictionary.components) + new_dictionary.debug_info.add_locations( + partial_dictionary.debug_info.all_locations) + new_dictionary.own_members.extend([ + member.make_copy() + for member in partial_dictionary.own_members + ]) + self._ir_map.add(new_dictionary) + def _merge_mixins(self): """ Merges mixins with interfaces that connected with includes statements.
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py b/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py index 40beebc..c9e9bad 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py
@@ -2,17 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -try: - import _pickle as pickle -except ImportError: - try: - import cPickle as pickle - except ImportError: - import pickle - -import idl_parser from .callback_function import CallbackFunction from .callback_interface import CallbackInterface +from .collection import Collection from .common import DebugInfo from .dictionary import Dictionary from .dictionary import DictionaryMember @@ -51,18 +43,15 @@ assert callable(register_ir) for filepath in filepaths: - with open(filepath) as pickle_file: - asts_per_component = pickle.load(pickle_file) - component = asts_per_component.component - builder = _IRBuilder(component, create_ref_to_idl_type, - create_ref_to_idl_def) + asts_per_component = Collection.load_from_file(filepath) + component = asts_per_component.component + builder = _IRBuilder(component, create_ref_to_idl_type, + create_ref_to_idl_def) - for file_node in asts_per_component.asts: - assert isinstance(file_node, idl_parser.idl_node.IDLNode) - assert file_node.GetClass() == 'File' - - for top_level_node in file_node.GetChildren(): - register_ir(builder.build_top_level_def(top_level_node)) + for file_node in asts_per_component.asts: + assert file_node.GetClass() == 'File' + for top_level_node in file_node.GetChildren(): + register_ir(builder.build_top_level_def(top_level_node)) class _IRBuilder(object): @@ -79,9 +68,9 @@ assert callable(create_ref_to_idl_type) assert callable(create_ref_to_idl_def) - self.component = component - self.create_ref_to_idl_type = create_ref_to_idl_type - self.create_ref_to_idl_def = create_ref_to_idl_def + self._component = component + self._create_ref_to_idl_type = create_ref_to_idl_type + self._create_ref_to_idl_def = create_ref_to_idl_def def build_top_level_def(self, node): build_functions = { @@ -105,7 +94,7 @@ identifier=node.GetName(), is_partial=bool(node.GetProperty('PARTIAL')), is_mixin=bool(node.GetProperty('MIXIN')), - component=self.component, + component=self._component, debug_info=self._build_debug_info(node)) # TODO(peria): Build members and register them in |interface| return interface @@ -114,7 +103,7 @@ namespace = Namespace.IR( identifier=node.GetName(), is_partial=bool(node.GetProperty('PARTIAL')), - component=self.component, + component=self._component, debug_info=self._build_debug_info(node)) # TODO(peria): Build members and register them in |namespace| return namespace @@ -122,20 +111,17 @@ def _build_dictionary(self, node): child_nodes = list(node.GetChildren()) extended_attributes = self._take_extended_attributes(child_nodes) - # TODO(yukishiino): Implement dictionary inheritance. - _ = self._take_inheritance(child_nodes) - own_members = [ - self._build_dictionary_member(child) for child in child_nodes - ] + inherited = self._take_inheritance(child_nodes) + own_members = map(self._build_dictionary_member, child_nodes) - dictionary = Dictionary.IR( + return Dictionary.IR( identifier=node.GetName(), is_partial=bool(node.GetProperty('PARTIAL')), + inherited=inherited, own_members=own_members, extended_attributes=extended_attributes, - component=self.component, + component=self._component, debug_info=self._build_debug_info(node)) - return dictionary def _build_dictionary_member(self, node): assert node.GetClass() == 'Key' @@ -152,13 +138,13 @@ is_required=bool(node.GetProperty('REQUIRED')), default_value=default_value, extended_attributes=extended_attributes, - component=self.component, + component=self._component, debug_info=self._build_debug_info(node)) def _build_callback_interface(self, node): callback_interface = CallbackInterface.IR( identifier=node.GetName(), - component=self.component, + component=self._component, debug_info=self._build_debug_info(node)) # TODO(peria): Build members and register them in |callback_interface| return callback_interface @@ -166,7 +152,7 @@ def _build_callback_function(self, node): callback_function = CallbackFunction.IR( identifier=node.GetName(), - component=self.component, + component=self._component, debug_info=self._build_debug_info(node)) # TODO(peria): Build members and register them in |callback_function| return callback_function @@ -175,7 +161,7 @@ enumeration = Enumeration.IR( identifier=node.GetName(), values=[child.GetName() for child in node.GetChildren()], - component=self.component, + component=self._component, debug_info=self._build_debug_info(node)) return enumeration @@ -187,7 +173,7 @@ typedef = Typedef.IR( identifier=node.GetName(), idl_type=idl_type, - component=self.component, + component=self._component, debug_info=self._build_debug_info(node)) return typedef @@ -195,7 +181,7 @@ includes = Includes.IR( interface_identifier=node.GetName(), mixin_identifier=node.GetProperty('REFERENCE'), - component=self.component, + component=self._component, debug_info=self._build_debug_info(node)) return includes @@ -218,7 +204,7 @@ def _build_inheritance(self, node): assert node.GetClass() == 'Inherit' - return None + return self._create_ref_to_idl_def(node.GetName()) def _build_type(self, node): def build_maybe_inner_type(node): @@ -280,7 +266,7 @@ def build_reference_type(node): identifier = node.GetName() ref_type = ReferenceType( - ref_to_idl_type=self.create_ref_to_idl_type(identifier), + ref_to_idl_type=self._create_ref_to_idl_type(identifier), debug_info=self._build_debug_info(node)) return ref_type
diff --git a/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl b/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl index 8dc3c151..fd0aaf5f 100644 --- a/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl +++ b/third_party/blink/renderer/bindings/templates/interface_base.cc.tmpl
@@ -883,14 +883,14 @@ {% if attribute.is_data_type_property %} static constexpr V8DOMConfiguration::AttributeConfiguration k{{attribute.name}}Configurations[] = { - {{attribute_configuration(attribute) | trim | indent(4)}} + {{attribute_configuration(attribute) | trim | indent(6)}} }; for (const auto& config : k{{attribute.name}}Configurations) V8DOMConfiguration::InstallAttribute(isolate, world, instance, prototype, config); {% else %} static constexpr V8DOMConfiguration::AccessorConfiguration k{{attribute.name}}Configurations[] = { - {{accessor_configuration(attribute) | trim | indent(4)}} + {{accessor_configuration(attribute) | trim | indent(6)}} }; for (const auto& config : k{{attribute.name}}Configurations) { V8DOMConfiguration::InstallAccessor(isolate, world, instance, prototype, @@ -913,7 +913,7 @@ {% filter secure_context(method.secure_context_test) %} static constexpr V8DOMConfiguration::MethodConfiguration k{{method.camel_case_name}}Configurations[] = { - {{method_configuration(method) | trim | indent(4)}} + {{method_configuration(method) | trim | indent(6)}} }; for (const auto& config : k{{method.camel_case_name}}Configurations) { V8DOMConfiguration::InstallMethod(
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc index 7b72dc3..e38c6a6 100644 --- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc +++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc
@@ -13615,7 +13615,7 @@ static constexpr V8DOMConfiguration::MethodConfiguration kPerWorldBindingsOriginTrialEnabledVoidMethodConfigurations[] = { {"perWorldBindingsOriginTrialEnabledVoidMethod", V8TestObject::PerWorldBindingsOriginTrialEnabledVoidMethodMethodCallbackForMainWorld, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kMainWorld}, - {"perWorldBindingsOriginTrialEnabledVoidMethod", V8TestObject::PerWorldBindingsOriginTrialEnabledVoidMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kNonMainWorlds} + {"perWorldBindingsOriginTrialEnabledVoidMethod", V8TestObject::PerWorldBindingsOriginTrialEnabledVoidMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kNonMainWorlds} }; for (const auto& config : kPerWorldBindingsOriginTrialEnabledVoidMethodConfigurations) { V8DOMConfiguration::InstallMethod(
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect.cc b/third_party/blink/renderer/core/animation/keyframe_effect.cc index a6b9953..81fc728 100644 --- a/third_party/blink/renderer/core/animation/keyframe_effect.cc +++ b/third_party/blink/renderer/core/animation/keyframe_effect.cc
@@ -34,7 +34,6 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" #include "third_party/blink/renderer/core/animation/effect_input.h" #include "third_party/blink/renderer/core/animation/element_animations.h" -#include "third_party/blink/renderer/core/animation/keyframe_effect_options.h" #include "third_party/blink/renderer/core/animation/sampled_effect.h" #include "third_party/blink/renderer/core/animation/timing_input.h" #include "third_party/blink/renderer/core/dom/element.h"
diff --git a/third_party/blink/renderer/core/css/css_numeric_literal_value.cc b/third_party/blink/renderer/core/css/css_numeric_literal_value.cc index 24a06a03..0adefe1 100644 --- a/third_party/blink/renderer/core/css/css_numeric_literal_value.cc +++ b/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
@@ -24,6 +24,7 @@ CSSNumericLiteralValue::CSSNumericLiteralValue(double num, UnitType type) : CSSPrimitiveValue(kNumericLiteralClass), num_(num) { DCHECK(std::isfinite(num)); + DCHECK_NE(UnitType::kUnknown, type); numeric_literal_unit_type_ = static_cast<unsigned>(type); }
diff --git a/third_party/blink/renderer/core/html/html_slot_element.cc b/third_party/blink/renderer/core/html/html_slot_element.cc index 58d24cdc..0aacd6c6 100644 --- a/third_party/blink/renderer/core/html/html_slot_element.cc +++ b/third_party/blink/renderer/core/html/html_slot_element.cc
@@ -30,8 +30,6 @@ #include "third_party/blink/renderer/core/html/html_slot_element.h" -#include <array> - #include "third_party/blink/renderer/core/css/style_change_reason.h" #include "third_party/blink/renderer/core/css/style_engine.h" #include "third_party/blink/renderer/core/dom/events/event.h" @@ -399,14 +397,15 @@ const HeapVector<Member<Node>>& old_slotted, const HeapVector<Member<Node>>& new_slotted) { // Use dynamic programming to minimize the number of nodes being reattached. - using LCSTable = std::array<std::array<wtf_size_t, kLCSTableSizeLimit>, - kLCSTableSizeLimit>; + using LCSTable = + Vector<LCSArray<wtf_size_t, kLCSTableSizeLimit>, kLCSTableSizeLimit>; using Backtrack = std::pair<wtf_size_t, wtf_size_t>; using BacktrackTable = - std::array<std::array<Backtrack, kLCSTableSizeLimit>, kLCSTableSizeLimit>; + Vector<LCSArray<Backtrack, kLCSTableSizeLimit>, kLCSTableSizeLimit>; - DEFINE_STATIC_LOCAL(LCSTable*, lcs_table, (new LCSTable)); - DEFINE_STATIC_LOCAL(BacktrackTable*, backtrack_table, (new BacktrackTable)); + DEFINE_STATIC_LOCAL(LCSTable*, lcs_table, (new LCSTable(kLCSTableSizeLimit))); + DEFINE_STATIC_LOCAL(BacktrackTable*, backtrack_table, + (new BacktrackTable(kLCSTableSizeLimit))); FillLongestCommonSubsequenceDynamicProgrammingTable( old_slotted, new_slotted, *lcs_table, *backtrack_table);
diff --git a/third_party/blink/renderer/core/html/html_slot_element.h b/third_party/blink/renderer/core/html/html_slot_element.h index 38390c91..0821db4 100644 --- a/third_party/blink/renderer/core/html/html_slot_element.h +++ b/third_party/blink/renderer/core/html/html_slot_element.h
@@ -148,6 +148,14 @@ // For imperative Shadow DOM distribution APIs HeapHashSet<Member<Node>> assigned_nodes_candidates_; + template <typename T, wtf_size_t S> + struct LCSArray { + LCSArray() : values(S) {} + T& operator[](wtf_size_t i) { return values[i]; } + wtf_size_t size() { return values.size(); } + Vector<T, S> values; + }; + // TODO(hayato): Move this to more appropriate directory (e.g. platform/wtf) // if there are more than one usages. template <typename Container, typename LCSTable, typename BacktrackTable>
diff --git a/third_party/blink/renderer/core/html/html_slot_element_test.cc b/third_party/blink/renderer/core/html/html_slot_element_test.cc index a0012df..bb8898cb 100644 --- a/third_party/blink/renderer/core/html/html_slot_element_test.cc +++ b/third_party/blink/renderer/core/html/html_slot_element_test.cc
@@ -4,8 +4,6 @@ #include "third_party/blink/renderer/core/html/html_slot_element.h" -#include <array> - #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/css/style_engine.h" #include "third_party/blink/renderer/core/dom/node_computed_style.h" @@ -22,10 +20,12 @@ class HTMLSlotElementTest : public testing::Test { protected: - HTMLSlotElementTest() = default; + HTMLSlotElementTest() + : lcs_table_(kTableSize), backtrack_table_(kTableSize) {} Seq LongestCommonSubsequence(const Seq& seq1, const Seq& seq2); - std::array<std::array<size_t, kTableSize>, kTableSize> lcs_table_; - std::array<std::array<Backtrack, kTableSize>, kTableSize> backtrack_table_; + Vector<HTMLSlotElement::LCSArray<size_t, kTableSize>, kTableSize> lcs_table_; + Vector<HTMLSlotElement::LCSArray<Backtrack, kTableSize>, kTableSize> + backtrack_table_; }; Vector<char> HTMLSlotElementTest::LongestCommonSubsequence(const Seq& seq1,
diff --git a/third_party/blink/renderer/core/html/track/html_track_element.idl b/third_party/blink/renderer/core/html/track/html_track_element.idl index 79bd122..a6d3296 100644 --- a/third_party/blink/renderer/core/html/track/html_track_element.idl +++ b/third_party/blink/renderer/core/html/track/html_track_element.idl
@@ -25,8 +25,10 @@ // https://html.spec.whatwg.org/C/#the-track-element -[HTMLConstructor] -interface HTMLTrackElement : HTMLElement { +[ + Exposed=Window, + HTMLConstructor +] interface HTMLTrackElement : HTMLElement { [CEReactions] attribute DOMString kind; [CEReactions, Reflect, URL, RaisesException=Setter] attribute URLString src; [CEReactions, Reflect] attribute DOMString srclang;
diff --git a/third_party/blink/renderer/core/layout/layout_shift_region.cc b/third_party/blink/renderer/core/layout/layout_shift_region.cc index 41197bd..b43c354 100644 --- a/third_party/blink/renderer/core/layout/layout_shift_region.cc +++ b/third_party/blink/renderer/core/layout/layout_shift_region.cc
@@ -4,7 +4,6 @@ #include "third_party/blink/renderer/core/layout/layout_shift_region.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" -#include "third_party/blink/renderer/platform/wtf/text/string_hash.h" namespace blink { @@ -45,11 +44,12 @@ private: Vector<int> endpoints_; - // Avoid WTF::HashMap as key may be 0 or -1. - HashMap<int, + // Use int64_t which is larger than real |int| since the empty value of the + // key is max and deleted value of the key is max - 1 in HashMap. + HashMap<int64_t, unsigned, - WTF::AlreadyHashed, - WTF::UnsignedWithZeroKeyHashTraits<int>> + WTF::IntHash<int64_t>, + WTF::UnsignedWithZeroKeyHashTraits<int64_t>> endpoint_to_index_; #if DCHECK_IS_ON()
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/elements/toast/index.mjs b/third_party/blink/renderer/core/script/resources/layered_api/elements/toast/index.mjs index a7e0541..086a565 100644 --- a/third_party/blink/renderer/core/script/resources/layered_api/elements/toast/index.mjs +++ b/third_party/blink/renderer/core/script/resources/layered_api/elements/toast/index.mjs
@@ -51,6 +51,7 @@ static observedAttributes = ['open']; #shadow = this.attachShadow({mode: 'closed'}); #timeoutID; + #actionSlot; constructor(message) { super(); @@ -58,6 +59,10 @@ this.#shadow.adoptedStyleSheets = [generateStylesheet()]; this.#shadow.innerHTML = `<slot></slot>`; + this.#actionSlot = document.createElement('slot'); + this.#actionSlot.setAttribute('name', 'action'); + this.#shadow.appendChild(this.#actionSlot); + if (message !== undefined) { this.textContent = message; }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/SyntaxHighlighter.js b/third_party/blink/renderer/devtools/front_end/ui/SyntaxHighlighter.js index f4b4aa2..fb2ebbd 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/SyntaxHighlighter.js +++ b/third_party/blink/renderer/devtools/front_end/ui/SyntaxHighlighter.js
@@ -48,7 +48,7 @@ */ createSpan(content, className) { const span = createElement('span'); - span.className = 'cm-' + className; + span.className = className.replace(/\S+/g, 'cm-$&'); if (this._stripExtraWhitespace && className !== 'whitespace') content = content.replace(/^[\n\r]*/, '').replace(/\s*$/, ''); span.createTextChild(content);
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc index 4c596286..de0ca749 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -3035,45 +3035,6 @@ .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack); Update(artifact.Build()); - if (RuntimeEnabledFeatures::FastBorderRadiusEnabled()) { - // Expectation in effect stack diagram: - // l0 l1 - // [ e1 ] - // [ mask_isolation_0 ] - // [ e0 ] - // One content layer, one clip mask. - ASSERT_EQ(1u, RootLayer()->children().size()); - ASSERT_EQ(1u, ContentLayerCount()); - // There is still a "synthesized layer" but it's null. - ASSERT_EQ(1u, SynthesizedClipLayerCount()); - EXPECT_FALSE(SynthesizedClipLayerAt(0)); - - const cc::Layer* content0 = RootLayer()->children()[0].get(); - - constexpr int c0_id = 1; - constexpr int e0_id = 1; - - EXPECT_EQ(ContentLayerAt(0), content0); - int c1_id = content0->clip_tree_index(); - const cc::ClipNode& cc_c1 = *GetPropertyTrees().clip_tree.Node(c1_id); - EXPECT_EQ(gfx::RectF(50, 50, 300, 200), cc_c1.clip); - ASSERT_EQ(c0_id, cc_c1.parent_id); - int e1_id = content0->effect_tree_index(); - const cc::EffectNode& cc_e1 = *GetPropertyTrees().effect_tree.Node(e1_id); - EXPECT_EQ(c1_id, cc_e1.clip_id); - int mask_isolation_0_id = cc_e1.parent_id; - const cc::EffectNode& mask_isolation_0 = - *GetPropertyTrees().effect_tree.Node(mask_isolation_0_id); - ASSERT_EQ(e0_id, mask_isolation_0.parent_id); - EXPECT_EQ(c1_id, mask_isolation_0.clip_id); - EXPECT_EQ(SkBlendMode::kSrcOver, mask_isolation_0.blend_mode); - EXPECT_TRUE(mask_isolation_0.is_fast_rounded_corner); - EXPECT_EQ(gfx::RRectF(50, 50, 300, 200, 0), - mask_isolation_0.rounded_corner_bounds); - EXPECT_FALSE(mask_isolation_0.HasRenderSurface()); - return; - } - // Expectation in effect stack diagram: // l0 l1 // [ e1 ][ mask_effect_0 ]
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc index d34a180..9ae9343f 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -808,7 +808,7 @@ } bool PropertyTreeManager::SupportsShaderBasedRoundedCorner( - const FloatRoundedRect& rect, + const ClipPaintPropertyNode& clip, PropertyTreeManager::CcEffectType type) { if (!RuntimeEnabledFeatures::FastBorderRadiusEnabled()) return false; @@ -816,11 +816,14 @@ if (type & CcEffectType::kSyntheticFor2dAxisAlignment) return false; + if (clip.ClipPath()) + return false; + auto WidthAndHeightAreTheSame = [](const FloatSize& size) { return size.Width() == size.Height(); }; - const FloatRoundedRect::Radii& radii = rect.GetRadii(); + const FloatRoundedRect::Radii& radii = clip.ClipRect().GetRadii(); if (!WidthAndHeightAreTheSame(radii.TopLeft()) || !WidthAndHeightAreTheSame(radii.TopRight()) || !WidthAndHeightAreTheSame(radii.BottomRight()) || @@ -917,7 +920,7 @@ synthetic_effect.transform_id = EnsureCompositorTransformNode(transform); synthetic_effect.double_sided = !transform.IsBackfaceHidden(); if (pending_clip.type & CcEffectType::kSyntheticForNonTrivialClip) { - if (SupportsShaderBasedRoundedCorner(pending_clip.clip->ClipRect(), + if (SupportsShaderBasedRoundedCorner(*pending_clip.clip, pending_clip.type)) { synthetic_effect.rounded_corner_bounds = gfx::RRectF(pending_clip.clip->ClipRect());
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h index 23c4c34..0031fa2 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h +++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
@@ -28,7 +28,6 @@ namespace blink { class ClipPaintPropertyNode; -class FloatRoundedRect; class LayerListBuilder; class EffectPaintPropertyNode; class ScrollPaintPropertyNode; @@ -152,7 +151,7 @@ kSyntheticFor2dAxisAlignment = 1 << 1 }; - static bool SupportsShaderBasedRoundedCorner(const FloatRoundedRect& rect, + static bool SupportsShaderBasedRoundedCorner(const ClipPaintPropertyNode&, CcEffectType type); struct EffectState {
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h index 8b8727c..3facb36 100644 --- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h +++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
@@ -141,7 +141,11 @@ // If the surface is not visible within in the current view port, we should // not submit. Not submitting when off-screen saves significant memory. - bool is_surface_visible_ = false; + // + // We start as visible to avoid a white flash for on-screen content. This does + // not seem to cause a memory regression, since when off-screen it the layer + // will quickly be marked as such. + bool is_surface_visible_ = true; // Likewise, if the entire page is not visible, we should not submit. Not // submitting in the background causes the VideoFrameProvider to enter a
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.cc b/third_party/blink/renderer/platform/heap/heap_allocator.cc index e55ee53..74bdb07 100644 --- a/third_party/blink/renderer/platform/heap/heap_allocator.cc +++ b/third_party/blink/renderer/platform/heap/heap_allocator.cc
@@ -17,14 +17,16 @@ BackingModifier CanFreeOrShrinkBacking(ThreadState* const state, void* address) { // - |SweepForbidden| protects against modifying objects from destructors. + // - |IsSweepingInProgress| protects against modifying objects while + // concurrent sweeping is in progress. // - |in_atomic_pause| protects against modifying objects from within the GC. // This can // e.g. happen when hash table buckets that have containers inlined are // freed during weakness processing. // - |IsMarkingInProgress| protects against incremental marking which may have // registered callbacks. - if (state->SweepForbidden() || state->in_atomic_pause() || - state->IsMarkingInProgress()) + if (state->SweepForbidden() || state->IsSweepingInProgress() || + state->in_atomic_pause() || state->IsMarkingInProgress()) return {false, nullptr, nullptr}; // - Don't adjust large objects because their page is never reused. @@ -76,7 +78,8 @@ return false; ThreadState* state = ThreadState::Current(); - if (state->SweepForbidden()) + // Don't expand if concurrent sweeping is in progress. + if (state->SweepForbidden() || state->IsSweepingInProgress()) return false; DCHECK(!state->in_atomic_pause()); DCHECK(state->IsAllocationAllowed());
diff --git a/third_party/blink/renderer/platform/heap/heap_test.cc b/third_party/blink/renderer/platform/heap/heap_test.cc index 899666b..4ec3955 100644 --- a/third_party/blink/renderer/platform/heap/heap_test.cc +++ b/third_party/blink/renderer/platform/heap/heap_test.cc
@@ -6115,4 +6115,13 @@ MakeGarbageCollected<P>(); } +TEST(HeapTest, PersistentAssignsDeletedValue) { + // Regression test: https://crbug.com/982313 + + Persistent<IntWrapper> deleted(WTF::kHashTableDeletedValue); + Persistent<IntWrapper> pre_initialized(MakeGarbageCollected<IntWrapper>(1)); + pre_initialized = deleted; + PreciselyCollectGarbage(); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/heap/persistent.h b/third_party/blink/renderer/platform/heap/persistent.h index 826e4d54..0f119b1 100644 --- a/third_party/blink/renderer/platform/heap/persistent.h +++ b/third_party/blink/renderer/platform/heap/persistent.h
@@ -261,7 +261,7 @@ raw_ = ptr; } CheckPointer(); - if (raw_) { + if (raw_ && !IsHashTableDeletedValue()) { if (!persistent_node_.IsInitialized()) Initialize(); return; @@ -269,11 +269,11 @@ Uninitialize(); } - template <typename VisitorDispatcher> - void TracePersistent(VisitorDispatcher visitor) { + void TracePersistent(Visitor* visitor) { static_assert(sizeof(T), "T must be fully defined"); static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage collected object"); + DCHECK(!IsHashTableDeletedValue()); if (weaknessConfiguration == kWeakPersistentConfiguration) { visitor->RegisterWeakCallback(this, HandleWeakPersistent); } else {
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint index cce019a..e2ea9f7a 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint +++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
@@ -467,8 +467,7 @@ Bug(none) fast/multicol/composited-layer-will-change.html [ Crash ] # Clip-path and mask. -crbug.com/979369 compositing/images/direct-image-clip-path.html [ Failure ] -crbug.com/979369 compositing/images/direct-image-dynamic-clip-path.html [ Failure ] +crbug.com/979369 compositing/geometry/child-layer-position-with-clip-path-overflow.html [ Failure ] crbug.com/979369 compositing/overflow/accelerated-scrolling-with-clip-path.html [ Failure ] crbug.com/979369 compositing/overflow/ancestor-with-clip-path.html [ Failure ] crbug.com/979369 compositing/overflow/descendant-with-clip-path.html [ Failure ] @@ -483,9 +482,7 @@ crbug.com/979369 external/wpt/css/css-masking/mask-svg-content/mask-type-002.svg [ Failure ] crbug.com/979369 external/wpt/css/css-masking/mask-svg-content/mask-type-003.svg [ Failure ] crbug.com/979369 paint/clipath/change-mask-clip-path-multicol-crash.html [ Crash ] -crbug.com/979369 paint/clipath/clip-path-with-background-and-box-behind.html [ Failure ] crbug.com/979369 paint/invalidation/clip/clip-path-constant-repaint.html [ Failure ] -crbug.com/979369 paint/invalidation/clip/clip-path-in-mask-layer.html [ Failure ] crbug.com/979369 svg/W3C-SVG-1.1/masking-intro-01-f.svg [ Failure ] crbug.com/979369 svg/clip-path/clip-in-mask.svg [ Failure ] crbug.com/979369 svg/clip-path/deep-nested-clip-in-mask-different-unitTypes.svg [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index dd6c63a..e27a5236 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -6260,6 +6260,7 @@ crbug.com/982289 virtual/gpu-rasterization/images/color-profile-image-canvas.html [ Pass Failure ] crbug.com/982289 virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Pass Failure ] crbug.com/982289 virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile.html [ Pass Failure ] +crbug.com/982289 virtual/gpu-rasterization/images/color-profile-image.html [ Pass Failure ] # Sheriff 2019-07-09 crbug.com/966249 [ Mac ] external/wpt/css/css-fonts/inheritance.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers.html similarity index 86% rename from third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers-manual.html rename to third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers.html index e7471451..97e0db1 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers-manual.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers.html
@@ -6,6 +6,9 @@ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> <!-- Additional helper script for common checks across event types --> <script type="text/javascript" src="pointerevent_support.js"></script> <script> @@ -95,6 +98,7 @@ var innerFrame = document.getElementById('innerFrame'); var square2 = innerFrame.contentDocument.getElementById('square2'); var rectSquare2 = square2.getBoundingClientRect(); + var actions_promise; eventList.forEach(function(eventName) { on_event(square1, eventName, function (event) { @@ -112,10 +116,32 @@ checkPointerEventAttributes(event, rectSquare2, "Inner frame "); if (Object.keys(detected_eventTypes).length == eventList.length) { square2.style.visibility = 'hidden'; - test_pointerEvent.done(); + // Make sure the test finishes after all the input actions are completed. + actions_promise.then( () => { + test_pointerEvent.done(); + }); } }); }); + + // Inject mouse and pen inputs. + actions_promise = clickInTarget("mouse", square1).then(function() { + return moveToDocument("mouse"); + }).then(function() { + return clickInTarget("mouse", square2); + }).then(function() { + return moveToDocument("mouse"); + }).then(function() { + test_pointerEvent.done(); + }).then(function() { + return clickInTarget("pen", square1); + }).then(function() { + return moveToDocument("pen"); + }).then(function() { + return clickInTarget("pen", square2); + }).then(function() { + return moveToDocument("pen"); + }); } </script> </head>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_nohover_pointers-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_nohover_pointers.html similarity index 90% rename from third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_nohover_pointers-manual.html rename to third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_nohover_pointers.html index 0fd7904..e0073de 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_nohover_pointers-manual.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_attributes_nohover_pointers.html
@@ -6,6 +6,9 @@ <link rel="stylesheet" type="text/css" href="pointerevent_styles.css"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-actions.js"></script> + <script src="/resources/testdriver-vendor.js"></script> <!-- Additional helper script for common checks across event types --> <script type="text/javascript" src="pointerevent_support.js"></script> <script> @@ -76,6 +79,7 @@ var innerFrame = document.getElementById('innerFrame'); var square2 = innerFrame.contentDocument.getElementById('square2'); var rectSquare2 = square2.getBoundingClientRect(); + var actions_promise; eventList.forEach(function(eventName) { on_event(square1, eventName, function (event) { @@ -93,10 +97,18 @@ checkPointerEventAttributes(event, rectSquare2, "Inner frame "); if (Object.keys(detected_eventTypes).length == eventList.length) { square2.style.visibility = 'hidden'; - test_pointerEvent.done(); + // Make sure the test finishes after all the input actions are completed. + actions_promise.then( () => { + test_pointerEvent.done(); + }); } }); }); + + // Inject touch inputs. + actions_promise = clickInTarget("touch", square1).then(function() { + return clickInTarget("touch", square2); + }); } </script> </head>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js index ae9b55c..3b37f48 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_support.js
@@ -353,3 +353,11 @@ .pointerMove(3 * x_delta, 3 * y_delta, {origin: target}) .send(); } + +function moveToDocument(pointerType) { + var pointerId = pointerType + "Pointer1"; + return new test_driver.Actions() + .addPointer(pointerId, pointerType) + .pointerMove(0, 0) + .send(); +}
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLVideoElement-invalid-state.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLVideoElement-invalid-state.html new file mode 100644 index 0000000..dcf9e3a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLVideoElement-invalid-state.html
@@ -0,0 +1,70 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +const videoElementTests = + [ + { + createDetector: () => { return new FaceDetector(); }, + name: "Face - detect(HTMLVideoElement)", + }, + { + createDetector: () => { return new BarcodeDetector(); }, + name: "Barcode - detect(HTMLVideoElement)", + } + ]; + +for (let videoElementTest of videoElementTests) { + + // Detector's detect() rejects on a HAVE_NOTHING HTMLVideoElement. + promise_test(async t => { + const video = document.createElement("video"); + video.src = ""; + const videoWatcher = new EventWatcher(t, video, ["play", "error"]); + video.load(); + await videoWatcher.wait_for("error"); + assert_equals(video.readyState, video.HAVE_NOTHING); + + const detector = videoElementTest.createDetector(); + await promise_rejects(t, 'InvalidStateError', detector.detect(video)); + }, `${videoElementTest.name} - HAVE_NOTHING`); + + // Detector's detect() rejects on a HAVE_METADATA HTMLVideoElement. + promise_test(async t => { + const url = '/media/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm'; + const type = 'video/webm; codecs="vp8, vorbis"'; + const video = document.createElement("video"); + document.body.appendChild(video); + t.add_cleanup(() => { document.body.removeChild(video); }); + + // Attach MediaSource to the video element. + const mediaSource = new MediaSource(); + const mediaSourceURL = URL.createObjectURL(mediaSource); + const mediaSourceWatcher = + new EventWatcher(t, mediaSource, ["sourceopen", "error"]); + video.src = mediaSourceURL; + await mediaSourceWatcher.wait_for("sourceopen"); + const sourceBuffer = mediaSource.addSourceBuffer(type); + + // Load media data from the video file to create an initialization segment. + const response = await fetch(url); + const mediaData = await response.arrayBuffer(); + const initSegment = new Uint8Array(mediaData, 0, 4052); + + // Append the initialization segment to trigger a transition + // to HAVE_METADATA. + const videoWatcher = + new EventWatcher(t, video, ["loadedmetadata", "error"]); + sourceBuffer.appendBuffer(initSegment); + + await videoWatcher.wait_for("loadedmetadata"); + assert_equals(video.readyState, video.HAVE_METADATA); + + const detector = videoElementTest.createDetector(); + await promise_rejects(t, 'InvalidStateError', detector.detect(video)); + }, `${videoElementTest.name} - HAVE_METADATA`); + +} + +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.html b/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.html index c9d86430..f4536926 100644 --- a/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.html +++ b/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.html
@@ -30,9 +30,9 @@ img.src = IMAGE_URL; await imgWatcher.wait_for("load"); const detector = crossOriginTest.createDetector(); - promise_rejects(t, "SecurityError", detector.detect(img)); - }, crossOriginTest.detectorType - + " should reject cross-origin HTMLImageElements with a SecurityError."); + await promise_rejects(t, "SecurityError", detector.detect(img)); + }, `${crossOriginTest.detectorType} should reject cross-origin \ +HTMLImageElements with a SecurityError.`); // Verifies that Detector rejects a cross-origin ImageBitmap. promise_test(async t => { @@ -42,9 +42,9 @@ await imgWatcher.wait_for("load"); const imgBitmap = await createImageBitmap(img); const detector = crossOriginTest.createDetector(); - promise_rejects(t, "SecurityError", detector.detect(imgBitmap)); - }, crossOriginTest.detectorType - + " should reject cross-origin ImageBitmaps with a SecurityError."); + await promise_rejects(t, "SecurityError", detector.detect(imgBitmap)); + }, `${crossOriginTest.detectorType} should reject cross-origin \ +ImageBitmaps with a SecurityError.`); // Verifies that Detector rejects a cross-origin HTMLVideoElement. promise_test(async t => { @@ -53,9 +53,22 @@ video.src = VIDEO_URL; await videoWatcher.wait_for("loadeddata"); const detector = crossOriginTest.createDetector(); - promise_rejects(t, "SecurityError", detector.detect(video)); - }, crossOriginTest.detectorType - + " should reject cross-origin HTMLVideoElements with a SecurityError."); + await promise_rejects(t, "SecurityError", detector.detect(video)); + }, `${crossOriginTest.detectorType} should reject cross-origin \ +HTMLVideoElements with a SecurityError.`); + + // Verifies that Detector rejects a cross-origin HTMLCanvasElement. + promise_test(async t => { + const img = new Image(); + const imgWatcher = new EventWatcher(t, img, ["load", "error"]); + img.src = IMAGE_URL; + await imgWatcher.wait_for("load"); + const canvas = document.createElement("canvas"); + canvas.getContext("2d").drawImage(img, 0, 0); + const detector = crossOriginTest.createDetector(); + await promise_rejects(t, "SecurityError", detector.detect(canvas)); + }, `${crossOriginTest.detectorType} should reject cross-origin \ +HTMLCanvasElement with a SecurityError.`); }
diff --git a/third_party/blink/web_tests/external/wpt/std-toast/ref-tests/toast-slotting-expected.html b/third_party/blink/web_tests/external/wpt/std-toast/ref-tests/toast-slotting-expected.html new file mode 100644 index 0000000..b4b365c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/std-toast/ref-tests/toast-slotting-expected.html
@@ -0,0 +1,8 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Toast: slotting test reference</title> +<script type="module"> +import 'std:elements/toast'; +</script> +<p>Pass if the toast is displayed with the action button last.</p> +<std-toast open>First. Second. <button>Last.</button></std-toast>
diff --git a/third_party/blink/web_tests/external/wpt/std-toast/ref-tests/toast-slotting.html b/third_party/blink/web_tests/external/wpt/std-toast/ref-tests/toast-slotting.html new file mode 100644 index 0000000..4d6f5038 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/std-toast/ref-tests/toast-slotting.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Toast: slotting test</title> +<link rel="help" href="https://github.com/jackbsteinberg/std-toast"> +<meta name="assert" content="Toast slots action button behind any text"> +<link rel="match" href="toast-slotting-expected.html"> +<script type="module"> +import 'std:elements/toast'; +</script> +<p>Pass if the toast is displayed with the action button last.</p> +<std-toast open>First. <button slot="action">Last.</button> Second. </std-toast> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/std-toast/resources/helpers.js b/third_party/blink/web_tests/external/wpt/std-toast/resources/helpers.js index 41b7672..e1b55f4 100644 --- a/third_party/blink/web_tests/external/wpt/std-toast/resources/helpers.js +++ b/third_party/blink/web_tests/external/wpt/std-toast/resources/helpers.js
@@ -2,10 +2,10 @@ // helper functions to keep tests from bleeding into each other -const runTest = (testFn, name, toast) => { +const runTest = (testFn, name, toast, action) => { try { test(() => { - testFn(toast); + testFn(toast, action); }, name); } finally { toast.remove(); @@ -41,6 +41,17 @@ runTest(testFn, name, toast); }; +export const testActionToast = (testFn, name) => { + const toast = new StdToastElement('Message', {}); + const action = document.createElement('button'); + action.setAttribute('slot', 'action'); + action.textContent = 'action'; + toast.appendChild(action); + document.querySelector('main').appendChild(toast); + + runTest(testFn, name, toast, action); +}; + export const assertToastShown = (toast) => { assert_not_equals(window.getComputedStyle(toast).display, 'none'); assert_true(toast.hasAttribute('open'));
diff --git a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_attributes_hoverable_pointers-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_attributes_hoverable_pointers-manual-automation.js deleted file mode 100644 index f2f8295..0000000 --- a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_attributes_hoverable_pointers-manual-automation.js +++ /dev/null
@@ -1,15 +0,0 @@ -importAutomationScript('/pointerevents/pointerevent_common_input.js'); - -function inject_input() { - return mouseClickInTarget('#square1').then(function() { - return mouseClickInTarget('#square2', document.querySelector('#innerFrame')); - }).then(function() { - return mouseMoveToDocument(); - }).then(function() { - return penClickInTarget('#square1'); - }).then(function() { - return penClickInTarget('#square2', document.querySelector('#innerFrame')); - }).then(function() { - return penMoveToDocument(); - }); -}
diff --git a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_attributes_nohover_pointers-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_attributes_nohover_pointers-manual-automation.js deleted file mode 100644 index d9ef3f3..0000000 --- a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_attributes_nohover_pointers-manual-automation.js +++ /dev/null
@@ -1,7 +0,0 @@ -importAutomationScript('/pointerevents/pointerevent_common_input.js'); - -function inject_input() { - return touchTapInTarget('#square1').then(function() { - return touchTapInTarget('#square2', document.querySelector('#innerFrame')); - }); -}
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt new file mode 100644 index 0000000..61ba22d --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt
@@ -0,0 +1,35 @@ +{ + "layers": [ + { + "name": "Scrolling background of LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF" + }, + { + "name": "LayoutNGBlockFlow DIV", + "bounds": [200, 200], + "backgroundColor": "#0000FF", + "paintInvalidations": [ + { + "object": "LayoutNGBlockFlow DIV", + "rect": [0, 0, 200, 200], + "reason": "full" + } + ], + "transform": 1 + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [8, 8, 0, 1] + ] + } + ] +} +
diff --git a/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-html-expected.txt b/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-html-expected.txt index b24992d..7948df21 100644 --- a/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-html-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-html-expected.txt
@@ -1,11 +1,11 @@ Tests that SourceHTMLTokenizer detects the tokens. -<html>: cm-xml-tag xml-bracket, cm-xml-tag, cm-xml-tag xml-bracket -<table cellspacing=0>: cm-xml-tag xml-bracket, cm-xml-tag, *, cm-xml-attribute, *, cm-xml-string, cm-xml-tag xml-bracket -<input checked value="foo">: cm-xml-tag xml-bracket, cm-xml-tag, *, cm-xml-attribute, *, cm-xml-attribute, *, cm-xml-string, cm-xml-tag xml-bracket -<table cellspacing="0" cellpadding='0'>: cm-xml-tag xml-bracket, cm-xml-tag, *, cm-xml-attribute, *, cm-xml-string, *, cm-xml-attribute, *, cm-xml-string, cm-xml-tag xml-bracket +<html>: cm-xml-tag cm-xml-bracket, cm-xml-tag, cm-xml-tag cm-xml-bracket +<table cellspacing=0>: cm-xml-tag cm-xml-bracket, cm-xml-tag, *, cm-xml-attribute, *, cm-xml-string, cm-xml-tag cm-xml-bracket +<input checked value="foo">: cm-xml-tag cm-xml-bracket, cm-xml-tag, *, cm-xml-attribute, *, cm-xml-attribute, *, cm-xml-string, cm-xml-tag cm-xml-bracket +<table cellspacing="0" cellpadding='0'>: cm-xml-tag cm-xml-bracket, cm-xml-tag, *, cm-xml-attribute, *, cm-xml-string, *, cm-xml-attribute, *, cm-xml-string, cm-xml-tag cm-xml-bracket <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">: cm-xml-meta <!--div><div foobar-->: cm-xml-comment -<script></script><!--div-->: cm-xml-tag xml-bracket, cm-xml-tag, cm-xml-tag xml-bracket, cm-xml-tag xml-bracket, cm-xml-tag, cm-xml-tag xml-bracket, cm-xml-comment -<script type="text/javascript">document.write('<script type="text/javascript"></' + 'script>');</script>: cm-xml-tag xml-bracket, cm-xml-tag, *, cm-xml-attribute, *, cm-xml-string, cm-xml-tag xml-bracket, cm-js-variable, *, cm-js-property, *, cm-js-string, *, cm-js-operator, *, cm-js-string, *, cm-xml-tag xml-bracket, cm-xml-tag, cm-xml-tag xml-bracket +<script></script><!--div-->: cm-xml-tag cm-xml-bracket, cm-xml-tag, cm-xml-tag cm-xml-bracket, cm-xml-tag cm-xml-bracket, cm-xml-tag, cm-xml-tag cm-xml-bracket, cm-xml-comment +<script type="text/javascript">document.write('<script type="text/javascript"></' + 'script>');</script>: cm-xml-tag cm-xml-bracket, cm-xml-tag, *, cm-xml-attribute, *, cm-xml-string, cm-xml-tag cm-xml-bracket, cm-js-variable, *, cm-js-property, *, cm-js-string, *, cm-js-operator, *, cm-js-string, *, cm-xml-tag cm-xml-bracket, cm-xml-tag, cm-xml-tag cm-xml-bracket
diff --git a/third_party/blink/web_tests/http/tests/shapedetection/detection-HTMLVideoElement-invalid-state.html b/third_party/blink/web_tests/http/tests/shapedetection/detection-HTMLVideoElement-invalid-state.html new file mode 100644 index 0000000..e245ff5 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/shapedetection/detection-HTMLVideoElement-invalid-state.html
@@ -0,0 +1,54 @@ +<!DOCTYPE html> +<script src="../../../../resources/testharness.js"></script> +<script src="../../../../resources/testharnessreport.js"></script> +<script> + +// Detector's detect() rejects on a HAVE_NOTHING HTMLVideoElement. +promise_test(async t => { + const video = document.createElement("video"); + video.src = ""; + const videoWatcher = new EventWatcher(t, video, ["play", "error"]); + video.load(); + await videoWatcher.wait_for("error"); + assert_equals(video.readyState, video.HAVE_NOTHING); + const detector = new TextDetector(); + await promise_rejects(t, 'InvalidStateError', detector.detect(video)); +}, "Text - detect(HTMLVideoElement) - HAVE_NOTHING"); + +// Detector's detect() rejects on a HAVE_METADATA HTMLVideoElement. +promise_test(async t => { + const url = "/media/resources/media-source/webm/" + + "test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm"; + const type = 'video/webm; codecs="vp8, vorbis"'; + const video = document.createElement("video"); + document.body.appendChild(video); + t.add_cleanup(() => { document.body.removeChild(video); }); + + // Attach MediaSource to the video element. + const mediaSource = new MediaSource(); + const mediaSourceURL = URL.createObjectURL(mediaSource); + const mediaSourceWatcher = + new EventWatcher(t, mediaSource, ["sourceopen", "error"]); + video.src = mediaSourceURL; + await mediaSourceWatcher.wait_for("sourceopen"); + const sourceBuffer = mediaSource.addSourceBuffer(type); + + // Load media data from the video file to create an initialization segment. + const response = await fetch(url); + const mediaData = await response.arrayBuffer(); + const initSegment = new Uint8Array(mediaData, 0, 4052); + + // Append the initialization segment to trigger a transition + // to HAVE_METADATA. + const videoWatcher = + new EventWatcher(t, video, ["loadedmetadata", "error"]); + sourceBuffer.appendBuffer(initSegment); + + await videoWatcher.wait_for("loadedmetadata"); + assert_equals(video.readyState, video.HAVE_METADATA); + + const detector = new TextDetector(); + await promise_rejects(t, 'InvalidStateError', detector.detect(video)); +}, "Text - detect(HTMLVideoElement) - HAVE_METADATA"); + +</script>
diff --git a/third_party/blink/web_tests/http/tests/shapedetection/shapedetection-cross-origin.html b/third_party/blink/web_tests/http/tests/shapedetection/shapedetection-cross-origin.html index 16956f79..593b06d1 100644 --- a/third_party/blink/web_tests/http/tests/shapedetection/shapedetection-cross-origin.html +++ b/third_party/blink/web_tests/http/tests/shapedetection/shapedetection-cross-origin.html
@@ -7,74 +7,51 @@ const IMAGE_URL = "http://localhost:8080/security/resources/abe.png"; const VIDEO_URL = "http://localhost:8080/external/wpt/media/white.webm"; -// Returns a Promise that is resolve()d if detect() is rejected. Needs an input -// |element| (e.g. an HTMLImageElement or HTMLVideoElement) and a |url| to load. -function detectTextOnElementAndExpectError(element, url) { - return new Promise(function(resolve, reject) { - var tryTextDetection = function() { - var textDetector = new TextDetector(); - textDetector.detect(element) - .then(textDetectionResult => { - reject("Promise should have been rejected."); - }) - .catch(error => { - resolve(error); - }); - }; - element.onload = tryTextDetection; - element.onerror = tryTextDetection; - element.src = url; - }); -} - -function detectTextOnImageBitmapAndExpectError(imageUrl) { - return new Promise(function(resolve, reject) { - var image = new Image(); - image.onload = function() { - createImageBitmap(image) - .then(imageBitmap => { - var textDetector = new TextDetector(); - return textDetector.detect(imageBitmap); - }) - .then(textDetectionResult => { - reject("Promise should have been rejected."); - }) - .catch(error => { - resolve(error); - }); - }; - image.onerror = () => {}; // Explicitly ignore expected error events. - image.src = imageUrl; - }); -} - // Verifies that TextDetector rejects a cross-origin HTMLImageElement. -promise_test(function(t) { - var image = new Image(); - return detectTextOnElementAndExpectError(image, IMAGE_URL) - .then(error => { - assert_equals(error.name, "SecurityError"); - }); +promise_test(async t => { + const img = new Image(); + const imgWatcher = new EventWatcher(t, img, ["load", "error"]); + img.src = IMAGE_URL; + await imgWatcher.wait_for("load"); + const detector = new TextDetector(); + await promise_rejects(t, "SecurityError", detector.detect(img)); }, "TextDetector should reject cross-origin HTMLImageElements with a SecurityError."); // Verifies that TextDetector rejects a cross-origin ImageBitmap. -promise_test(function(t) { - return detectTextOnImageBitmapAndExpectError(IMAGE_URL) - .then(error => { - assert_equals(error.name, "SecurityError"); - }); +promise_test(async t => { + const img = new Image(); + const imgWatcher = new EventWatcher(t, img, ["load", "error"]); + img.src = IMAGE_URL; + await imgWatcher.wait_for("load"); + const imgBitmap = await createImageBitmap(img); + const detector = new TextDetector(); + await promise_rejects(t, "SecurityError", detector.detect(imgBitmap)); }, "TextDetector should reject cross-origin ImageBitmaps with a SecurityError."); // Verifies that TextDetector rejects a cross-origin HTMLVideoElement. -promise_test(function(t) { - var video = document.createElement('video'); - return detectTextOnElementAndExpectError(video, VIDEO_URL) - .then(error => { - assert_equals(error.name, "SecurityError"); - }); +promise_test(async t => { + const video = document.createElement('video'); + const videoWatcher = new EventWatcher(t, video, ["load", "error"]); + video.src = VIDEO_URL; + await videoWatcher.wait_for("error"); + const detector = new TextDetector(); + await promise_rejects(t, "SecurityError", detector.detect(video)); }, "TextDetector should reject cross-origin HTMLVideoElements with a SecurityError."); +// Verifies that TextDetector rejects a cross-origin HTMLCanvasElement. +promise_test(async t => { + const img = new Image(); + const imgWatcher = new EventWatcher(t, img, ["load", "error"]); + img.src = IMAGE_URL; + await imgWatcher.wait_for("load"); + const canvas = document.createElement("canvas"); + canvas.getContext("2d").drawImage(img, 0, 0); + const detector = new TextDetector(); + await promise_rejects(t, "SecurityError", detector.detect(canvas)); +}, +"TextDetector should reject cross-origin HTMLCanvasElements with a SecurityError."); + </script>
diff --git a/third_party/blink/web_tests/resources/testdriver-vendor.js b/third_party/blink/web_tests/resources/testdriver-vendor.js index 17b89e22..0250c168 100644 --- a/third_party/blink/web_tests/resources/testdriver-vendor.js +++ b/third_party/blink/web_tests/resources/testdriver-vendor.js
@@ -17,31 +17,47 @@ return [x, y]; } - function getPointerInteractablePaintTree(element) { - if (!window.document.contains(element)) { + function getPointerInteractablePaintTree(element, frame) { + var frameDocument = frame == window ? window.document : frame.contentDocument; + if (!frameDocument.contains(element)) { return []; } var rectangles = element.getClientRects(); - if (rectangles.length === 0) { return []; } var centerPoint = getInViewCenterPoint(rectangles[0]); if ("elementsFromPoint" in document) { - return document.elementsFromPoint(centerPoint[0], centerPoint[1]); + return frameDocument.elementsFromPoint(centerPoint[0], centerPoint[1]); } else if ("msElementsFromPoint" in document) { - var rv = document.msElementsFromPoint(centerPoint[0], centerPoint[1]); + var rv = frameDocument.msElementsFromPoint(centerPoint[0], centerPoint[1]); return Array.prototype.slice.call(rv ? rv : []); } else { throw new Error("document.elementsFromPoint unsupported"); } } - function inView(element) { - var pointerInteractablePaintTree = getPointerInteractablePaintTree(element); - return pointerInteractablePaintTree.indexOf(element) !== -1 || element.contains(pointerInteractablePaintTree[0]); + function inView(element, frame) { + var pointerInteractablePaintTree = getPointerInteractablePaintTree(element, frame); + return pointerInteractablePaintTree.indexOf(element) !== -1 || element.contains(pointerInteractablePaintTree[0], frame); + } + + function findElementInFrame(element, frame) { + var foundFrame = frame; + var frameDocument = frame == window ? window.document : frame.contentDocument; + if (!frameDocument.contains(element)) { + foundFrame = null; + var frames = document.getElementsByTagName("iframe"); + for (let i = 0; i < frames.length; i++) { + if (findElementInFrame(element, frames[i])) { + foundFrame = frames[i]; + break; + } + } + } + return foundFrame; } window.test_driver_internal.click = function(element, coords) { @@ -122,12 +138,13 @@ return Promise.reject(new Error("pointer origin is not given correctly")); } } else { - let element = actions[i].actions[j].origin; - if (!window.document.contains(element)) { - return Promise.reject(new Error("element in different document or shadow tree")); + var element = actions[i].actions[j].origin; + var frame = findElementInFrame(element, window); + if (frame == null) { + return Promise.reject(new Error("element in different document or iframe")); } - if (!inView(element)) { + if (!inView(element, frame)) { if (didScrollIntoView) return Promise.reject(new Error("already scrolled into view, the element is not found")); @@ -137,7 +154,7 @@ didScrollIntoView = true; } - var pointerInteractablePaintTree = getPointerInteractablePaintTree(element); + var pointerInteractablePaintTree = getPointerInteractablePaintTree(element, frame); if (pointerInteractablePaintTree.length === 0 || !element.contains(pointerInteractablePaintTree[0])) { return Promise.reject(new Error("element click intercepted error")); @@ -147,6 +164,11 @@ var centerPoint = getInViewCenterPoint(rect); last_x_position = actions[i].actions[j].x + centerPoint[0]; last_y_position = actions[i].actions[j].y + centerPoint[1]; + if (frame != window) { + var frameRect = frame.getClientRects(); + last_x_position += frameRect[0].left; + last_y_position += frameRect[0].top; + } } }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 6c660d4..9d85e7d 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -4810,6 +4810,7 @@ <int value="215" label="RFHI_BEGIN_NAVIGATION_NON_WEBBY_TRANSITION"/> <int value="216" label="RFH_NO_MATCHING_NAVIGATION_REQUEST_ON_COMMIT"/> <int value="217" label="AUTH_INVALID_ICON_URL"/> + <int value="218" label="REGISTER_PROTOCOL_HANDLER_INVALID_URL"/> </enum> <enum name="BadMessageReasonExtensions"> @@ -33558,6 +33559,7 @@ <int value="-2075807193" label="enable-webusb-on-any-origin"/> <int value="-2075725205" label="disable-new-zip-unpacker"/> <int value="-2074080173" label="NightLight:disabled"/> + <int value="-2073617042" label="CrostiniWebUIInstaller:enabled"/> <int value="-2067166422" label="enable-slimming-paint-v2"/> <int value="-2066541315" label="Mus:enabled"/> <int value="-2064164557" label="DownloadsForeground:disabled"/> @@ -35818,6 +35820,7 @@ <int value="1173244409" label="AutofillUseMobileLabelDisambiguation:enabled"/> <int value="1174088940" label="enable-wasm"/> <int value="1177120582" label="InstallableInkDrop:disabled"/> + <int value="1178215520" label="CrostiniWebUIInstaller:disabled"/> <int value="1179013979" label="OmniboxUIExperimentMaxAutocompleteMatches:enabled"/> <int value="1179936481" label="enable-android-pay-integration-v1"/> @@ -56554,6 +56557,7 @@ <int value="42" label="Send Tab"/> <int value="43" label="Security Events"/> <int value="44" label="Wi-Fi Configurations"/> + <int value="45" label="Web Apps"/> </enum> <enum name="SyncModelTypeStoreInitResult">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index d745689..974a0c9 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -46148,7 +46148,10 @@ <histogram name="GPU.DirectComposition.DisableLargerThanScreenOverlaysWorkaround" - enum="BooleanActive" expires_after="2019-7-31"> + enum="BooleanActive" expires_after="2019-07-09"> + <obsolete> + No longer needed. Data has been collected. + </obsolete> <owner>magchen@chromium.org</owner> <owner>zmo@chromium.org</owner> <summary> @@ -110474,6 +110477,18 @@ </summary> </histogram> +<histogram name="ResourceScheduler.PeakObservedQueueingDelay" units="ms" + expires_after="M80"> + <owner>jfwang@google.com</owner> + <owner>tbansal@chromium.org</owner> + <summary> + Within a request's lifetime, the peak observed queueing delay tells whether + the request was affected by the network congestion. Records the maximum + network queueing delay when the given request was in-flight. This is emitted + when the request is completed. + </summary> +</histogram> + <histogram name="ResourceScheduler.RequestQueuingDuration" units="ms"> <owner>tbansal@chromium.org</owner> <summary> @@ -122756,7 +122771,7 @@ </histogram> <histogram name="SignedExchange.ValidityPingDuration" units="ms" - expires_after="M77"> + expires_after="M82"> <owner>kinuko@chromium.org</owner> <owner>kouhei@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> @@ -122768,7 +122783,7 @@ </histogram> <histogram name="SignedExchange.ValidityPingResult" - enum="SignedExchangeValidityPingResult" expires_after="M77"> + enum="SignedExchangeValidityPingResult" expires_after="M82"> <owner>kinuko@chromium.org</owner> <owner>kouhei@chromium.org</owner> <owner>ksakamoto@chromium.org</owner> @@ -165009,6 +165024,7 @@ <suffix name="USER_CONSENT" label="USER_CONSENT"/> <suffix name="USER_EVENT" label="USER_EVENT"/> <suffix name="WALLET_METADATA" label="WALLET_METADATA"/> + <suffix name="WEB_APP" label="WEB_APP"/> <suffix name="WIFI_CONFIGURATION" label="WIFI_CONFIGURATION"/> <suffix name="WIFI_CREDENTIAL" label="WIFI_CREDENTIAL"/> <affected-histogram name="FCMInvalidations.SubscriptionResponseCodeForTopic"/>
diff --git a/tools/perf/chrome_telemetry_build/BUILD.gn b/tools/perf/chrome_telemetry_build/BUILD.gn index 55970a2..ff9df95 100644 --- a/tools/perf/chrome_telemetry_build/BUILD.gn +++ b/tools/perf/chrome_telemetry_build/BUILD.gn
@@ -95,7 +95,16 @@ "//third_party/catapult:telemetry_chrome_test_support", ] if (is_android) { - data += [ "//build/android/stacktrace/" ] + data += [ + "//build/android/stacktrace/", + "//build/android/tombstones.py", + + # TODO(httpss://crbug.com/833808): Remove this once bots always set + # CHROMIUM_OUTPUT_DIR correctly. Currently, this is necessary in order + # for //build/android/pylib/constants/__init__.py to detect the output + # directory, which tombstones.py depends on. + "$root_out_dir/build.ninja", + ] data_deps += [ "//chrome/android/webapk/shell_apk:maps_go_webapk", "//build/android:devil_chromium_py",
diff --git a/tools/perf/core/minidump_unittest.py b/tools/perf/core/minidump_unittest.py index 2ad6cf4..47870df1 100644 --- a/tools/perf/core/minidump_unittest.py +++ b/tools/perf/core/minidump_unittest.py
@@ -13,14 +13,16 @@ class BrowserMinidumpTest(tab_test_case.TabTestCase): @decorators.Isolated - # Disabled tests due to flakiness: http://crbug.com/641469 - @decorators.Disabled('all') + # ChromeOS and Android are currently hard coded to return None for minidump + # paths, so disable on those platforms. Windows 7 doesn't find any minidump + # paths for some reason. + @decorators.Disabled('chromeos', 'android', 'win7') def testSymbolizeMinidump(self): # Wait for the browser to restart fully before crashing self._LoadPageThenWait('var sam = "car";', 'sam') self._browser.tabs.New().Navigate('chrome://gpucrash', timeout=5) crash_minidump_path = self._browser.GetMostRecentMinidumpPath() - #self.assertIsNotNone(crash_minidump_path) + self.assertIsNotNone(crash_minidump_path) if crash_minidump_path is not None: logging.info('testSymbolizeMinidump: most recent path = ' @@ -32,7 +34,7 @@ if all_unsymbolized_paths is not None: logging.info('testSymbolizeMinidump: all unsymbolized paths ' + ''.join(all_unsymbolized_paths)) - #self.assertTrue(len(all_unsymbolized_paths) == 1) + self.assertTrue(len(all_unsymbolized_paths) == 1) # Now symbolize that minidump and make sure there are no longer any present self._browser.SymbolizeMinidump(crash_minidump_path) @@ -43,19 +45,57 @@ logging.info('testSymbolizeMinidump: after symbolize all ' + 'unsymbolized paths: ' + ''.join(all_unsymbolized_after_symbolize_paths)) - #self.assertTrue(len(all_unsymbolized_after_symbolize_paths) == 0) - + self.assertTrue(len(all_unsymbolized_after_symbolize_paths) == 0) @decorators.Isolated - # Disabled tests due to flakiness: http://crbug.com/641469 - @decorators.Disabled('all') + # The way Android handles crashes is through a different set of methods, so + # have an Android-specific test similar to testSymbolizeMinidump. + @decorators.Enabled('android') + def testGetStackTrace(self): + self._LoadPageThenWait('var sam = "car";', 'sam') + self._browser.tabs.New().Navigate('chrome://gpucrash', timeout=5) + _, output = self._browser.GetStackTrace() + + # The output is a single string with multiple sections: + # 1. UI Dump + # 2. Logcat + # 3. Stack from Logcat + # 4. Tombstones + # 5. Crashpad stackwalk + # Each section is finished with 80 asterisks, so split based on that. + sections = output.split('*' * 80 + '\n') + + # We will always get the UI dump and logcat sections. The logcat stack, + # tombstones, and Crashpad stack are dependent on the necessary tools being + # present, which they always should be. The Crashpad section actually having + # data is dependent on a Crashpad dump being found, which may not always be + # the case. So, expect 5 actual sections (6 total due to the way .split() + # works), the 5th possibly not having any valid data. + self.assertTrue(len(sections) == 6) + self.assertTrue(sections[2].startswith('Stack from Logcat')) + self.assertTrue(sections[3].startswith('Tombstones')) + + # Since the crash is a simulated one from gl::Crash(), we expect that to + # show up in the symbolized stacks, but not the unsymbolized one. + crash_function = 'gl::Crash()' + self.assertFalse(crash_function in sections[1]) + self.assertTrue(crash_function in sections[2]) + self.assertTrue(crash_function in sections[3]) + # If we actually have a valid Crashpad stack, make sure it contains the + # crash function as well. + print sections[4][:80] + if '**EMPTY**' not in sections[4]: + self.assertTrue(crash_function in sections[4]) + + @decorators.Isolated + @decorators.Disabled('chromeos', 'android', 'win7') def testMultipleCrashMinidumps(self): # Wait for the browser to restart fully before crashing self._LoadPageThenWait('var cat = "dog";', 'cat') self._browser.tabs.New().Navigate('chrome://gpucrash', timeout=5) first_crash_path = self._browser.GetMostRecentMinidumpPath() - #self.assertIsNotNone(first_crash_path) + self.assertIsNotNone(first_crash_path) if first_crash_path is not None: logging.info('testMultipleCrashMinidumps: first crash most recent path' + first_crash_path) @@ -63,10 +103,10 @@ if all_paths is not None: logging.info('testMultipleCrashMinidumps: first crash all paths: ' + ''.join(all_paths)) - #self.assertEquals(len(all_paths), 1) - #self.assertEqual(all_paths[0], first_crash_path) + self.assertEquals(len(all_paths), 1) + self.assertEqual(all_paths[0], first_crash_path) all_unsymbolized_paths = self._browser.GetAllUnsymbolizedMinidumpPaths() - #self.assertTrue(len(all_unsymbolized_paths) == 1) + self.assertTrue(len(all_unsymbolized_paths) == 1) if all_unsymbolized_paths is not None: logging.info('testMultipleCrashMinidumps: first crash all unsymbolized ' 'paths: ' + ''.join(all_unsymbolized_paths)) @@ -79,7 +119,7 @@ self._browser.tabs.New().Navigate('chrome://gpucrash', timeout=5) second_crash_path = self._browser.GetMostRecentMinidumpPath() - #self.assertIsNotNone(second_crash_path) + self.assertIsNotNone(second_crash_path) if second_crash_path is not None: logging.info('testMultipleCrashMinidumps: second crash most recent path' + second_crash_path) @@ -93,11 +133,11 @@ if second_crash_all_unsymbolized_paths is not None: logging.info('testMultipleCrashMinidumps: second crash all unsymbolized ' 'paths: ' + ''.join(second_crash_all_unsymbolized_paths)) - #self.assertEquals(len(second_crash_all_paths), 2) + self.assertEquals(len(second_crash_all_paths), 2) # Check that both paths are now present and unsymbolized - #self.assertTrue(first_crash_path in second_crash_all_paths) - #self.assertTrue(second_crash_path in second_crash_all_paths) - #self.assertTrue(len(second_crash_all_unsymbolized_paths) == 2) + self.assertTrue(first_crash_path in second_crash_all_paths) + self.assertTrue(second_crash_path in second_crash_all_paths) + self.assertTrue(len(second_crash_all_unsymbolized_paths) == 2) # Now symbolize one of those paths and assert that there is still one @@ -107,15 +147,15 @@ if after_symbolize_all_paths is not None: logging.info('testMultipleCrashMinidumps: after symbolize all paths: ' + ''.join(after_symbolize_all_paths)) - #self.assertEquals(len(after_symbolize_all_paths), 2) + self.assertEquals(len(after_symbolize_all_paths), 2) after_symbolize_all_unsymbolized_paths = \ self._browser.GetAllUnsymbolizedMinidumpPaths() if after_symbolize_all_unsymbolized_paths is not None: logging.info('testMultipleCrashMinidumps: after symbolize all ' + 'unsymbolized paths: ' + ''.join(after_symbolize_all_unsymbolized_paths)) - #self.assertEquals(after_symbolize_all_unsymbolized_paths, - # [first_crash_path]) + self.assertEquals(after_symbolize_all_unsymbolized_paths, + [first_crash_path]) def _LoadPageThenWait(self, script, value): # We are occasionally seeing these tests fail on the first load and
diff --git a/tools/perf/core/perf_benchmark_unittest.py b/tools/perf/core/perf_benchmark_unittest.py index ee4014a..8c97a754 100644 --- a/tools/perf/core/perf_benchmark_unittest.py +++ b/tools/perf/core/perf_benchmark_unittest.py
@@ -8,6 +8,7 @@ import tempfile import unittest +from telemetry.core import util from telemetry.internal.browser import browser_finder from telemetry.testing import options_for_unittests @@ -126,6 +127,17 @@ self.assertNotIn(arg, options.browser_options.extra_browser_args) def testNoAdTaggingRuleset(self): + # This tests (badly) assumes that util.GetBuildDirectories() will always + # return a list of multiple directories, with Debug ordered before Release. + # This is not the case if CHROMIUM_OUTPUT_DIR is set or a build.ninja file + # exists in the current working directory - in those cases, only a single + # directory is returned. So, abort early if we only get back one directory. + num_dirs = 0 + for _ in util.GetBuildDirectories(self._chrome_root): + num_dirs += 1 + if num_dirs < 2: + return + benchmark = perf_benchmark.PerfBenchmark() options = options_for_unittests.GetCopy() @@ -194,6 +206,17 @@ # directories matching the browser_type. self._PopulateGenFiles(os.path.join(self._chrome_root, 'out', 'Debug')) + # This tests (badly) assumes that util.GetBuildDirectories() will always + # return a list of multiple directories, with Debug ordered before Release. + # This is not the case if CHROMIUM_OUTPUT_DIR is set or a build.ninja file + # exists in the current working directory - in those cases, only a single + # directory is returned. So, abort early if we only get back one directory. + num_dirs = 0 + for _ in util.GetBuildDirectories(self._chrome_root): + num_dirs += 1 + if num_dirs < 2: + return + benchmark = perf_benchmark.PerfBenchmark() options = options_for_unittests.GetCopy() options.chrome_root = self._chrome_root
diff --git a/tools/traffic_annotation/scripts/traffic_annotation_auditor_tests.py b/tools/traffic_annotation/scripts/traffic_annotation_auditor_tests.py index 4c1719ec..cf3db645 100755 --- a/tools/traffic_annotation/scripts/traffic_annotation_auditor_tests.py +++ b/tools/traffic_annotation/scripts/traffic_annotation_auditor_tests.py
@@ -54,7 +54,16 @@ configs = [ ["--test-only", "--error-resilient"], # Similar to trybot. ["--test-only"], # Failing on any runtime error. - ["--test-only", "--no-filtering"] # Not using heuristic filtering. + ["--test-only", "--no-filtering"], # Not using heuristic filtering. + [ # extractor.py. + "--test-only", + "--extractor-backend=python_script", + ], + [ # extractor.py, no filtering. + "--test-only", + "--no-filtering", + "--extractor-backend=python_script", + ], ] self.last_result = None
diff --git a/ui/accessibility/ax_language_detection.h b/ui/accessibility/ax_language_detection.h index 8851290..41b50f83 100644 --- a/ui/accessibility/ax_language_detection.h +++ b/ui/accessibility/ax_language_detection.h
@@ -21,61 +21,28 @@ class AXTree; // This module implements language detection enabling Chrome to automatically -// detect the language for spans of text within the page without relying on any -// declared attributes. +// detect the language for runs of text within the page. // -// Language detection relies on four key data structures: -// AXLanguageInfo represents the local language detection data for all text -// within an AXNode. -// AXLanguageInfoStats records statistics about AXLanguageInfo for all AXNodes -// within a single AXTree, this is used to help give language detection -// some context to reduce false positive language assignment. -// AXLanguageSpan represents local language detection data for spans of text -// within an AXNode, this is used by sub-node level language detection. -// AXLanguageDetectionManager is in charge of managing all language detection -// context for a single AXTree. +// Node-level language detection runs once per page after the load complete +// event. This involves two passes: +// *Detect* walks the tree from the given root using cld3 to detect up to 3 +// potential languages per node. A ranked list is created enumerating +// all potential languages on a page. +// *Label* re-walks the tree, assigning a language to each node considering +// the potential languages from the detect phase, page level +// statistics, and the assigned languages of ancestor nodes. // -// -// Language detection is currently separated into two related implementation -// which are trying to address slightly different use cases, one operates at the -// node level, while the other operates at the sub-node level. -// -// -// Language detection at the node-level attempts to assign at most one language -// for each AXNode in order to support mixed-language pages. Node-level language -// detection is implemented as a two-pass process to reduce the assignment of -// spurious languages. -// -// After the first pass no languages have been assigned to AXNode(s), this is -// left to the second pass so that we can take use tree-level statistics to -// better inform the local language assigned. -// -// The first pass 'Detect' (entry point DetectLanguageForSubtree) walks the -// subtree from a given AXNode and attempts to detect the language of any text -// found. It records results in an instance of AXLanguageInfo which it stores on -// the AXNode, it also records statistics on the languages found in the -// AXLanguageInfoStats instance associated with each AXTree. -// -// The second pass 'Label' (entry point LabelLanguageForSubtree) walks the -// subtree from a given AXNode and attempts to find an appropriate language to -// associate with each AXNode based on a combination of the local detection -// results (AXLanguageInfo) and the global stats (AXLanguageInfoStats). -// -// -// Language detection at the sub-node level differs from node-level in that it -// operates at a much finer granularity of text, potentially down to individual -// characters in order to support mixed language sentences. -// We would like to detect languages that may only occur once throughout the -// entire document. Sub-node-level language detection is performed by using a -// language identifier constructed with a byte minimum of -// kShortTextIdentifierMinByteLength. This way, it can potentially detect the -// language of strings that are as short as one character in length. -// -// The entry point for sub-nod level language detection is -// GetLanguageAnnotationForStringAttribute. +// Optionally an embedder may run *sub-node* language detection which attempts +// to assign languages for runs of text within a node, potentially down to the +// individual character level. This is useful in cases where a single paragraph +// involves switching between multiple languages, and where the speech engine +// doesn't automatically switch voices to handle different character sets. +// Due to the potentially small lengths of text runs involved this tends to be +// lower in accuracy, and works best when a node is composed of multiple +// languages with easily distinguishable scripts. -// An instance of AXLanguageInfo is used to record the detected and assigned -// languages for a single AXNode, this data is entirely local to the AXNode. +// AXLanguageInfo represents the local language detection data for all text +// within an AXNode. Stored on AXNode. struct AX_EXPORT AXLanguageInfo { AXLanguageInfo(); ~AXLanguageInfo(); @@ -121,15 +88,21 @@ float probability; }; -// A single AXLanguageInfoStats instance is stored for each AXTree and -// represents the language detection statistics for every AXNode within that -// AXTree. +// A single AXLanguageInfoStats instance is stored on each AXTree and contains +// statistics on detected languages for all the AXNodes in that tree. // -// We rely on these tree-level statistics to avoid spurious language detection -// assignments. +// We rely on these tree-level statistics when labelling individual nodes, to +// provide extra signals to increase our confidence in assigning a detected +// language. // // The Label step will only assign a detected language to a node if that -// language is one of the dominant languages on the page. +// language is one of the most frequent languages on the page. +// +// For example, if a single node has detected_languages (in order of probability +// assigned by cld_3): da-DK, en-AU, fr-FR, but the page statistics overall +// indicate that the page is generally in en-AU and ja-JP, it is more likely to +// be a mis-recognition of Danish than an accurate assignment, so we assign +// en-AU instead of da-DK. class AX_EXPORT AXLanguageInfoStats { public: AXLanguageInfoStats(); @@ -163,8 +136,8 @@ DISALLOW_COPY_AND_ASSIGN(AXLanguageInfoStats); }; -// An instance of AXLanguageDetectionManager manages all the context needed for -// language detection within a single AXTree. +// AXLanguageDetectionManager manages all of the context needed for language +// detection within an AXTree. class AX_EXPORT AXLanguageDetectionManager { public: AXLanguageDetectionManager(); @@ -182,7 +155,7 @@ // having already completed. void LabelLanguageForSubtree(AXNode* subtree_root); - // Detect and return languages for string attribute. + // Sub-node language detection for a given string attribute. // For example, if a node has name: "My name is Fred", then calling // GetLanguageAnnotationForStringAttribute(*node, ax::mojom::StringAttribute:: // kName) would return language detection information about "My name is Fred".
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc index e99c109..5a5394f 100644 --- a/ui/accessibility/platform/ax_platform_node_base.cc +++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -733,6 +733,7 @@ bool AXPlatformNodeBase::IsInvisibleOrIgnored() const { const AXNodeData& data = GetData(); return data.HasState(ax::mojom::State::kInvisible) || + data.HasState(ax::mojom::State::kIgnored) || data.role == ax::mojom::Role::kIgnored; }
diff --git a/ui/base/l10n/l10n_util_unittest.cc b/ui/base/l10n/l10n_util_unittest.cc index ba9a3ea7..c3070971 100644 --- a/ui/base/l10n/l10n_util_unittest.cc +++ b/ui/base/l10n/l10n_util_unittest.cc
@@ -13,6 +13,7 @@ #include "base/i18n/time_formatting.h" #include "base/path_service.h" #include "base/stl_util.h" +#include "base/strings/pattern.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/test/icu_test_util.h" @@ -430,12 +431,18 @@ TEST_F(L10nUtilTest, GetDisplayNameForLocale) { // TODO(jungshik): Make this test more extensive. // Test zh-CN and zh-TW are treated as zh-Hans and zh-Hant. + // Displays as "Chinese, Simplified" on iOS 13+ and as "Chinese (Simplified)" + // on other platforms. base::string16 result = l10n_util::GetDisplayNameForLocale("zh-CN", "en", false); - EXPECT_EQ(ASCIIToUTF16("Chinese (Simplified)"), result); + EXPECT_TRUE( + base::MatchPattern(base::UTF16ToUTF8(result), "Chinese*Simplified*")); + // Displays as "Chinese, Traditional" on iOS 13+ and as + // "Chinese (Traditional)" on other platforms. result = l10n_util::GetDisplayNameForLocale("zh-TW", "en", false); - EXPECT_EQ(ASCIIToUTF16("Chinese (Traditional)"), result); + EXPECT_TRUE( + base::MatchPattern(base::UTF16ToUTF8(result), "Chinese*Traditional*")); // tl and fil are not identical to be strict, but we treat them as // synonyms.
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index e9be02b..04529b09 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -206,6 +206,7 @@ features::kCompositorThreadedScrollbarScrolling)) { settings.compositor_threaded_scrollbar_scrolling = true; } + settings.layer_transforms_should_scale_layer_contents = true; animation_host_ = cc::AnimationHost::CreateMainInstance();
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.cc b/ui/events/ozone/evdev/touch_event_converter_evdev.cc index 77d364f6..b1d83fa 100644 --- a/ui/events/ozone/evdev/touch_event_converter_evdev.cc +++ b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
@@ -608,7 +608,7 @@ ReportEvents(EventTimeForNow()); } -float TouchEventConverterEvdev::ScalePressure(int32_t value) { +float TouchEventConverterEvdev::ScalePressure(int32_t value) const { float pressure = value - pressure_min_; if (pressure_max_ - pressure_min_) pressure /= pressure_max_ - pressure_min_;
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.h b/ui/events/ozone/evdev/touch_event_converter_evdev.h index 2bbdc40..991f88b 100644 --- a/ui/events/ozone/evdev/touch_event_converter_evdev.h +++ b/ui/events/ozone/evdev/touch_event_converter_evdev.h
@@ -93,7 +93,7 @@ void CancelAllTouches(); bool IsPalm(const InProgressTouchEvdev& touch); // Normalize pressure value to [0, 1]. - float ScalePressure(int32_t value); + float ScalePressure(int32_t value) const; int NextTrackingId(); @@ -165,7 +165,6 @@ // Callback to enable/disable palm suppression. base::RepeatingCallback<void(bool)> enable_palm_suppression_callback_; - DISALLOW_COPY_AND_ASSIGN(TouchEventConverterEvdev); };
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc index b9404ce..e8acc7c 100644 --- a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc +++ b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
@@ -1543,6 +1543,40 @@ up_event.pointer_details.pointer_type); } +TEST_F(TouchEventConverterEvdevTest, ScalePressure) { + EventDeviceInfo devinfo; + EXPECT_TRUE(CapabilitiesToDeviceInfo(kEveTouchScreen, &devinfo)); + device()->Initialize(devinfo); + timeval time; + time = {1507226211, 483601}; + // Fake abroken input: note the pressure. + struct input_event mock_kernel_queue[] = { + {time, EV_ABS, ABS_MT_TRACKING_ID, 461}, + {time, EV_ABS, ABS_MT_POSITION_X, 1795}, + {time, EV_ABS, ABS_MT_POSITION_Y, 5559}, + {time, EV_ABS, ABS_MT_PRESSURE, + devinfo.GetAbsMaximum(ABS_MT_PRESSURE) * 2}, + {time, EV_ABS, ABS_MT_TOUCH_MAJOR, 14}, + {time, EV_ABS, ABS_MT_TOUCH_MINOR, 14}, + {time, EV_KEY, BTN_TOUCH, 1}, + {time, EV_ABS, ABS_X, 1795}, + {time, EV_ABS, ABS_Y, 5559}, + {time, EV_ABS, ABS_PRESSURE, 217}, + {time, EV_MSC, MSC_TIMESTAMP, 0}, + {time, EV_SYN, SYN_REPORT, 0}, + }; + // Set test now time to ensure above timestamps are in the past. + SetTestNowTime(time); + + // Finger pressed with major/minor reported. + device()->ConfigureReadMock(mock_kernel_queue, base::size(mock_kernel_queue), + 0); + device()->ReadNow(); + EXPECT_EQ(1u, size()); + ui::TouchEventParams event = dispatched_touch_event(0); + EXPECT_FLOAT_EQ(1.0, event.pointer_details.force); +} + // crbug.com/771374 TEST_F(TouchEventConverterEvdevTest, FingerSizeWithResolution) { ui::MockTouchEventConverterEvdev* dev = device(); @@ -1581,9 +1615,10 @@ EXPECT_EQ(1795, event.location.x()); EXPECT_EQ(5559, event.location.y()); EXPECT_EQ(0, event.slot); + EXPECT_FLOAT_EQ(217.0 / devinfo.GetAbsMaximum(ABS_MT_PRESSURE), + event.pointer_details.force); EXPECT_EQ(EventPointerType::POINTER_TYPE_TOUCH, event.pointer_details.pointer_type); EXPECT_FLOAT_EQ(280.f, event.pointer_details.radius_x); - EXPECT_FLOAT_EQ(0.8509804f, event.pointer_details.force); } } // namespace ui
diff --git a/ui/file_manager/file_manager/foreground/js/metadata_box_controller.js b/ui/file_manager/file_manager/foreground/js/metadata_box_controller.js index ff51b42..4ed41605e 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata_box_controller.js +++ b/ui/file_manager/file_manager/foreground/js/metadata_box_controller.js
@@ -239,20 +239,20 @@ * A loading animation is shown while fetching the directory size. However, it * won't show if there is no size value. Use a dummy value ' ' in that case. * - * If previous getDirectorySize is still running, next getDirectorySize is not - * called at the time. After the previous callback is finished, getDirectorySize - * that corresponds to the last setDirectorySize_ is called. + * To avoid flooding the OS system with chrome.getDirectorySize requests, if a + * previous request is active, store the new request and return. Only the most + * recent new request is stored. When the active request returns, it calls the + * stored request instead of updating the size field. * * @param {!DirectoryEntry} entry - * @param {boolean} isSameEntry if the entry is not changed from the last time. + * @param {boolean} isSameEntry True if the entry is not changed from the last + * time. False enables the loading animation. * * @private */ MetadataBoxController.prototype.setDirectorySize_ = function( entry, isSameEntry) { - if (!entry.isDirectory) { - return; - } + assert(entry.isDirectory); if (this.metadataBox_.size === '') { this.metadataBox_.size = ' '; // Provide a dummy size value. @@ -263,14 +263,13 @@ this.metadataBox_.isSizeLoading = true; } - // Only retain the last setDirectorySize_ request. + // Store the new setDirectorySize_ request and return. this.onDirectorySizeLoaded_ = lastEntry => { this.setDirectorySize_(entry, util.isSameEntry(entry, lastEntry)); }; return; } - // false if the entry is same. true if the entry is changed. this.metadataBox_.isSizeLoading = !isSameEntry; this.isDirectorySizeLoading_ = true; @@ -280,6 +279,7 @@ if (this.onDirectorySizeLoaded_) { setTimeout(this.onDirectorySizeLoaded_.bind(null, entry)); this.onDirectorySizeLoaded_ = null; + return; } if (this.quickViewModel_.getSelectedEntry() != entry) { @@ -287,8 +287,8 @@ } if (chrome.runtime.lastError) { - this.metadataBox_.isSizeLoading = false; - return; + console.error(chrome.runtime.lastError); + size = undefined; } this.metadataBox_.size = this.fileMetadataFormatter_.formatSize(size, true);
diff --git a/ui/gfx/linux/native_pixmap_dmabuf.cc b/ui/gfx/linux/native_pixmap_dmabuf.cc index 97fa6de..e9f5bd3 100644 --- a/ui/gfx/linux/native_pixmap_dmabuf.cc +++ b/ui/gfx/linux/native_pixmap_dmabuf.cc
@@ -76,7 +76,7 @@ } gfx::NativePixmapHandle NativePixmapDmaBuf::ExportHandle() { - return gfx::NativePixmapHandle(); + return gfx::CloneHandleForIPC(handle_); } } // namespace gfx
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc index 4967369..9783b72 100644 --- a/ui/gl/swap_chain_presenter.cc +++ b/ui/gl/swap_chain_presenter.cc
@@ -62,8 +62,7 @@ kMaxValue = kNotAvailable, }; -void RecordOverlayFullScreenTypes(bool workaround_applied, - const gfx::Rect& overlay_onscreen_rect) { +void RecordOverlayFullScreenTypes(const gfx::Rect& overlay_onscreen_rect) { OverlayFullScreenTypes full_screen_type; const gfx::Size& screen_size = DirectCompositionSurfaceWin::GetOverlayMonitorSize(); @@ -91,12 +90,6 @@ UMA_HISTOGRAM_ENUMERATION("GPU.DirectComposition.OverlayFullScreenTypes", full_screen_type); - - // TODO(magchen): To be deleted once we know if this workaround is still - // needed - UMA_HISTOGRAM_BOOLEAN( - "GPU.DirectComposition.DisableLargerThanScreenOverlaysWorkaround", - workaround_applied); } const char* ProtectedVideoTypeToString(gfx::ProtectedVideoType type) { @@ -373,7 +366,6 @@ swap_chain_size.SetToMin(params.content_rect.size()); } - bool workaround_applied = false; gfx::Size overlay_monitor_size = DirectCompositionSurfaceWin::GetOverlayMonitorSize(); if (layer_tree_->disable_larger_than_screen_overlays() && @@ -393,19 +385,15 @@ (swap_chain_size.width() <= overlay_monitor_size.width() + kOversizeMargin)) { swap_chain_size.set_width(overlay_monitor_size.width()); - workaround_applied = true; } if ((swap_chain_size.height() > overlay_monitor_size.height()) && (swap_chain_size.height() <= overlay_monitor_size.height() + kOversizeMargin)) { swap_chain_size.set_height(overlay_monitor_size.height()); - workaround_applied = true; } } - RecordOverlayFullScreenTypes( - workaround_applied, - /*overlay_onscreen_rect*/ gfx::ToEnclosingRect(bounds)); + RecordOverlayFullScreenTypes(gfx::ToEnclosingRect(bounds)); // 4:2:2 subsampled formats like YUY2 must have an even width, and 4:2:0 // subsampled formats like NV12 must have an even width and height.
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js index 58fb3bd7..930b447 100644 --- a/ui/webui/resources/cr_components/chromeos/network/network_config.js +++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -406,7 +406,9 @@ this.getManagedPropertiesCallback_(managedProperties); }); } else { - this.focusFirstInput_(); + setTimeout(() => { + this.focusFirstInput_(); + }); } if (this.type == CrOnc.Type.VPN ||
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_nameservers.js b/ui/webui/resources/cr_components/chromeos/network/network_nameservers.js index edcd2d8..995cad9 100644 --- a/ui/webui/resources/cr_components/chromeos/network/network_nameservers.js +++ b/ui/webui/resources/cr_components/chromeos/network/network_nameservers.js
@@ -193,9 +193,9 @@ return nameserversType == 'custom' && !this.isNetworkPolicyEnforced( networkProperties.NameServersConfigType) && - !!networkProperties.StaticIPConfig && - !this.isNetworkPolicyEnforced( - networkProperties.StaticIPConfig.NameServers); + (!networkProperties.StaticIPConfig || + !this.isNetworkPolicyEnforced( + networkProperties.StaticIPConfig.NameServers)); }, /**