diff --git a/DEPS b/DEPS index 0f099ba..8501e3e 100644 --- a/DEPS +++ b/DEPS
@@ -105,11 +105,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '4ec72f7cc745bbd98a0ae0d160e774ce8ad1a1ff', + 'skia_revision': 'fcc10da18eb533e83d8d46181819deed234ad1a3', # 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': '8dc93fc4fa1ec6d0501d982679ce93efc383d3b8', + 'v8_revision': '8b17db68f75a95d69debfa85b70aea3ec0766aaf', # 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. @@ -117,7 +117,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': '89ef177f94753a91d7ec12aa58a5b06df2c12f0f', + 'angle_revision': '5598148b761380773c4e650b5b67f47553b0f090', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -129,7 +129,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': 'b165ffb64e59998ec6d5f76c82bd2fe53734b3cd', + 'pdfium_revision': 'd8882193737ae167a33c1bf7a5cdb64543ad0301', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -153,7 +153,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': '0ba35b21089a442dd4f25c35fd571d46cb4aa199', + 'nacl_revision': 'e6ce828ef60c4c1438867b535efbbb5d9a177c0e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -161,11 +161,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling HarfBuzz # and whatever else without interference from each other. - 'harfbuzz_revision': '058708a665cdd9e796581dbcf60a5778d3f5e240', + 'harfbuzz_revision': '2b76767bf572364d3d647cdd139f2044a7ad06b2', # 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': '1af68170e543102499b0b9be0351a5ffa6e21da2', + 'catapult_revision': '39de3d2258563f5ef8c7366c0354adf41fe5a94b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -540,7 +540,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a3bc29bcacf392cdba0021fee8bab5bd45665975', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'c228d491eb86e4a116799d3e3a68e28c843077f5', 'condition': 'checkout_linux', }, @@ -565,7 +565,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c3975e55e1465d9d9320ae67889f0b057c7d7ec3', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '32e3d1e37cd6a379cc5767dc3aaa43053df9a151', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -1035,7 +1035,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'a5c263cc63ffc2cc189b5214074c8792067c1853', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'ef43aafcf5953845b71840e14c94942d60c541c1', + Var('webrtc_git') + '/src.git' + '@' + '5795489e83adba65cb480d57e71f52bae1f5ee1b', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1884,19 +1884,6 @@ ], }, - # Download Telemetry's binary dependencies - # TODO(crbug.com/780967) - remove this once the bots are setting the - # `checkout_telemetry_dependencies` condition. - { - 'name': 'fetch_telemetry_binary_dependencies', - 'pattern': '.', - 'action': [ 'vpython', - 'src/tools/perf/conditionally_execute', - '--gyp-condition', 'fetch_telemetry_dependencies=1', - 'src/third_party/catapult/telemetry/bin/fetch_telemetry_binary_dependencies', - ], - }, - # This is used to ensure that all network operations are properly # annotated so we can document what they're for. {
diff --git a/WATCHLISTS b/WATCHLISTS index e984014e..abe561d 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -563,6 +563,16 @@ 'bottombar': { 'filepath': 'chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/', }, + 'breve': { + 'filepath': 'chrome/browser/net/spdyproxy|'\ + 'chrome_proxy|'\ + 'components/blacklist|'\ + 'components/data_use|'\ + 'data_reduction_proxy|'\ + 'previews|'\ + 'optimization_guide|'\ + 'optimization_hints' + }, 'browser_components': { 'filepath': 'chrome/browser/autofill/' \ '|chrome/browser/bookmarks/' \ @@ -772,11 +782,6 @@ 'filepath': 'chrome/android/java/src/org/chromium/chrome/browser/customtabs/|'\ 'chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/', }, - 'data_reduction_proxy': { - 'filepath': 'chrome/browser/net/spdyproxy/|'\ - 'data_reduction_proxy|'\ - 'chrome_proxy', - }, 'dbus': { 'filepath': 'dbus/', }, @@ -1927,6 +1932,7 @@ 'bookmarks': ['tfarina@chromium.org'], 'bottombar': ['donnd+watch@chromium.org', 'mdjones+watch@chromium.org'], + 'breve': ['breve-team-reviews@chromium.org'], 'browser_components': ['browser-components-watch@chromium.org'], 'browser_compositor': ['piman+watch@chromium.org', 'vollick@chromium.org'], @@ -2031,8 +2037,7 @@ 'cywang@chromium.org', 'vovoy@chromium.org'], 'crostini': ['crostini-ui@chromium.org'], - 'custom_tabs': ['lizeb+watch-custom-tabs@chromium.org'], - 'data_reduction_proxy': ['tbansal+watch-data-reduction-proxy@chromium.org'], + 'custom_tabs': ['lizeb+watch-custom-tabs@chromium.org'], 'dbus': ['hashimoto+watch@chromium.org'], 'deep_memory_profiler': ['dmikurube@chromium.org'], 'device_bluetooth': ['mattreynolds+watch@chromium.org',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index 1c4915e..1403ed5 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -713,6 +713,7 @@ "//components/crash/content/app", "//components/crash/content/browser", "//components/download/public/common:public", + "//components/embedder_support/android:web_contents_delegate", "//components/google/core/browser", "//components/heap_profiling", "//components/keyed_service/content", @@ -750,7 +751,6 @@ "//components/visitedlink/browser", "//components/visitedlink/renderer", "//components/viz/service", - "//components/web_contents_delegate_android:web_contents_delegate_android", "//components/web_restrictions:browser", "//content", "//content/public/app:both", @@ -894,6 +894,7 @@ "//components/autofill/android:provider_java", "//components/background_task_scheduler:background_task_scheduler_java", "//components/crash/android:java", + "//components/embedder_support/android:web_contents_delegate_java", "//components/minidump_uploader:minidump_uploader_java", "//components/navigation_interception/android:navigation_interception_java", "//components/policy/android:policy_java", @@ -901,7 +902,6 @@ "//components/variations:load_seed_result_enum_java", "//components/variations/android:variations_java", "//components/version_info/android:version_constants_java", - "//components/web_contents_delegate_android:web_contents_delegate_android_java", "//components/web_restrictions:client_java", "//content/public/android:content_java", "//device/gamepad:java",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS index f2379488..0b836c7 100644 --- a/android_webview/browser/DEPS +++ b/android_webview/browser/DEPS
@@ -46,7 +46,7 @@ "+media/base/android", "+components/policy/policy_constants.h", - "+components/web_contents_delegate_android", + "+components/embedder_support/android", "+printing",
diff --git a/android_webview/browser/aw_web_contents_delegate.h b/android_webview/browser/aw_web_contents_delegate.h index b78778e..e78cab18 100644 --- a/android_webview/browser/aw_web_contents_delegate.h +++ b/android_webview/browser/aw_web_contents_delegate.h
@@ -5,7 +5,7 @@ #ifndef ANDROID_WEBVIEW_BROWSER_AW_WEB_CONTENTS_DELEGATE_H_ #define ANDROID_WEBVIEW_BROWSER_AW_WEB_CONTENTS_DELEGATE_H_ -#include "components/web_contents_delegate_android/web_contents_delegate_android.h" +#include "components/embedder_support/android/delegate/web_contents_delegate_android.h" namespace android_webview {
diff --git a/android_webview/java/DEPS b/android_webview/java/DEPS index 8279631..22f0142 100644 --- a/android_webview/java/DEPS +++ b/android_webview/java/DEPS
@@ -1,11 +1,11 @@ include_rules = [ "+components/autofill/android/java", "+components/background_task_scheduler/android/java", + "+components/embedder_support/android/java", "+components/minidump_uploader/android/java", "+components/navigation_interception/android/java", "+components/policy/android/java", "+components/safe_browsing/android/java", - "+components/web_contents_delegate_android/java", "+components/variations/android/java", "-content/public/android/java",
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java index 1455028..ec85440 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java +++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java
@@ -7,7 +7,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; -import org.chromium.components.web_contents_delegate_android.WebContentsDelegateAndroid; +import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid; /** * WebView-specific WebContentsDelegate.
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn index 17b6ce2..ff24abb 100644 --- a/android_webview/test/BUILD.gn +++ b/android_webview/test/BUILD.gn
@@ -131,12 +131,12 @@ "//base:base_java", "//base:base_java_test_support", "//components/autofill/android:provider_java", + "//components/embedder_support/android:web_contents_delegate_java", "//components/minidump_uploader:minidump_uploader_java", "//components/minidump_uploader:minidump_uploader_javatests", "//components/policy/android:policy_java", "//components/policy/android:policy_java_test_support", "//components/safe_browsing/android:safe_browsing_java", - "//components/web_contents_delegate_android:web_contents_delegate_android_java", "//content/public/android:content_java", "//content/public/test/android:content_java_test_support", "//mojo/public/java:bindings_java",
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index dbf984a..bbaa66b 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -2015,6 +2015,7 @@ "//components/sync_preferences:test_support", "//components/user_manager", "//components/user_manager:test_support", + "//device/base", "//device/bluetooth", "//mojo/core/embedder", "//net:net",
diff --git a/ash/DEPS b/ash/DEPS index ec6fc9f2..21bb83e 100644 --- a/ash/DEPS +++ b/ash/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+device/base/features.h", "+device/bluetooth", "+cc/debug", "+cc/output",
diff --git a/ash/accelerators/debug_commands.cc b/ash/accelerators/debug_commands.cc index 838f814..ec508e9f 100644 --- a/ash/accelerators/debug_commands.cc +++ b/ash/accelerators/debug_commands.cc
@@ -16,10 +16,12 @@ #include "ash/wm/widget_finder.h" #include "ash/wm/window_properties.h" #include "ash/wm/window_util.h" +#include "ash/ws/window_service_owner.h" #include "base/command_line.h" #include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics_action.h" #include "base/strings/utf_string_conversions.h" +#include "services/ui/ws2/window_service.h" #include "ui/compositor/debug_utils.h" #include "ui/compositor/layer.h" #include "ui/display/manager/display_manager.h" @@ -53,7 +55,8 @@ views::PrintViewHierarchy(widget->GetRootView()); } -void PrintWindowHierarchy(const aura::Window* active_window, +void PrintWindowHierarchy(ui::ws2::WindowService* window_service, + const aura::Window* active_window, aura::Window* window, int indent, std::ostringstream* out) { @@ -61,27 +64,34 @@ std::string name(window->GetName()); if (name.empty()) name = "\"\""; + const gfx::Vector2dF& subpixel_position_offset = + window->layer()->subpixel_position_offset(); *out << indent_str << name << " (" << window << ")" << " type=" << window->type() - << ((window == active_window) ? " [active] " : " ") - << (window->IsVisible() ? " visible " : " ") - << window->bounds().ToString() - << (window->GetProperty(kSnapChildrenToPixelBoundary) ? " [snapped] " - : "") - << ", subpixel offset=" - << window->layer()->subpixel_position_offset().ToString() << '\n'; + << ((window == active_window) ? " [active]" : "") + << (window->IsVisible() ? " visible" : "") << " " + << window->bounds().ToString(); + if (window->GetProperty(kSnapChildrenToPixelBoundary)) + *out << " [snapped]"; + if (!subpixel_position_offset.IsZero()) + *out << " subpixel offset=" + subpixel_position_offset.ToString(); + if (window_service && ui::ws2::WindowService::HasRemoteClient(window)) + *out << " remote_id=" << window_service->GetIdForDebugging(window); + *out << '\n'; for (aura::Window* child : window->children()) - PrintWindowHierarchy(active_window, child, indent + 3, out); + PrintWindowHierarchy(window_service, active_window, child, indent + 3, out); } void HandlePrintWindowHierarchy() { aura::Window* active_window = wm::GetActiveWindow(); aura::Window::Windows roots = Shell::Get()->GetAllRootWindows(); + ui::ws2::WindowService* window_service = + Shell::Get()->window_service_owner()->window_service(); for (size_t i = 0; i < roots.size(); ++i) { std::ostringstream out; out << "RootWindow " << i << ":\n"; - PrintWindowHierarchy(active_window, roots[i], 0, &out); + PrintWindowHierarchy(window_service, active_window, roots[i], 0, &out); // Error so logs can be collected from end-users. LOG(ERROR) << out.str(); }
diff --git a/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc b/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc index 5ac7095..cee5fa4c 100644 --- a/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc +++ b/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc
@@ -139,9 +139,7 @@ if (!timer->IsRunning()) return false; - base::Closure task = timer->user_task(); - timer->Stop(); - task.Run(); + timer->FireNow(); return true; }
diff --git a/ash/policy/policy_recommendation_restorer_unittest.cc b/ash/policy/policy_recommendation_restorer_unittest.cc index 81c43141..5eab2f5a 100644 --- a/ash/policy/policy_recommendation_restorer_unittest.cc +++ b/ash/policy/policy_recommendation_restorer_unittest.cc
@@ -135,10 +135,7 @@ if (!restorer_->restore_timer_for_test()->IsRunning()) return false; - base::RepeatingClosure task = - restorer_->restore_timer_for_test()->user_task(); - restorer_->restore_timer_for_test()->Stop(); - task.Run(); + restorer_->restore_timer_for_test()->FireNow(); return true; }
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc index 60d44bd..efd023a 100644 --- a/ash/shelf/shelf.cc +++ b/ash/shelf/shelf.cc
@@ -7,7 +7,6 @@ #include <memory> #include "ash/app_list/app_list_controller_impl.h" -#include "ash/public/cpp/config.h" #include "ash/public/cpp/shelf_item_delegate.h" #include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shell_window_ids.h" @@ -29,7 +28,6 @@ // Shelf::AutoHideEventHandler ----------------------------------------------- // Forwards mouse and gesture events to ShelfLayoutManager for auto-hide. -// TODO(mash): Add similar event handling support for mash. class Shelf::AutoHideEventHandler : public ui::EventHandler { public: explicit AutoHideEventHandler(ShelfLayoutManager* shelf_layout_manager) @@ -57,12 +55,9 @@ // Shelf --------------------------------------------------------------------- -Shelf::Shelf() : shelf_locking_manager_(this) { - // TODO: ShelfBezelEventHandler needs to work with mus too. - // http://crbug.com/636647 - if (Shell::GetAshConfig() != Config::MASH_DEPRECATED) - bezel_event_handler_ = std::make_unique<ShelfBezelEventHandler>(this); -} +Shelf::Shelf() + : shelf_locking_manager_(this), + bezel_event_handler_(std::make_unique<ShelfBezelEventHandler>(this)) {} Shelf::~Shelf() = default; @@ -348,8 +343,7 @@ observer.WillChangeVisibilityState(new_state); if (new_state != SHELF_AUTO_HIDE) { auto_hide_event_handler_.reset(); - } else if (!auto_hide_event_handler_ && - Shell::GetAshConfig() != Config::MASH_DEPRECATED) { + } else if (!auto_hide_event_handler_) { auto_hide_event_handler_ = std::make_unique<AutoHideEventHandler>(shelf_layout_manager()); }
diff --git a/ash/shelf/shelf.h b/ash/shelf/shelf.h index ae578c9..999726a6 100644 --- a/ash/shelf/shelf.h +++ b/ash/shelf/shelf.h
@@ -187,11 +187,9 @@ base::ObserverList<ShelfObserver> observers_; // Forwards mouse and gesture events to ShelfLayoutManager for auto-hide. - // TODO(mash): Facilitate simliar functionality in mash: crbug.com/631216 std::unique_ptr<AutoHideEventHandler> auto_hide_event_handler_; // Forwards touch gestures on a bezel sensor to the shelf. - // TODO(mash): Facilitate simliar functionality in mash: crbug.com/636647 std::unique_ptr<ShelfBezelEventHandler> bezel_event_handler_; // True while the animation to enter or exit tablet mode is running. Sometimes
diff --git a/ash/shell.h b/ash/shell.h index d711335cc..42c3d8106 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -569,7 +569,6 @@ WindowSelectorController* window_selector_controller() { return window_selector_controller_.get(); } - // WindowServiceOwner is null in mash. WindowServiceOwner* window_service_owner() { return window_service_owner_.get(); }
diff --git a/ash/system/bluetooth/tray_bluetooth_helper_unittest.cc b/ash/system/bluetooth/tray_bluetooth_helper_unittest.cc index 87ebdc4e..7b481a5f 100644 --- a/ash/system/bluetooth/tray_bluetooth_helper_unittest.cc +++ b/ash/system/bluetooth/tray_bluetooth_helper_unittest.cc
@@ -7,6 +7,8 @@ #include <vector> #include "ash/test/ash_test_base.h" +#include "base/test/scoped_feature_list.h" +#include "device/base/features.h" #include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h" #include "device/bluetooth/dbus/fake_bluetooth_device_client.h" @@ -76,5 +78,42 @@ EXPECT_FALSE(helper.HasBluetoothDiscoverySession()); } +// Tests the Bluetooth device list when UnfilteredBluetoothDevices feature is +// enabled. +TEST_F(TrayBluetoothHelperTest, UnfilteredBluetoothDevices) { + base::test::ScopedFeatureList feature_list; + feature_list.InitFromCommandLine(device::kUnfilteredBluetoothDevices.name, + ""); + + // Set Bluetooth discovery simulation delay to 0 so the test doesn't have to + // wait or use timers. + FakeBluetoothAdapterClient* adapter_client = + static_cast<FakeBluetoothAdapterClient*>( + BluezDBusManager::Get()->GetBluetoothAdapterClient()); + adapter_client->SetSimulationIntervalMs(0); + + FakeBluetoothDeviceClient* device_client = + static_cast<FakeBluetoothDeviceClient*>( + BluezDBusManager::Get()->GetBluetoothDeviceClient()); + // All devices should be shown (unfiltered). + device_client->CreateDevice( + dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath), + dbus::ObjectPath(FakeBluetoothDeviceClient::kDisplayPinCodePath)); + device_client->CreateDevice( + dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath), + dbus::ObjectPath(FakeBluetoothDeviceClient::kLowEnergyPath)); + + TrayBluetoothHelper helper; + helper.Initialize(); + base::RunLoop().RunUntilIdle(); + + BluetoothDeviceList devices = helper.GetAvailableBluetoothDevices(); + // The devices are fake in tests, so don't assume any particular number. + EXPECT_TRUE(ExistInFilteredDevices( + FakeBluetoothDeviceClient::kDisplayPinCodeAddress, devices)); + EXPECT_TRUE(ExistInFilteredDevices( + FakeBluetoothDeviceClient::kLowEnergyAddress, devices)); +} + } // namespace } // namespace ash
diff --git a/ash/system/flag_warning/flag_warning_tray.cc b/ash/system/flag_warning/flag_warning_tray.cc index a14cd4f..e5edde6 100644 --- a/ash/system/flag_warning/flag_warning_tray.cc +++ b/ash/system/flag_warning/flag_warning_tray.cc
@@ -38,9 +38,6 @@ DCHECK(shelf_); SetLayoutManager(std::make_unique<views::FillLayout>()); - // Flag warning tray is not currently used in non-MASH environments, because - // mus will roll out via experiment/Finch trial and showing the tray would - // reveal the experiment state to users. DCHECK(!::features::IsAshInBrowserProcess()); container_ = new TrayContainer(shelf); AddChildView(container_);
diff --git a/ash/system/flag_warning/flag_warning_tray_unittest.cc b/ash/system/flag_warning/flag_warning_tray_unittest.cc index 0a13e9c5..b8f5b5d 100644 --- a/ash/system/flag_warning/flag_warning_tray_unittest.cc +++ b/ash/system/flag_warning/flag_warning_tray_unittest.cc
@@ -4,26 +4,40 @@ #include "ash/system/flag_warning/flag_warning_tray.h" -#include "ash/public/cpp/config.h" #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/system/status_area_widget.h" #include "ash/test/ash_test_base.h" +#include "base/macros.h" +#include "base/test/scoped_feature_list.h" +#include "ui/base/ui_base_features.h" namespace ash { namespace { -using FlagWarningTrayTest = AshTestBase; +class FlagWarningTrayTest : public AshTestBase { + public: + FlagWarningTrayTest() = default; + ~FlagWarningTrayTest() override = default; -TEST_F(FlagWarningTrayTest, Visibility) { - // Flag warning tray is not currently used in non-MASH environments, because - // mus will roll out via experiment/Finch trial and showing the tray would - // reveal the experiment state to users. - const bool is_mash = Shell::GetAshConfig() == Config::MASH_DEPRECATED; + // testing::Test: + void SetUp() override { + scoped_feature_list_.InitAndEnableFeature(::features::kMash); + AshTestBase::SetUp(); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; + + DISALLOW_COPY_AND_ASSIGN(FlagWarningTrayTest); +}; + +TEST_F(FlagWarningTrayTest, VisibleForMash) { FlagWarningTray* tray = Shell::GetPrimaryRootWindowController() ->GetStatusAreaWidget() ->flag_warning_tray_for_testing(); - EXPECT_EQ(tray != nullptr, is_mash); + ASSERT_TRUE(tray); + EXPECT_TRUE(tray->visible()); } } // namespace
diff --git a/ash/system/night_light/night_light_controller.h b/ash/system/night_light/night_light_controller.h index 6f7e327..550929a 100644 --- a/ash/system/night_light/night_light_controller.h +++ b/ash/system/night_light/night_light_controller.h
@@ -118,7 +118,7 @@ AnimationDuration last_animation_duration() const { return last_animation_duration_; } - const base::OneShotTimer& timer() const { return timer_; } + base::OneShotTimer* timer() { return &timer_; } void BindRequest(mojom::NightLightControllerRequest request);
diff --git a/ash/system/night_light/night_light_controller_unittest.cc b/ash/system/night_light/night_light_controller_unittest.cc index bfa8a87..1955f8d 100644 --- a/ash/system/night_light/night_light_controller_unittest.cc +++ b/ash/system/night_light/night_light_controller_unittest.cc
@@ -391,17 +391,16 @@ TestCompositorsTemperature(controller->GetColorTemperature()); EXPECT_EQ(NightLightController::AnimationDuration::kShort, controller->last_animation_duration()); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(2), - controller->timer().GetCurrentDelay()); - EXPECT_TRUE(controller->timer().user_task()); + controller->timer()->GetCurrentDelay()); // If the user changes the schedule type to "none", the NightLight status // should not change, but the timer should not be running. controller->SetScheduleType(NightLightController::ScheduleType::kNone); EXPECT_TRUE(controller->GetEnabled()); TestCompositorsTemperature(controller->GetColorTemperature()); - EXPECT_FALSE(controller->timer().IsRunning()); + EXPECT_FALSE(controller->timer()->IsRunning()); } // Tests what happens when the time now reaches the end of the NightLight @@ -425,16 +424,16 @@ // // Now is 8:00 PM. delegate()->SetFakeNow(TimeOfDay(20 * 60)); - controller->timer().user_task().Run(); + controller->timer()->FireNow(); EXPECT_FALSE(controller->GetEnabled()); TestCompositorsTemperature(0.0f); EXPECT_EQ(NightLightController::AnimationDuration::kLong, controller->last_animation_duration()); // The timer should still be running, but now scheduling the start at 3:00 PM // tomorrow which is 19 hours from "now" (8:00 PM). - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(19), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); } // Tests that user toggles from the system menu or system settings override any @@ -467,9 +466,9 @@ controller->last_animation_duration()); // The timer should still be running, but NightLight should automatically // turn off at 8:00 PM tomorrow, which is 21 hours from now (11:00 PM). - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(21), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); // Manually turning it back off should also be respected, and this time the // start is scheduled at 3:00 PM tomorrow after 19 hours from "now" (8:00 PM). @@ -478,9 +477,9 @@ TestCompositorsTemperature(0.0f); EXPECT_EQ(NightLightController::AnimationDuration::kShort, controller->last_animation_duration()); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(16), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); } // Tests that changing the custom start and end times, in such a way that @@ -505,27 +504,27 @@ controller->SetScheduleType(NightLightController::ScheduleType::kCustom); EXPECT_FALSE(controller->GetEnabled()); TestCompositorsTemperature(0.0f); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(2), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); // Change the start time in such a way that doesn't change the status, but // despite that, confirm that schedule has been updated. controller->SetCustomStartTime(TimeOfDay(19 * 60)); // 7:00 PM. EXPECT_FALSE(controller->GetEnabled()); TestCompositorsTemperature(0.0f); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(3), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); // Changing the end time in a similar fashion to the above and expect no // change. controller->SetCustomEndTime(TimeOfDay(23 * 60)); // 11:00 PM. EXPECT_FALSE(controller->GetEnabled()); TestCompositorsTemperature(0.0f); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(3), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); } // Tests the behavior of the sunset to sunrise automatic schedule type. @@ -550,33 +549,33 @@ NightLightController::ScheduleType::kSunsetToSunrise); EXPECT_FALSE(controller->GetEnabled()); TestCompositorsTemperature(0.0f); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(4), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); // Simulate reaching sunset. delegate()->SetFakeNow(TimeOfDay(20 * 60)); // Now is 8:00 PM. - controller->timer().user_task().Run(); + controller->timer()->FireNow(); EXPECT_TRUE(controller->GetEnabled()); TestCompositorsTemperature(controller->GetColorTemperature()); EXPECT_EQ(NightLightController::AnimationDuration::kLong, controller->last_animation_duration()); // Timer is running scheduling the end at sunrise. - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(9), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); // Simulate reaching sunrise. delegate()->SetFakeNow(TimeOfDay(5 * 60)); // Now is 5:00 AM. - controller->timer().user_task().Run(); + controller->timer()->FireNow(); EXPECT_FALSE(controller->GetEnabled()); TestCompositorsTemperature(0.0f); EXPECT_EQ(NightLightController::AnimationDuration::kLong, controller->last_animation_duration()); // Timer is running scheduling the start at the next sunset. - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(15), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); } // Tests the behavior of the sunset to sunrise automatic schedule type when the @@ -599,21 +598,21 @@ NightLightController::ScheduleType::kSunsetToSunrise); EXPECT_FALSE(controller->GetEnabled()); TestCompositorsTemperature(0.0f); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(4), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); // Simulate reaching sunset. delegate()->SetFakeNow(TimeOfDay(20 * 60)); // Now is 8:00 PM. - controller->timer().user_task().Run(); + controller->timer()->FireNow(); EXPECT_TRUE(controller->GetEnabled()); TestCompositorsTemperature(controller->GetColorTemperature()); EXPECT_EQ(NightLightController::AnimationDuration::kLong, controller->last_animation_duration()); // Timer is running scheduling the end at sunrise. - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(8), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); // Now simulate user changing position. // Position 2 sunset and sunrise times. @@ -630,21 +629,21 @@ // changed. EXPECT_TRUE(controller->GetEnabled()); TestCompositorsTemperature(controller->GetColorTemperature()); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(7), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); // Simulate reaching sunrise. delegate()->SetFakeNow(TimeOfDay(3 * 60)); // Now is 5:00 AM. - controller->timer().user_task().Run(); + controller->timer()->FireNow(); EXPECT_FALSE(controller->GetEnabled()); TestCompositorsTemperature(0.0f); EXPECT_EQ(NightLightController::AnimationDuration::kLong, controller->last_animation_duration()); // Timer is running scheduling the start at the next sunset. - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); EXPECT_EQ(base::TimeDelta::FromHours(14), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); } // Tests that on device resume from sleep, the NightLight status is updated @@ -668,10 +667,10 @@ EXPECT_FALSE(controller->GetEnabled()); TestCompositorsTemperature(0.0f); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); // NightLight should start in 2 hours. EXPECT_EQ(base::TimeDelta::FromHours(2), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); // Now simulate that the device was suspended for 3 hours, and the time now // is 7:00 PM when the devices was resumed. Expect that NightLight turns on. @@ -680,10 +679,10 @@ EXPECT_TRUE(controller->GetEnabled()); TestCompositorsTemperature(0.4f); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); // NightLight should end in 3 hours. EXPECT_EQ(base::TimeDelta::FromHours(3), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); } // The following tests ensure that the NightLight schedule is correctly @@ -711,10 +710,10 @@ EXPECT_TRUE(controller->GetEnabled()); TestCompositorsTemperature(0.4f); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); // NightLight should end in two hours. EXPECT_EQ(base::TimeDelta::FromHours(2), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); } // Case 2: "Now" is between "end" and "start". @@ -737,10 +736,10 @@ EXPECT_FALSE(controller->GetEnabled()); TestCompositorsTemperature(0.0f); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); // NightLight should start in 15 hours. EXPECT_EQ(base::TimeDelta::FromHours(15), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); } // Case 3: "Now" is greater than both "start" and "end". @@ -763,10 +762,10 @@ EXPECT_TRUE(controller->GetEnabled()); TestCompositorsTemperature(0.4f); - EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_TRUE(controller->timer()->IsRunning()); // NightLight should end in 5 hours. EXPECT_EQ(base::TimeDelta::FromHours(5), - controller->timer().GetCurrentDelay()); + controller->timer()->GetCurrentDelay()); } // Fixture for testing behavior of Night Light when displays support hardware
diff --git a/ash/system/power/power_button_controller_test_api.cc b/ash/system/power/power_button_controller_test_api.cc index 94287a7..b2d2dfa 100644 --- a/ash/system/power/power_button_controller_test_api.cc +++ b/ash/system/power/power_button_controller_test_api.cc
@@ -28,9 +28,7 @@ if (!controller_->pre_shutdown_timer_.IsRunning()) return false; - base::Closure task = controller_->pre_shutdown_timer_.user_task(); - controller_->pre_shutdown_timer_.Stop(); - task.Run(); + controller_->pre_shutdown_timer_.FireNow(); return true; } @@ -42,9 +40,7 @@ if (!controller_->power_button_menu_timer_.IsRunning()) return false; - base::Closure task = controller_->power_button_menu_timer_.user_task(); - controller_->power_button_menu_timer_.Stop(); - task.Run(); + controller_->power_button_menu_timer_.FireNow(); return true; }
diff --git a/ash/system/power/power_button_screenshot_controller_test_api.cc b/ash/system/power/power_button_screenshot_controller_test_api.cc index 8b19033..4f58af4c 100644 --- a/ash/system/power/power_button_screenshot_controller_test_api.cc +++ b/ash/system/power/power_button_screenshot_controller_test_api.cc
@@ -21,9 +21,7 @@ if (!controller_->volume_down_timer_.IsRunning()) return false; - base::Closure task = controller_->volume_down_timer_.user_task(); - controller_->volume_down_timer_.Stop(); - task.Run(); + controller_->volume_down_timer_.FireNow(); return true; }
diff --git a/ash/system/tray/tray_detailed_view.cc b/ash/system/tray/tray_detailed_view.cc index 02d41736..d84ac971 100644 --- a/ash/system/tray/tray_detailed_view.cc +++ b/ash/system/tray/tray_detailed_view.cc
@@ -469,4 +469,9 @@ return height(); } +void TrayDetailedView::RequestFocus() { + if (back_button_) + back_button_->RequestFocus(); +} + } // namespace ash
diff --git a/ash/system/tray/tray_detailed_view.h b/ash/system/tray/tray_detailed_view.h index f0ec573b..4b5cf9b1 100644 --- a/ash/system/tray/tray_detailed_view.h +++ b/ash/system/tray/tray_detailed_view.h
@@ -52,6 +52,7 @@ // views::View: void Layout() override; int GetHeightForWidth(int width) const override; + void RequestFocus() override; // Exposes the layout manager of this view to give control to subclasses. views::BoxLayout* box_layout() { return box_layout_; }
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc index f2332bc..5e9b338 100644 --- a/ash/system/unified/unified_system_tray_controller.cc +++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -367,8 +367,8 @@ animation_->Reset(1.0); UpdateExpandedAmount(); - unified_view_->SetDetailedView(controller->CreateView()); unified_view_->SaveFeaturePodFocus(); + unified_view_->SetDetailedView(controller->CreateView()); detailed_view_controller_ = std::move(controller); }
diff --git a/ash/system/unified/unified_system_tray_view.cc b/ash/system/unified/unified_system_tray_view.cc index ffb1d80e..7c0d87ac 100644 --- a/ash/system/unified/unified_system_tray_view.cc +++ b/ash/system/unified/unified_system_tray_view.cc
@@ -199,6 +199,8 @@ detailed_view_container_->SetPreferredSize(system_tray_size); detailed_view->InvalidateLayout(); Layout(); + + detailed_view->RequestFocus(); } void UnifiedSystemTrayView::ResetDetailedView() {
diff --git a/ash/wm/immersive_fullscreen_controller_unittest.cc b/ash/wm/immersive_fullscreen_controller_unittest.cc index 9702cbf..e3f2edc5 100644 --- a/ash/wm/immersive_fullscreen_controller_unittest.cc +++ b/ash/wm/immersive_fullscreen_controller_unittest.cc
@@ -212,8 +212,7 @@ // top-of-window views synchronously if the mouse is hovered at the top of // the screen. if (controller()->top_edge_hover_timer_.IsRunning()) { - controller()->top_edge_hover_timer_.user_task().Run(); - controller()->top_edge_hover_timer_.Stop(); + controller()->top_edge_hover_timer_.FireNow(); } }
diff --git a/base/timer/timer.cc b/base/timer/timer.cc index 99cd83933..0c26971 100644 --- a/base/timer/timer.cc +++ b/base/timer/timer.cc
@@ -265,4 +265,15 @@ // No more member accesses here: |this| could be deleted at this point. } +void OneShotTimer::FireNow() { + DCHECK(origin_sequence_checker_.CalledOnValidSequence()); + DCHECK(!task_runner_) << "FireNow() is incompatible with SetTaskRunner()"; + DCHECK(IsRunning()); + + OnceClosure task = user_task(); + Stop(); + DCHECK(!user_task()); + std::move(task).Run(); +} + } // namespace base
diff --git a/base/timer/timer.h b/base/timer/timer.h index bbd1f7fe..14ba3e3 100644 --- a/base/timer/timer.h +++ b/base/timer/timer.h
@@ -165,6 +165,15 @@ const Location& posted_from() const { return posted_from_; } + // The task runner on which the task should be scheduled. If it is null, the + // task runner for the current sequence will be used. + scoped_refptr<SequencedTaskRunner> task_runner_; + + // Timer isn't thread-safe and must only be used on its origin sequence + // (sequence on which it was started). Once fully Stop()'ed it may be + // destroyed or restarted on another sequence. + SequenceChecker origin_sequence_checker_; + private: friend class BaseTimerTaskInternal; @@ -189,10 +198,6 @@ // at |scheduled_run_time_|. BaseTimerTaskInternal* scheduled_task_; - // The task runner on which the task should be scheduled. If it is null, the - // task runner for the current sequence will be used. - scoped_refptr<SequencedTaskRunner> task_runner_; - // Location in user code. Location posted_from_; // Delay requested by user. @@ -213,11 +218,6 @@ // if the task must be run immediately. TimeTicks desired_run_time_; - // Timer isn't thread-safe and must only be used on its origin sequence - // (sequence on which it was started). Once fully Stop()'ed it may be - // destroyed or restarted on another sequence. - SequenceChecker origin_sequence_checker_; - // Repeating timers automatically post the task again before calling the task // callback. const bool is_repeating_; @@ -236,11 +236,15 @@ //----------------------------------------------------------------------------- // A simple, one-shot timer. See usage notes at the top of the file. -class OneShotTimer : public Timer { +class BASE_EXPORT OneShotTimer : public Timer { public: OneShotTimer() : OneShotTimer(nullptr) {} explicit OneShotTimer(const TickClock* tick_clock) : Timer(false, false, tick_clock) {} + + // Run the scheduled task immediately, and stop the timer. The timer needs to + // be running. + void FireNow(); }; //-----------------------------------------------------------------------------
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml index 27287dd..6e5562a 100644 --- a/build/android/lint/suppressions.xml +++ b/build/android/lint/suppressions.xml
@@ -157,7 +157,7 @@ <ignore regexp="tools/android/push_apps_to_background/res"/> <ignore regexp="ui/android/java/res"/> <!-- crbug.com/457918 is tracking missing assets --> - <ignore regexp="components/web_contents_delegate_android/java/res"/> + <ignore regexp="components/embedder_support/android/java/res"/> </issue> <issue id="ImpliedQuantity" severity="Error"> <ignore regexp="chrome/android/chrome_strings_grd"/>
diff --git a/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/cc/mojo_embedder/async_layer_tree_frame_sink.cc index a51d645..2445fe6 100644 --- a/cc/mojo_embedder/async_layer_tree_frame_sink.cc +++ b/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -152,16 +152,18 @@ else hit_test_region_list = client_->BuildHitTestData(); - last_submitted_local_surface_id_ = local_surface_id_; - last_submitted_device_scale_factor_ = frame.device_scale_factor(); - last_submitted_size_in_pixels_ = frame.size_in_pixels(); + if (last_submitted_local_surface_id_ != local_surface_id_) { + last_submitted_local_surface_id_ = local_surface_id_; + last_submitted_device_scale_factor_ = frame.device_scale_factor(); + last_submitted_size_in_pixels_ = frame.size_in_pixels(); - TRACE_EVENT_WITH_FLOW2( - TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), - "LocalSurfaceId.Submission.Flow", - TRACE_ID_GLOBAL(local_surface_id_.submission_trace_id()), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", - "SubmitCompositorFrame", "surface_id", local_surface_id_.ToString()); + TRACE_EVENT_WITH_FLOW2( + TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), + "LocalSurfaceId.Submission.Flow", + TRACE_ID_GLOBAL(local_surface_id_.submission_trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", + "SubmitCompositorFrame", "surface_id", local_surface_id_.ToString()); + } compositor_frame_sink_ptr_->SubmitCompositorFrame( local_surface_id_, std::move(frame), std::move(hit_test_region_list),
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index c42da9a..814f025 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -1217,7 +1217,7 @@ "LocalSurfaceId.Submission.Flow", TRACE_ID_GLOBAL(local_surface_id_from_parent.submission_trace_id()), TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", - "SetLocalSurfaceIdFromParent", "surface_id", + "SetLocalSurfaceIdFromParent", "local_surface_id", local_surface_id_from_parent.ToString()); local_surface_id_from_parent_ = local_surface_id_from_parent; has_pushed_local_surface_id_from_parent_ = false;
diff --git a/chrome/VERSION b/chrome/VERSION index a42e3bef..20b2754 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=69 MINOR=0 -BUILD=3489 +BUILD=3490 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 486b4fb8..c967ac7d 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -236,6 +236,7 @@ "//components/download/public/common:public_java", "//components/embedder_support/android:content_view_java", "//components/embedder_support/android:media_java", + "//components/embedder_support/android:web_contents_delegate_java", "//components/feature_engagement:feature_engagement_java", "//components/gcm_driver/android:gcm_driver_java", "//components/gcm_driver/instance_id/android:instance_id_driver_java", @@ -255,7 +256,6 @@ "//components/variations/android:variations_java", "//components/version_info/android:version_constants_java", "//components/viz/service:service_java", - "//components/web_contents_delegate_android:web_contents_delegate_android_java", "//components/web_restrictions:provider_java", "//content/public/android:content_java", "//device/gamepad:java", @@ -580,6 +580,7 @@ "//components/crash/android:javatests", "//components/dom_distiller/core/android:dom_distiller_core_java", "//components/download/internal/background_service:internal_java", + "//components/embedder_support/android:web_contents_delegate_java", "//components/feature_engagement:feature_engagement_java", "//components/gcm_driver/android:gcm_driver_java", "//components/gcm_driver/instance_id/android:instance_id_driver_java", @@ -603,7 +604,6 @@ "//components/sync/android:sync_java", "//components/sync/android:sync_javatests", "//components/url_formatter/android:url_formatter_java", - "//components/web_contents_delegate_android:web_contents_delegate_android_java", "//components/web_restrictions:provider_java", "//content/public/android:content_java", "//content/public/test/android:content_java_test_support",
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS index 088d9da..58b1c80 100644 --- a/chrome/android/java/DEPS +++ b/chrome/android/java/DEPS
@@ -6,6 +6,7 @@ "+components/crash/android/java", "+components/dom_distiller/content/browser/android/java/src/org/chromium/components/dom_distiller/content", "+components/dom_distiller/core/android/java/src/org/chromium/components/dom_distiller/core", + "+components/embedder_support/android/delegate", "+components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement", "+components/gcm_driver/android/java/src/org/chromium/components/gcm_driver", "+components/location/android/java", @@ -14,7 +15,6 @@ "+components/offline_items_collection/core/android/java", "+components/payments/content/android/java/src/org/chromium/components/payments", "+components/sync/android/java/src/org/chromium/components/sync", - "+components/web_contents_delegate_android", "+components/web_restrictions", "-content/public/android",
diff --git a/chrome/android/java/res/drawable-hdpi/ic_help_and_feedback.png b/chrome/android/java/res/drawable-hdpi/ic_help_and_feedback.png deleted file mode 100644 index 675e2f51..0000000 --- a/chrome/android/java/res/drawable-hdpi/ic_help_and_feedback.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/ic_help_white_24dp.png b/chrome/android/java/res/drawable-hdpi/ic_help_white_24dp.png deleted file mode 100644 index 2287fad..0000000 --- a/chrome/android/java/res/drawable-hdpi/ic_help_white_24dp.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/ic_help_and_feedback.png b/chrome/android/java/res/drawable-mdpi/ic_help_and_feedback.png deleted file mode 100644 index 6933113..0000000 --- a/chrome/android/java/res/drawable-mdpi/ic_help_and_feedback.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/ic_help_white_24dp.png b/chrome/android/java/res/drawable-mdpi/ic_help_white_24dp.png deleted file mode 100644 index db69962..0000000 --- a/chrome/android/java/res/drawable-mdpi/ic_help_white_24dp.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/ic_help_and_feedback.png b/chrome/android/java/res/drawable-xhdpi/ic_help_and_feedback.png deleted file mode 100644 index f5eb9a32..0000000 --- a/chrome/android/java/res/drawable-xhdpi/ic_help_and_feedback.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/ic_help_white_24dp.png b/chrome/android/java/res/drawable-xhdpi/ic_help_white_24dp.png deleted file mode 100644 index 212a6369..0000000 --- a/chrome/android/java/res/drawable-xhdpi/ic_help_white_24dp.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/ic_help_and_feedback.png b/chrome/android/java/res/drawable-xxhdpi/ic_help_and_feedback.png deleted file mode 100644 index 316a6302..0000000 --- a/chrome/android/java/res/drawable-xxhdpi/ic_help_and_feedback.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/ic_help_white_24dp.png b/chrome/android/java/res/drawable-xxhdpi/ic_help_white_24dp.png deleted file mode 100644 index 04ab158..0000000 --- a/chrome/android/java/res/drawable-xxhdpi/ic_help_white_24dp.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/ic_help_and_feedback.png b/chrome/android/java/res/drawable-xxxhdpi/ic_help_and_feedback.png deleted file mode 100644 index d4a5579..0000000 --- a/chrome/android/java/res/drawable-xxxhdpi/ic_help_and_feedback.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/ic_help_white_24dp.png b/chrome/android/java/res/drawable-xxxhdpi/ic_help_white_24dp.png deleted file mode 100644 index 64442a5e..0000000 --- a/chrome/android/java/res/drawable-xxxhdpi/ic_help_white_24dp.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable/ic_help_and_feedback.xml b/chrome/android/java/res/drawable/ic_help_and_feedback.xml new file mode 100644 index 0000000..c3f3504 --- /dev/null +++ b/chrome/android/java/res/drawable/ic_help_and_feedback.xml
@@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + tools:targetApi="21" + android:width="20dp" + android:height="20dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + + <path + android:fillColor="@color/black_alpha_65" + android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13, + 19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17, + -2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0, + -2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/> +</vector>
diff --git a/chrome/android/java/res/layout/add_languages_main.xml b/chrome/android/java/res/layout/add_languages_main.xml index 4d77cbd..7996792 100644 --- a/chrome/android/java/res/layout/add_languages_main.xml +++ b/chrome/android/java/res/layout/add_languages_main.xml
@@ -3,8 +3,16 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<android.support.v7.widget.RecyclerView +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/language_list" android:layout_width="match_parent" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" > + + <android.support.v7.widget.RecyclerView + android:id="@+id/language_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <include layout="@layout/preferences_action_bar_shadow"/> + +</FrameLayout>
diff --git a/chrome/android/java/res/layout/autofill_editor_base.xml b/chrome/android/java/res/layout/autofill_editor_base.xml index be4ceac..e42d42f 100644 --- a/chrome/android/java/res/layout/autofill_editor_base.xml +++ b/chrome/android/java/res/layout/autofill_editor_base.xml
@@ -6,21 +6,30 @@ <!-- Base layout for Autofill editors. Editor fields are expected to be added to the LinearLayout inside of the ScrollView. --> -<org.chromium.chrome.browser.widget.FadingEdgeScrollView +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/scroll_view" + xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent" - android:fillViewport="true" > + android:layout_height="match_parent" > - <!-- All fields go into this LinearLayout. Note that some horizontal margins are set, but the - embedded views are responsible for their top margins. --> - <LinearLayout - android:id="@+id/content" + <org.chromium.chrome.browser.widget.FadingEdgeScrollView + android:id="@+id/scroll_view" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingStart="@dimen/pref_autofill_content_spacing" - android:paddingEnd="@dimen/pref_autofill_content_spacing" - android:orientation="vertical" /> + android:layout_height="match_parent" + android:fillViewport="true" > -</org.chromium.chrome.browser.widget.FadingEdgeScrollView> + <!-- All fields go into this LinearLayout. Note that some horizontal margins are set, but + the embedded views are responsible for their top margins. --> + <LinearLayout + android:id="@+id/content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="@dimen/pref_autofill_content_spacing" + android:paddingEnd="@dimen/pref_autofill_content_spacing" + android:orientation="vertical" /> + + </org.chromium.chrome.browser.widget.FadingEdgeScrollView> + + <include layout="@layout/preferences_action_bar_shadow"/> + +</FrameLayout>
diff --git a/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml b/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml index c3397d7..4663206 100644 --- a/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml +++ b/chrome/android/java/res/layout/bookmark_add_edit_folder_activity.xml
@@ -67,7 +67,7 @@ <View android:id="@+id/shadow" android:layout_width="match_parent" - android:layout_height="4dp" + android:layout_height="@dimen/selectable_list_toolbar_shadow_height" android:layout_marginTop="@dimen/toolbar_height_no_shadow" android:background="@drawable/bookmark_title_bar_shadow" android:visibility="gone" />
diff --git a/chrome/android/java/res/layout/bookmark_edit.xml b/chrome/android/java/res/layout/bookmark_edit.xml index 1648d5d..c21d435 100644 --- a/chrome/android/java/res/layout/bookmark_edit.xml +++ b/chrome/android/java/res/layout/bookmark_edit.xml
@@ -83,7 +83,7 @@ <View android:id="@+id/shadow" android:layout_width="match_parent" - android:layout_height="4dp" + android:layout_height="@dimen/selectable_list_toolbar_shadow_height" android:layout_marginTop="@dimen/toolbar_height_no_shadow" android:background="@drawable/bookmark_title_bar_shadow" android:visibility="gone" />
diff --git a/chrome/android/java/res/layout/bookmark_folder_select_activity.xml b/chrome/android/java/res/layout/bookmark_folder_select_activity.xml index 75dfa95e..a80604f 100644 --- a/chrome/android/java/res/layout/bookmark_folder_select_activity.xml +++ b/chrome/android/java/res/layout/bookmark_folder_select_activity.xml
@@ -24,7 +24,7 @@ <View android:id="@+id/shadow" android:layout_width="match_parent" - android:layout_height="4dp" + android:layout_height="@dimen/selectable_list_toolbar_shadow_height" android:layout_marginTop="@dimen/toolbar_height_no_shadow" android:background="@drawable/bookmark_title_bar_shadow" android:visibility="gone" />
diff --git a/chrome/android/java/res/layout/clear_browsing_data_tabs.xml b/chrome/android/java/res/layout/clear_browsing_data_tabs.xml index ff3069f..8da6de0 100644 --- a/chrome/android/java/res/layout/clear_browsing_data_tabs.xml +++ b/chrome/android/java/res/layout/clear_browsing_data_tabs.xml
@@ -13,8 +13,7 @@ <android.support.design.widget.AppBarLayout android:layout_width="match_parent" - android:layout_height="wrap_content" - android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> + android:layout_height="wrap_content" > <!-- RTL is handled manually in ClearBrowsingDataTabsFragment because it is not working correctly with a ViewPager --> @@ -23,6 +22,8 @@ android:layoutDirection="ltr" android:layout_width="match_parent" android:layout_height="wrap_content" + app:tabTextColor="@color/disabled_text_color" + app:tabSelectedTextColor="@color/clear_browsing_data_selected_tab_color" app:tabMode="fixed" app:tabMaxWidth="0dp" app:tabGravity="fill" />
diff --git a/chrome/android/java/res/layout/homepage_editor.xml b/chrome/android/java/res/layout/homepage_editor.xml index 24a7230..3dad103 100644 --- a/chrome/android/java/res/layout/homepage_editor.xml +++ b/chrome/android/java/res/layout/homepage_editor.xml
@@ -3,51 +3,60 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent" - android:fillViewport="true" > + android:layout_height="match_parent" > - <LinearLayout + <ScrollView android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:focusableInTouchMode="true" > + android:layout_height="match_parent" + android:id="@+id/scroll_view" + android:fillViewport="true" > - <org.chromium.chrome.browser.widget.CompatibilityTextInputLayout - android:id="@+id/homepage_url" - style="@style/PreferenceScreenLayout" + <LinearLayout android:layout_width="match_parent" - android:layout_height="wrap_content" > - <EditText - android:id="@+id/homepage_url_edit" + android:layout_height="wrap_content" + android:orientation="vertical" + android:focusableInTouchMode="true" > + + <org.chromium.chrome.browser.widget.CompatibilityTextInputLayout + android:id="@+id/homepage_url" + style="@style/PreferenceScreenLayout" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:inputType="textUri" - android:singleLine="true" - android:hint="@string/options_homepage_edit_label" /> - </org.chromium.chrome.browser.widget.CompatibilityTextInputLayout> + android:layout_height="wrap_content" > + <EditText + android:id="@+id/homepage_url_edit" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="textUri" + android:singleLine="true" + android:hint="@string/options_homepage_edit_label" /> + </org.chromium.chrome.browser.widget.CompatibilityTextInputLayout> - <Space style="@style/ButtonBarTopSpacer" /> - <View style="@style/ButtonBarTopDivider" /> + <Space style="@style/ButtonBarTopSpacer" /> + <View style="@style/ButtonBarTopDivider" /> - <LinearLayout style="@style/ButtonBar" > - <Button - android:id="@+id/homepage_reset" - style="@style/ButtonBarButton" - android:text="@string/reset" /> + <LinearLayout style="@style/ButtonBar" > + <Button + android:id="@+id/homepage_reset" + style="@style/ButtonBarButton" + android:text="@string/reset" /> - <Button - android:id="@+id/homepage_cancel" - style="@style/ButtonBarButton" - android:text="@string/cancel" /> + <Button + android:id="@+id/homepage_cancel" + style="@style/ButtonBarButton" + android:text="@string/cancel" /> - <Button - android:id="@+id/homepage_save" - style="@style/ButtonBarButton" - android:text="@string/save" /> + <Button + android:id="@+id/homepage_save" + style="@style/ButtonBarButton" + android:text="@string/save" /> + </LinearLayout> </LinearLayout> - </LinearLayout> + </ScrollView> -</ScrollView> + <include layout="@layout/preferences_action_bar_shadow"/> + +</FrameLayout>
diff --git a/chrome/android/java/res/layout/password_entry_editor_interactive.xml b/chrome/android/java/res/layout/password_entry_editor_interactive.xml index 8200500e..3a100a9 100644 --- a/chrome/android/java/res/layout/password_entry_editor_interactive.xml +++ b/chrome/android/java/res/layout/password_entry_editor_interactive.xml
@@ -3,92 +3,101 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent" - android:fillViewport="true" > + android:layout_height="match_parent" > - <LinearLayout - android:id="@+id/password_entry_editor_interactive" + <ScrollView android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:paddingStart="15dp" - android:title="@string/password_entry_editor_title"> - - <TextView - android:text="@string/password_entry_editor_site_title" - android:layout_marginTop="15dp" - style="@style/PasswordEntryName" /> - - <include android:id="@+id/url_row" - layout="@layout/password_entry_editor_copyable_row"/> - - <TextView - android:text="@string/password_entry_editor_username_title" - android:layout_marginTop="10dp" - style="@style/PasswordEntryName" /> - - <include android:id="@+id/username_row" - layout="@layout/password_entry_editor_copyable_row"/> - - <TextView - android:text="@string/password_entry_editor_password" - android:id="@+id/password_title" - android:layout_marginTop="10dp" - style="@style/PasswordEntryName" /> + android:layout_height="match_parent" + android:id="@+id/scroll_view" + android:fillViewport="true" > <LinearLayout + android:id="@+id/password_entry_editor_interactive" android:layout_width="match_parent" android:layout_height="wrap_content" - android:id="@+id/password_data" - android:orientation="horizontal"> + android:orientation="vertical" + android:paddingStart="15dp" + android:title="@string/password_entry_editor_title"> <TextView - android:id="@+id/password_entry_editor_password" + android:text="@string/password_entry_editor_site_title" + android:layout_marginTop="15dp" + style="@style/PasswordEntryName" /> + + <include android:id="@+id/url_row" + layout="@layout/password_entry_editor_copyable_row"/> + + <TextView + android:text="@string/password_entry_editor_username_title" + android:layout_marginTop="10dp" + style="@style/PasswordEntryName" /> + + <include android:id="@+id/username_row" + layout="@layout/password_entry_editor_copyable_row"/> + + <TextView + android:text="@string/password_entry_editor_password" + android:id="@+id/password_title" + android:layout_marginTop="10dp" + style="@style/PasswordEntryName" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/password_data" + android:orientation="horizontal"> + + <TextView + android:id="@+id/password_entry_editor_password" + android:textColor="@color/default_text_color" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginTop="15dp" + android:layout_weight="1" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <org.chromium.chrome.browser.widget.TintedImageButton + android:id="@+id/password_entry_editor_view_password" + android:background="@null" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:layout_marginTop="15dp" + android:layout_marginEnd="15dp" + app:srcCompat="@drawable/ic_visibility_black" + app:chrometint="@color/dark_mode_tint" + android:contentDescription="@string/password_entry_editor_view_stored_password" + style="?android:attr/buttonStyleSmall" /> + + <org.chromium.chrome.browser.widget.TintedImageButton + android:id="@+id/password_entry_editor_copy_password" + android:background="@null" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:layout_marginTop="15dp" + android:layout_marginEnd="15dp" + app:chrometint="@color/dark_mode_tint" + android:contentDescription="@string/password_entry_editor_copy_stored_password" + style="?android:attr/buttonStyleSmall" /> + </LinearLayout> + + <TextView + android:id="@+id/passwords_link" + android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@color/default_text_color" - android:layout_width="0dp" + android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="15dp" - android:layout_weight="1" - android:textAppearance="?android:attr/textAppearanceMedium" /> + android:visibility="gone"/> - <org.chromium.chrome.browser.widget.TintedImageButton - android:id="@+id/password_entry_editor_view_password" - android:background="@null" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="end" - android:layout_marginTop="15dp" - android:layout_marginEnd="15dp" - app:srcCompat="@drawable/ic_visibility_black" - app:chrometint="@color/dark_mode_tint" - android:contentDescription="@string/password_entry_editor_view_stored_password" - style="?android:attr/buttonStyleSmall" /> - - <org.chromium.chrome.browser.widget.TintedImageButton - android:id="@+id/password_entry_editor_copy_password" - android:background="@null" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="end" - android:layout_marginTop="15dp" - android:layout_marginEnd="15dp" - app:chrometint="@color/dark_mode_tint" - android:contentDescription="@string/password_entry_editor_copy_stored_password" - style="?android:attr/buttonStyleSmall" /> </LinearLayout> + </ScrollView> - <TextView - android:id="@+id/passwords_link" - android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="@color/default_text_color" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginTop="15dp" - android:visibility="gone"/> + <include layout="@layout/preferences_action_bar_shadow"/> - </LinearLayout> - -</ScrollView> +</FrameLayout>
diff --git a/chrome/android/java/res/layout/password_entry_exception.xml b/chrome/android/java/res/layout/password_entry_exception.xml index 445360de..cffa451 100644 --- a/chrome/android/java/res/layout/password_entry_exception.xml +++ b/chrome/android/java/res/layout/password_entry_exception.xml
@@ -3,26 +3,37 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent" - android:fillViewport="true" > + android:layout_height="match_parent" > - <LinearLayout - android:id="@+id/password_entry_editor_interactive" + <ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:paddingStart="15dp" - android:title="@string/password_entry_editor_title"> + android:layout_height="match_parent" + android:id="@+id/scroll_view" + android:fillViewport="true" > - <TextView - android:text="@string/password_entry_editor_site_title" - android:layout_marginTop="15dp" - style="@style/PasswordEntryName" /> + <LinearLayout + android:id="@+id/password_entry_editor_interactive" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingStart="15dp" + android:title="@string/password_entry_editor_title"> - <include android:id="@+id/url_row" - layout="@layout/password_entry_editor_copyable_row"/> - </LinearLayout> + <TextView + android:text="@string/password_entry_editor_site_title" + android:layout_marginTop="15dp" + style="@style/PasswordEntryName" /> -</ScrollView> + <include android:id="@+id/url_row" + layout="@layout/password_entry_editor_copyable_row"/> + + </LinearLayout> + </ScrollView> + + <include layout="@layout/preferences_action_bar_shadow"/> + +</FrameLayout>
diff --git a/chrome/android/java/res/layout/payment_request_editor.xml b/chrome/android/java/res/layout/payment_request_editor.xml index c63bc4d..1c48ab9 100644 --- a/chrome/android/java/res/layout/payment_request_editor.xml +++ b/chrome/android/java/res/layout/payment_request_editor.xml
@@ -15,8 +15,9 @@ android:layout_height="?attr/actionBarSize" android:layout_alignParentTop="true" android:layout_alignParentStart="true" - android:layout_alignParentEnd="true" - android:background="@color/dark_action_bar_color" /> + android:layout_alignParentEnd="true" /> + + <include layout="@layout/preferences_action_bar_shadow" /> <!-- All the page content in scrollable form. --> <org.chromium.chrome.browser.widget.FadingEdgeScrollView @@ -38,13 +39,4 @@ </org.chromium.chrome.browser.widget.FadingEdgeScrollView> - <!-- Shadow overlaps the FadingEdgeScrollView. --> - <org.chromium.chrome.browser.widget.FadingShadowView - android:id="@+id/shadow" - android:layout_width="match_parent" - android:layout_height="@dimen/action_bar_shadow_height" - android:layout_below="@id/action_bar" - android:layout_alignParentStart="true" - android:layout_alignParentEnd="true" /> - </RelativeLayout>
diff --git a/chrome/android/java/res/layout/preferences_action_bar_shadow.xml b/chrome/android/java/res/layout/preferences_action_bar_shadow.xml new file mode 100644 index 0000000..9b326a91 --- /dev/null +++ b/chrome/android/java/res/layout/preferences_action_bar_shadow.xml
@@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. --> + +<!-- The shadow found below the action bar in settings.--> +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" > + + <ImageView + android:id="@+id/shadow" + android:layout_width="match_parent" + android:layout_height="@dimen/action_bar_shadow_height" + android:background="@drawable/modern_toolbar_shadow" + android:visibility="gone" + tools:ignore="ContentDescription" /> + +</merge> \ No newline at end of file
diff --git a/chrome/android/java/res/menu/prefeditor_editor_menu.xml b/chrome/android/java/res/menu/prefeditor_editor_menu.xml index 56c11153..99931dc 100644 --- a/chrome/android/java/res/menu/prefeditor_editor_menu.xml +++ b/chrome/android/java/res/menu/prefeditor_editor_menu.xml
@@ -14,7 +14,7 @@ <item android:id="@+id/help_menu_id" - android:icon="@drawable/ic_help_white_24dp" + android:icon="@drawable/ic_help_and_feedback" android:title="@string/help" app:showAsAction="ifRoom" />
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml index d07b4d5..e6e8c7a 100644 --- a/chrome/android/java/res/values-v17/styles.xml +++ b/chrome/android/java/res/values-v17/styles.xml
@@ -155,6 +155,11 @@ <item name="floatLabelPaddingLeft">@dimen/pref_autofill_field_horizontal_padding</item> <item name="floatLabelPaddingRight">@dimen/pref_autofill_field_horizontal_padding</item> <item name="floatLabelPaddingTop">@dimen/pref_autofill_field_top_margin</item> + <item name="actionBarStyle">@style/PreferenceActionBarModern</item> + <item name="android:windowContentOverlay">@null</item> + </style> + <style name="PreferenceActionBarModern" parent="@style/Widget.AppCompat.Light.ActionBar.Solid"> + <item name="titleTextStyle">@style/BlackHeadline1</item> </style> <style name="PreferenceTextAppearanceMedium"> <item name="android:textSize">18sp</item> @@ -224,12 +229,12 @@ <item name="android:importantForAccessibility">no</item> </style> - <style name="ThemeWithActionBarBase" parent="Theme.AppCompat.Light.DarkActionBar"> + <style name="ThemeWithActionBarBase" parent="Theme.AppCompat.Light"> <item name="android:windowBackground">@drawable/action_bar_activity_bg</item> <!-- Action bar color --> - <item name="colorPrimary">@color/dark_action_bar_color</item> + <item name="colorPrimary">@color/modern_primary_color</item> <!-- Status bar color --> - <item name="colorPrimaryDark">#161e21</item> + <item name="colorPrimaryDark">@android:color/black</item> <!-- Color of checkboxes, switches, buttons, etc. --> <item name="colorAccent">@color/pref_accent_color</item> <!-- Button style -->
diff --git a/chrome/android/java/res/values-v21/styles.xml b/chrome/android/java/res/values-v21/styles.xml index 753ec3b4..52b7bc1 100644 --- a/chrome/android/java/res/values-v21/styles.xml +++ b/chrome/android/java/res/values-v21/styles.xml
@@ -14,6 +14,7 @@ <item name="floatLabelPaddingLeft">@dimen/pref_autofill_field_horizontal_padding</item> <item name="floatLabelPaddingRight">@dimen/pref_autofill_field_horizontal_padding</item> <item name="floatLabelPaddingTop">@dimen/pref_autofill_field_top_margin</item> + <item name="actionBarStyle">@style/PreferenceActionBarModern</item> </style> <style name="PreferencesDialogTheme" parent="@android:style/Theme.Material.Light.Dialog.Alert"> <item name="android:colorAccent">@color/pref_accent_color</item>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml index 60479bb..943edfa2 100644 --- a/chrome/android/java/res/values/colors.xml +++ b/chrome/android/java/res/values/colors.xml
@@ -213,5 +213,6 @@ <color name="bottom_system_nav_divider_color">@color/black_alpha_12</color> <color name="search_box_hint">@color/black_alpha_54</color> <color name="contextual_suggestions_thumbnail_bg_color">#DADCE0</color> + <color name="clear_browsing_data_selected_tab_color">@color/modern_blue_600</color> </resources>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 4bd2cf4b..d393ade2 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -136,9 +136,6 @@ <dimen name="password_generation_horizontal_margin">10dp</dimen> <dimen name="password_generation_text_vertical_margin">12dp</dimen> - <!-- Search engine preference dimensions --> - <dimen name="search_engine_list_margin_top">6dp</dimen> - <!-- Minimum height/width for a touchable item --> <dimen name="min_touch_target_size">48dp</dimen> @@ -513,6 +510,7 @@ <dimen name="search_toolbar_modern_bg_lateral_inset">8dp</dimen> <dimen name="selectable_list_toolbar_nav_button_start_offset">4dp</dimen> <dimen name="selectable_list_search_icon_end_padding">4dp</dimen> + <dimen name="selectable_list_toolbar_shadow_height">4dp</dimen> <!-- Chrome Home dimensions --> <dimen name="chrome_home_min_full_half_distance">160dp</dimen>
diff --git a/chrome/android/java/res_vr/OWNERS b/chrome/android/java/res_vr/OWNERS index 460c9e34..bf69a62 100644 --- a/chrome/android/java/res_vr/OWNERS +++ b/chrome/android/java/res_vr/OWNERS
@@ -1,3 +1,5 @@ file://chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VR_JAVA_OWNERS + +# TEAM: xr-dev@chromium.org # COMPONENT: UI>Browser>VR # OS: Android
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index b92ac85..a3161b0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -562,7 +562,7 @@ public void onMenuVisibilityChanged(boolean isVisible) { if (isVisible && !isInOverviewMode()) { // The app menu badge should be removed the first time the menu is opened. - if (mToolbarManager.getToolbar().isShowingAppMenuUpdateBadge()) { + if (mToolbarManager.isShowingAppMenuUpdateBadge()) { mToolbarManager.removeAppMenuUpdateBadge(true); mCompositorViewHolder.requestRender(); } @@ -883,6 +883,8 @@ * @param color The color that the status bar should be set to. * @param isDefaultThemeColor Whether {@code color} is the default theme color. */ + // TODO(danielpark): Move status bar & status bar icon color logic into helper class. + // See crbug.com/855079. protected void setStatusBarColor(int color, boolean isDefaultThemeColor) { if (UiUtils.isSystemUiThemingDisabled()) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java index c79256b..01ff9994 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -19,10 +19,10 @@ import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager; import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid; import org.chromium.components.embedder_support.view.ContentView; import org.chromium.components.navigation_interception.InterceptNavigationDelegate; import org.chromium.components.navigation_interception.NavigationParams; -import org.chromium.components.web_contents_delegate_android.WebContentsDelegateAndroid; import org.chromium.content_public.browser.ContentVideoViewEmbedder; import org.chromium.content_public.browser.ContentViewCore; import org.chromium.content_public.browser.LoadUrlParams;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentWebContentsDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentWebContentsDelegate.java index e47771e..71e186f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentWebContentsDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/document/DocumentWebContentsDelegate.java
@@ -4,7 +4,7 @@ package org.chromium.chrome.browser.document; -import org.chromium.components.web_contents_delegate_android.WebContentsDelegateAndroid; +import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid; import org.chromium.content_public.browser.WebContents; /** @@ -48,4 +48,4 @@ private native long nativeInitialize(); private native void nativeAttachContents( long nativeDocumentWebContentsDelegate, WebContents webContents); -} \ No newline at end of file +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java index b3ada0a..aee2fbe 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java
@@ -165,11 +165,8 @@ */ public boolean isGooglePlayServicesMissing(final Context context) { final int resultCode = checkGooglePlayServicesAvailable(context); - if (resultCode == ConnectionResult.SERVICE_MISSING - || resultCode == ConnectionResult.SERVICE_INVALID) { - return true; - } - return false; + return (resultCode == ConnectionResult.SERVICE_MISSING + || resultCode == ConnectionResult.SERVICE_INVALID); } /** @@ -187,9 +184,7 @@ Context context = ContextUtils.getApplicationContext(); final int resultCode = checkGooglePlayServicesAvailable(context); recordConnectionResult(resultCode); - if (resultCode == ConnectionResult.SUCCESS) { - return true; - } + if (resultCode == ConnectionResult.SUCCESS) return true; // resultCode is some kind of error. Log.v(TAG, "Unable to use Google Play Services: %s", describeError(resultCode)); if (isUserRecoverableError(resultCode)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java index 3956339..c2c918c3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java
@@ -8,6 +8,7 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.support.annotation.IntDef; import com.google.android.gms.common.GoogleApiAvailability; @@ -15,6 +16,8 @@ import org.chromium.base.metrics.CachedMetrics.ActionEvent; import org.chromium.base.metrics.CachedMetrics.EnumeratedHistogramSample; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -44,15 +47,20 @@ private static final String ERROR_HANDLER_ACTION_HISTOGRAM_NAME = "GooglePlayServices.ErrorHandlerAction"; // Never remove or reorder histogram values. It is safe to append new values to the end. - private static final int ERROR_HANDLER_ACTION_SILENT = 0; - private static final int ERROR_HANDLER_ACTION_SYSTEM_NOTIFICATION = 1; - private static final int ERROR_HANDLER_ACTION_MODAL_DIALOG = 2; - private static final int ERROR_HANDLER_ACTION_IGNORED_AS_REDUNDANT = 3; - private static final int ERROR_HANDLER_ACTION_HISTOGRAM_BOUNDARY = 4; + @IntDef({ErrorHandlerAction.SILENT, ErrorHandlerAction.SYSTEM_NOTIFICATION, + ErrorHandlerAction.MODAL_DIALOG, ErrorHandlerAction.IGNORED_AS_REDUNDANT}) + @Retention(RetentionPolicy.SOURCE) + private @interface ErrorHandlerAction { + int SILENT = 0; + int SYSTEM_NOTIFICATION = 1; + int MODAL_DIALOG = 2; + int IGNORED_AS_REDUNDANT = 3; + int NUM_ENTRIES = 4; + } private static final EnumeratedHistogramSample sErrorHandlerActionHistogramSample = - new EnumeratedHistogramSample(ERROR_HANDLER_ACTION_HISTOGRAM_NAME, - ERROR_HANDLER_ACTION_HISTOGRAM_BOUNDARY); + new EnumeratedHistogramSample( + ERROR_HANDLER_ACTION_HISTOGRAM_NAME, ErrorHandlerAction.NUM_ENTRIES); private static final ActionEvent sModalDialogShownActionEvent = new ActionEvent("Signin_Android_GmsUserRecoverableDialogShown"); @@ -87,7 +95,7 @@ public static final class Silent extends UserRecoverableErrorHandler { @Override protected final void handle(final Context context, final int errorCode) { - sErrorHandlerActionHistogramSample.record(ERROR_HANDLER_ACTION_SILENT); + sErrorHandlerActionHistogramSample.record(ErrorHandlerAction.SILENT); } } @@ -109,12 +117,11 @@ @Override protected void handle(final Context context, final int errorCode) { if (!sNotificationShown.getAndSet(true)) { - sErrorHandlerActionHistogramSample - .record(ERROR_HANDLER_ACTION_IGNORED_AS_REDUNDANT); + sErrorHandlerActionHistogramSample.record(ErrorHandlerAction.IGNORED_AS_REDUNDANT); return; } GoogleApiAvailability.getInstance().showErrorNotification(context, errorCode); - sErrorHandlerActionHistogramSample.record(ERROR_HANDLER_ACTION_SYSTEM_NOTIFICATION); + sErrorHandlerActionHistogramSample.record(ErrorHandlerAction.SYSTEM_NOTIFICATION); } } @@ -219,7 +226,7 @@ mDialog.show(); sModalDialogShownActionEvent.record(); } - sErrorHandlerActionHistogramSample.record(ERROR_HANDLER_ACTION_MODAL_DIALOG); + sErrorHandlerActionHistogramSample.record(ErrorHandlerAction.MODAL_DIALOG); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/VerifiedHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/VerifiedHandler.java index 2991176..fcf1688 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/VerifiedHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/VerifiedHandler.java
@@ -49,9 +49,7 @@ public boolean sendMessageAtTime(Message msg, long uptimeMillis) { Messenger client = msg.replyTo; if (!mClientTrustMap.containsKey(client)) mClientTrustMap.put(client, checkCallerIsValid()); - if (!mClientTrustMap.get(client)) return false; - - return super.sendMessageAtTime(msg, uptimeMillis); + return (!mClientTrustMap.get(client)) ? false : super.sendMessageAtTime(msg, uptimeMillis); } /** @@ -59,11 +57,9 @@ * set during construction. */ public boolean checkCallerIsValid() { - if (TextUtils.isEmpty(mCallerPackageToMatch)) { - return ExternalAuthUtils.getInstance().isCallerValid(mContext, mAuthRequirements); - } else { - return ExternalAuthUtils.getInstance().isCallerValidForPackage( - mContext, mAuthRequirements, mCallerPackageToMatch); - } + return TextUtils.isEmpty(mCallerPackageToMatch) + ? ExternalAuthUtils.getInstance().isCallerValid(mContext, mAuthRequirements) + : ExternalAuthUtils.getInstance().isCallerValidForPackage( + mContext, mAuthRequirements, mCallerPackageToMatch); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java index b9a889c..b0d94678 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java
@@ -39,7 +39,9 @@ getActivity().setTitle(R.string.options_homepage_edit_title); } View v = inflater.inflate(R.layout.homepage_editor, container, false); - + View scrollView = v.findViewById(R.id.scroll_view); + scrollView.getViewTreeObserver().addOnScrollChangedListener( + PreferenceUtils.getShowShadowOnScrollListener(v, v.findViewById(R.id.shadow))); mHomepageUrlEdit = (EditText) v.findViewById(R.id.homepage_url_edit); mHomepageUrlEdit.setText(HomepageManager.getHomepageUri()); mHomepageUrlEdit.addTextChangedListener(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferenceUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferenceUtils.java index dde83e59..251341e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferenceUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferenceUtils.java
@@ -7,6 +7,8 @@ import android.os.StrictMode; import android.preference.PreferenceFragment; import android.support.annotation.XmlRes; +import android.view.View; +import android.view.ViewTreeObserver.OnScrollChangedListener; /** * A helper class for Preferences. @@ -28,4 +30,24 @@ StrictMode.setThreadPolicy(oldPolicy); } } + + /** + * Returns a view tree observer to show the shadow if and only if the view is scrolled. + * @param view The view whose scroll will be detected to determine the shadow's visibility. + * @param shadow The shadow to show/hide. + * @return An OnScrollChangedListener that detects scrolling and shows the passed in shadow + * when a scroll is detected and hides the shadow otherwise. + */ + public static OnScrollChangedListener getShowShadowOnScrollListener(View view, View shadow) { + return new OnScrollChangedListener() { + @Override + public void onScrollChanged() { + if (!view.canScrollVertically(-1)) { + shadow.setVisibility(View.GONE); + } else { + shadow.setVisibility(View.VISIBLE); + } + } + }; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java index e7334b6..65278a9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
@@ -20,10 +20,15 @@ import android.preference.Preference; import android.preference.PreferenceFragment; import android.preference.PreferenceFragment.OnPreferenceStartFragmentCallback; +import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ListView; import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.VisibleForTesting; @@ -41,10 +46,13 @@ * through settings, a separate Preferences activity is created for each screen. Thus each fragment * may freely modify its activity's action bar or title. This mimics the behavior of * android.preference.PreferenceActivity. + * + * If the preference overrides the root layout (e.g. {@link HomepageEditor}), add the following: + * 1) preferences_action_bar_shadow.xml to the custom XML hierarchy and + * 2) an OnScrollChangedListener to the main content's view's view tree observer via + * PreferenceUtils.getShowShadowOnScrollListener(...). */ -public class Preferences extends AppCompatActivity implements - OnPreferenceStartFragmentCallback { - +public class Preferences extends AppCompatActivity implements OnPreferenceStartFragmentCallback { public static final String EXTRA_SHOW_FRAGMENT = "show_fragment"; public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = "show_fragment_args"; @@ -87,6 +95,7 @@ Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS); getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setElevation(0); // If savedInstanceState is non-null, then the activity is being // recreated and super.onCreate() has already recreated the fragment. @@ -140,13 +149,28 @@ @Override public void onAttachedToWindow() { super.onAttachedToWindow(); + Fragment fragment = getFragmentManager().findFragmentById(android.R.id.content); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Fragment fragment = getFragmentManager().findFragmentById(android.R.id.content); if (fragment instanceof PreferenceFragment && fragment.getView() != null) { // Set list view padding to 0 so dividers are the full width of the screen. fragment.getView().findViewById(android.R.id.list).setPadding(0, 0, 0, 0); } } + if (fragment == null || fragment.getView() == null + || fragment.getView().findViewById(android.R.id.list) == null) { + return; + } + View contentView = fragment.getActivity().findViewById(android.R.id.content); + if (contentView == null || !(contentView instanceof FrameLayout)) { + return; + } + + View inflatedView = View.inflate(getApplicationContext(), + R.layout.preferences_action_bar_shadow, (ViewGroup) contentView); + ListView listView = fragment.getView().findViewById(android.R.id.list); + listView.getViewTreeObserver().addOnScrollChangedListener( + PreferenceUtils.getShowShadowOnScrollListener( + listView, inflatedView.findViewById(R.id.shadow))); } @Override @@ -198,7 +222,8 @@ // By default, every screen in Settings shows a "Help & feedback" menu item. MenuItem help = menu.add( Menu.NONE, R.id.menu_id_general_help, Menu.CATEGORY_SECONDARY, R.string.menu_help); - help.setIcon(R.drawable.ic_help_and_feedback); + help.setIcon(VectorDrawableCompat.create( + getResources(), R.drawable.ic_help_and_feedback, getTheme())); return true; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEnginePreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEnginePreference.java index 2bcbcd4..966f4713 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEnginePreference.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SearchEnginePreference.java
@@ -6,7 +6,6 @@ import android.os.Bundle; import android.preference.PreferenceFragment; -import android.view.ViewGroup.MarginLayoutParams; import android.widget.ListView; import org.chromium.base.VisibleForTesting; @@ -46,11 +45,6 @@ public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mListView = (ListView) getView().findViewById(android.R.id.list); - int marginTop = getActivity().getResources().getDimensionPixelSize( - R.dimen.search_engine_list_margin_top); - MarginLayoutParams layoutParams = (MarginLayoutParams) mListView.getLayoutParams(); - layoutParams.setMargins(0, marginTop, 0, 0); - mListView.setLayoutParams(layoutParams); mListView.setAdapter(mSearchEngineAdapter); mListView.setDivider(null); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java index 483c5de32..dfed115 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java
@@ -26,6 +26,7 @@ import android.widget.Spinner; import org.chromium.chrome.R; +import org.chromium.chrome.browser.preferences.PreferenceUtils; import org.chromium.chrome.browser.widget.FadingEdgeScrollView; import org.chromium.chrome.browser.widget.prefeditor.EditorDialog; @@ -63,18 +64,22 @@ } getActivity().setTitle(getTitleResourceId(mIsNewEntry)); + View baseView = inflater.inflate(R.layout.autofill_editor_base, container, false); + // Hide the top shadow on the ScrollView because the toolbar draws one. - FadingEdgeScrollView scrollView = (FadingEdgeScrollView) inflater.inflate( - R.layout.autofill_editor_base, container, false); + FadingEdgeScrollView scrollView = + (FadingEdgeScrollView) baseView.findViewById(R.id.scroll_view); scrollView.setEdgeVisibility( FadingEdgeScrollView.DRAW_NO_EDGE, FadingEdgeScrollView.DRAW_FADING_EDGE); - + scrollView.getViewTreeObserver().addOnScrollChangedListener( + PreferenceUtils.getShowShadowOnScrollListener( + scrollView, baseView.findViewById(R.id.shadow))); // Inflate the editor and buttons into the "content" LinearLayout. LinearLayout contentLayout = (LinearLayout) scrollView.findViewById(R.id.content); inflater.inflate(getLayoutId(), contentLayout, true); inflater.inflate(R.layout.autofill_editor_base_buttons, contentLayout, true); - return scrollView; + return baseView; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferences.java index 061d5df..f32b9e0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferences.java
@@ -9,6 +9,7 @@ import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceFragment; +import android.support.graphics.drawable.VectorDrawableCompat; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -101,7 +102,8 @@ menu.clear(); MenuItem help = menu.add( Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help); - help.setIcon(R.drawable.ic_help_and_feedback); + help.setIcon(VectorDrawableCompat.create( + getResources(), R.drawable.ic_help_and_feedback, getActivity().getTheme())); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/AddLanguageFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/AddLanguageFragment.java index d3625e4..ccb97a9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/AddLanguageFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/AddLanguageFragment.java
@@ -22,6 +22,7 @@ import android.view.inputmethod.EditorInfo; import org.chromium.chrome.R; +import org.chromium.chrome.browser.preferences.PreferenceUtils; import java.util.ArrayList; import java.util.List; @@ -123,6 +124,9 @@ mRecyclerView.setAdapter(mAdapter); mAdapter.reload(mFullLanguageList); + mRecyclerView.getViewTreeObserver().addOnScrollChangedListener( + PreferenceUtils.getShowShadowOnScrollListener( + mRecyclerView, view.findViewById(R.id.shadow))); return view; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java index ec1d7ab..9f03ac8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
@@ -33,6 +33,7 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.metrics.RecordHistogram; import org.chromium.chrome.R; +import org.chromium.chrome.browser.preferences.PreferenceUtils; import org.chromium.chrome.browser.sync.ProfileSyncService; import org.chromium.chrome.browser.widget.TintedImageButton; import org.chromium.components.sync.AndroidSyncSettings; @@ -113,15 +114,20 @@ getActivity().setTitle(R.string.password_entry_editor_title); mClipboard = (ClipboardManager) getActivity().getApplicationContext().getSystemService( Context.CLIPBOARD_SERVICE); - mView = inflater.inflate(mException ? R.layout.password_entry_exception + View inflatedView = + inflater.inflate(mException ? R.layout.password_entry_exception : R.layout.password_entry_editor_interactive, - container, false); + container, false); + mView = inflatedView.findViewById(R.id.scroll_view); getActivity().setTitle(R.string.password_entry_editor_title); mClipboard = (ClipboardManager) getActivity().getApplicationContext().getSystemService( Context.CLIPBOARD_SERVICE); View urlRowsView = mView.findViewById(R.id.url_row); TextView dataView = urlRowsView.findViewById(R.id.password_entry_editor_row_data); dataView.setText(url); + mView.getViewTreeObserver().addOnScrollChangedListener( + PreferenceUtils.getShowShadowOnScrollListener( + mView, inflatedView.findViewById(R.id.shadow))); hookupCopySiteButton(urlRowsView); if (!mException) { @@ -179,7 +185,7 @@ "PasswordManager.Android.PasswordExceptionEntry", PASSWORD_ENTRY_ACTION_VIEWED, PASSWORD_ENTRY_ACTION_BOUNDARY); } - return mView; + return inflatedView; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataTabsFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataTabsFragment.java index a700394..f75b651 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataTabsFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataTabsFragment.java
@@ -9,6 +9,7 @@ import android.content.Context; import android.os.Bundle; import android.support.design.widget.TabLayout; +import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v13.app.FragmentPagerAdapter; import android.support.v4.text.TextUtilsCompat; import android.support.v4.view.ViewCompat; @@ -179,7 +180,8 @@ menu.clear(); MenuItem help = menu.add(Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help); - help.setIcon(R.drawable.ic_help_and_feedback); + help.setIcon(VectorDrawableCompat.create( + getResources(), R.drawable.ic_help_and_feedback, getActivity().getTheme())); help.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java index 971acbd0..a84b85a4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
@@ -10,6 +10,7 @@ import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; +import android.support.graphics.drawable.VectorDrawableCompat; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -270,7 +271,8 @@ menu.clear(); MenuItem help = menu.add( Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help); - help.setIcon(R.drawable.ic_help_and_feedback); + help.setIcon(VectorDrawableCompat.create( + getResources(), R.drawable.ic_help_and_feedback, getActivity().getTheme())); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ChosenObjectPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ChosenObjectPreferences.java index 70cb1ca..422c45fc8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ChosenObjectPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ChosenObjectPreferences.java
@@ -8,6 +8,7 @@ import android.preference.Preference; import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; +import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v4.view.MenuItemCompat; import android.support.v7.widget.SearchView; import android.view.Menu; @@ -116,7 +117,8 @@ MenuItem help = menu.add(Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help); - help.setIcon(R.drawable.ic_help_and_feedback); + help.setIcon(VectorDrawableCompat.create( + getResources(), R.drawable.ic_help_and_feedback, getActivity().getTheme())); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java index 9a1a768..40433e8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java
@@ -14,6 +14,7 @@ import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; +import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.AlertDialog; import android.support.v7.widget.SearchView; @@ -364,7 +365,8 @@ MenuItem help = menu.add( Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help); - help.setIcon(R.drawable.ic_help_and_feedback); + help.setIcon(VectorDrawableCompat.create( + getResources(), R.drawable.ic_help_and_feedback, getActivity().getTheme())); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/TranslatePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/TranslatePreferences.java index 19542cc9..995967c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/TranslatePreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/TranslatePreferences.java
@@ -10,6 +10,7 @@ import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceFragment; +import android.support.graphics.drawable.VectorDrawableCompat; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -78,7 +79,8 @@ menu.clear(); MenuItem help = menu.add( Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help); - help.setIcon(R.drawable.ic_help_and_feedback); + help.setIcon(VectorDrawableCompat.create( + getResources(), R.drawable.ic_help_and_feedback, getActivity().getTheme())); help.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); menu.add(Menu.NONE, R.id.menu_id_reset, Menu.NONE, R.string.reset_translate_defaults);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java index 86a9edd..73d2631 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java
@@ -6,8 +6,8 @@ import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator; import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator; +import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid; import org.chromium.components.navigation_interception.InterceptNavigationDelegate; -import org.chromium.components.web_contents_delegate_android.WebContentsDelegateAndroid; /** * A factory class to create {@link Tab} related delegates.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java index 0bab7de5..63df102 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
@@ -43,8 +43,8 @@ import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.browser.tabmodel.TabWindowManager; +import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid; import org.chromium.components.embedder_support.media.ActivityContentVideoViewEmbedder; -import org.chromium.components.web_contents_delegate_android.WebContentsDelegateAndroid; import org.chromium.content_public.browser.ContentVideoViewEmbedder; import org.chromium.content_public.browser.GestureListenerManager; import org.chromium.content_public.browser.InvalidateTypes;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/vr/OWNERS index 7fb6ea3..bf69a62 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr/OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/OWNERS
@@ -1,3 +1,5 @@ file://chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VR_JAVA_OWNERS +# TEAM: xr-dev@chromium.org # COMPONENT: UI>Browser>VR +# OS: Android
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/OWNERS index 7fb6ea3..bf69a62 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/OWNERS
@@ -1,3 +1,5 @@ file://chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VR_JAVA_OWNERS +# TEAM: xr-dev@chromium.org # COMPONENT: UI>Browser>VR +# OS: Android
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VR_JAVA_OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VR_JAVA_OWNERS index 7dedb4727..88f07e7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VR_JAVA_OWNERS +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VR_JAVA_OWNERS
@@ -1,3 +1,6 @@ -bshe@chromium.org -mthiesse@chromium.org asimjour@chromium.org +mthiesse@chromium.org + +# TEAM: xr-dev@chromium.org +# COMPONENT: UI>Browser>VR +# OS: Android
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/prefeditor/EditorDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/prefeditor/EditorDialog.java index a536176..b487df6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/prefeditor/EditorDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/prefeditor/EditorDialog.java
@@ -13,7 +13,9 @@ import android.content.DialogInterface; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.os.Handler; +import android.support.annotation.Nullable; import android.support.v4.view.MarginLayoutParamsCompat; import android.support.v4.view.animation.FastOutLinearInInterpolator; import android.support.v4.view.animation.LinearOutSlowInInterpolator; @@ -34,6 +36,7 @@ import android.widget.CompoundButton; import android.widget.EditText; import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.Spinner; import android.widget.TextView; @@ -41,20 +44,18 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; import org.chromium.chrome.browser.help.HelpAndFeedback; +import org.chromium.chrome.browser.preferences.PreferenceUtils; import org.chromium.chrome.browser.preferences.autofill.CreditCardNumberFormattingTextWatcher; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.widget.AlwaysDismissedDialog; import org.chromium.chrome.browser.widget.FadingEdgeScrollView; -import org.chromium.chrome.browser.widget.FadingShadow; -import org.chromium.chrome.browser.widget.FadingShadowView; +import org.chromium.chrome.browser.widget.TintedDrawable; import org.chromium.ui.UiUtils; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; -import javax.annotation.Nullable; - /** * The editor dialog. Can be used for editing contact information, shipping address, * billing address, and credit cards. @@ -186,8 +187,10 @@ */ private void prepareToolbar() { EditorDialogToolbar toolbar = (EditorDialogToolbar) mLayout.findViewById(R.id.action_bar); + toolbar.setBackgroundColor(ApiCompatibilityUtils.getColor( + toolbar.getResources(), R.color.modern_primary_color)); + toolbar.setTitleTextAppearance(toolbar.getContext(), R.style.BlackHeadline1); toolbar.setTitle(mEditorModel.getTitle()); - toolbar.setTitleTextColor(Color.WHITE); toolbar.setShowDeleteMenuItem(mDeleteRunnable != null); // Show the help article when the help icon is clicked on, or delete @@ -207,7 +210,7 @@ // Cancel editing when the user hits the back arrow. toolbar.setNavigationContentDescription(R.string.cancel); - toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); + toolbar.setNavigationIcon(getBlackTintedBackIcon()); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -215,17 +218,19 @@ } }); - // Make it appear that the toolbar is floating by adding a shadow. - FadingShadowView shadow = (FadingShadowView) mLayout.findViewById(R.id.shadow); - shadow.init(ApiCompatibilityUtils.getColor( - mContext.getResources(), R.color.toolbar_shadow_color), - FadingShadow.POSITION_TOP); - // The top shadow is handled by the toolbar, so hide the one used in the field editor. FadingEdgeScrollView scrollView = (FadingEdgeScrollView) mLayout.findViewById(R.id.scroll_view); scrollView.setEdgeVisibility( FadingEdgeScrollView.DRAW_NO_EDGE, FadingEdgeScrollView.DRAW_FADING_EDGE); + + // The shadow's top margin doesn't get picked up in the xml; set it programmatically. + View shadow = mLayout.findViewById(R.id.shadow); + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) shadow.getLayoutParams(); + params.topMargin = toolbar.getLayoutParams().height; + shadow.setLayoutParams(params); + scrollView.getViewTreeObserver().addOnScrollChangedListener( + PreferenceUtils.getShowShadowOnScrollListener(scrollView, shadow)); } /** @@ -602,4 +607,9 @@ public List<Spinner> getDropdownFieldsForTest() { return mDropdownFields; } + + private Drawable getBlackTintedBackIcon() { + return TintedDrawable.constructTintedDrawable( + getContext(), R.drawable.ic_arrow_back_white_24dp, android.R.color.black); + } }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 4e74c53..d8c95294 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -4964,7 +4964,7 @@ </message> <message name="IDS_CROSTINI_INSTALLER_TITLE" desc="Title of the Crostini installer, a dialog for installing Linux."> - Set up Linux on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> + Set up Linux (Beta) on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> </message> <message name="IDS_CROSTINI_INSTALLER_BODY" desc="Description for the Crostini installer, a dialog for installing Linux."> Get tools for developing websites, Android apps, and more. Installing Linux will download <ph name="DOWNLOAD_SIZE">$1<ex>300MB</ex></ph> of data.
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 0888da7..caaa61c5 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -1521,7 +1521,7 @@ <message name="IDS_SETTINGS_EASY_UNLOCK_OPTIONS" desc="Heading for options for the Smart Lock feature."> Smart Lock options </message> - <message name="IDS_SETTINGS_EASY_UNLOCK_UNLOCK_DEVICE_ONLY" desc="This option lets the user unlock their Chromebook from their phone one the user has already logged in."> + <message name="IDS_SETTINGS_EASY_UNLOCK_UNLOCK_DEVICE_ONLY" desc="This option lets the user unlock their Chromebook from their phone if they're logged in. It will unlock their Chromebook but will not sign them in."> Unlock device only </message> <message name="IDS_SETTINGS_EASY_UNLOCK_UNLOCK_DEVICE_AND_ALLOW_SIGNIN" desc="This option lets the user unlock their Chromebook from their phone as well as log into their Chromebook without a password if their phone is nearby and unlocked.">
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn index 33ed8da..3a2fa5c 100644 --- a/chrome/app/vector_icons/BUILD.gn +++ b/chrome/app/vector_icons/BUILD.gn
@@ -53,7 +53,7 @@ "folder_supervised.icon", "forward_arrow_touch.icon", "globe.icon", - "google_pay_logo_with_vertical_separator.icon", + "google_pay_logo.icon", "horizontal_menu.icon", "incognito.icon", "input.icon",
diff --git a/chrome/app/vector_icons/google_pay_logo_with_vertical_separator.icon b/chrome/app/vector_icons/google_pay_logo.icon similarity index 95% rename from chrome/app/vector_icons/google_pay_logo_with_vertical_separator.icon rename to chrome/app/vector_icons/google_pay_logo.icon index f3f5e160..8830edf 100644 --- a/chrome/app/vector_icons/google_pay_logo_with_vertical_separator.icon +++ b/chrome/app/vector_icons/google_pay_logo.icon
@@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -CANVAS_DIMENSIONS, 57, +CANVAS_DIMENSIONS, 40, + +// Pay part. PATH_COLOR_ARGB, 0xFF, 0x5F, 0x63, 0x68, MOVE_TO, 18.92f, 7.82f, R_V_LINE_TO, 4.64f, @@ -62,6 +64,8 @@ R_H_LINE_TO, 0.03f, R_LINE_TO, 2.28f, -5.63f, CLOSE, + +// Blue part of the G. NEW_PATH, PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4, MOVE_TO, 12.95f, 6.82f, @@ -74,6 +78,8 @@ R_H_LINE_TO, 2.13f, R_CUBIC_TO, 1.25f, -1.14f, 1.97f, -2.84f, 1.97f, -4.84f, CLOSE, + +// Green part of the G. NEW_PATH, PATH_COLOR_ARGB, 0xFF, 0x34, 0xA8, 0x53, MOVE_TO, 6.61f, 13.26f, @@ -85,6 +91,8 @@ V_LINE_TO, 9.63f, R_ARC_TO, 6.61f, 6.61f, 0, 0, 0, 5.9f, 3.63f, CLOSE, + +// Yellow part of the G. NEW_PATH, PATH_COLOR_ARGB, 0xFF, 0xFB, 0xBC, 0x05, MOVE_TO, 2.9f, 7.93f, @@ -94,6 +102,8 @@ R_ARC_TO, 6.56f, 6.56f, 0, 0, 0, 0, 5.91f, R_LINE_TO, 2.19f, -1.7f, CLOSE, + +// Red part of the G. NEW_PATH, PATH_COLOR_ARGB, 0xFF, 0xEA, 0x43, 0x35, MOVE_TO, 6.61f, 2.7f, @@ -103,12 +113,5 @@ ARC_TO, 6.61f, 6.61f, 0, 0, 0, 0.71f, 3.72f, R_LINE_TO, 2.19f, 1.7f, R_CUBIC_TO, 0.52f, -1.56f, 1.99f, -2.72f, 3.71f, -2.72f, -CLOSE, -NEW_PATH, -PATH_COLOR_ARGB, 0xFF, 0x9E, 0x9E, 0x9E, -MOVE_TO, 56, 1, -R_H_LINE_TO, 1, -R_V_LINE_TO, 14, -R_H_LINE_TO, -1, CLOSE
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 05712a08..0f5bb38b 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1192,6 +1192,8 @@ "previews/previews_service.h", "previews/previews_service_factory.cc", "previews/previews_service_factory.h", + "previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc", + "previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h", "process_resource_usage.cc", "process_resource_usage.h", "process_singleton.h", @@ -2434,12 +2436,12 @@ "//chrome/services/media_gallery_util/public/cpp", "//components/cdm/browser", "//components/data_usage/android", + "//components/embedder_support/android:web_contents_delegate", "//components/feed:buildflags", "//components/feed:feature_list", "//components/payments/content/android", "//components/resources:components_resources", "//components/toolbar", - "//components/web_contents_delegate_android", "//rlz:rlz_utils", "//sandbox", "//sandbox:sandbox_buildflags", @@ -3220,7 +3222,6 @@ "shell_integration_linux.cc", "shell_integration_linux.h", "speech/tts_linux.cc", - "web_applications/web_app_linux.cc", ] deps += [ "//third_party/speech-dispatcher" ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 42bf63e..796f243 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1567,6 +1567,10 @@ {"newblue", flag_descriptions::kNewblueName, flag_descriptions::kNewblueDescription, kOsCrOS, FEATURE_VALUE_TYPE(device::kNewblueDaemon)}, + {"unfiltered-bluetooth-devices", + flag_descriptions::kUnfilteredBluetoothDevicesName, + flag_descriptions::kUnfilteredBluetoothDevicesDescription, kOsCrOS, + FEATURE_VALUE_TYPE(device::kUnfilteredBluetoothDevices)}, {"shelf-hover-previews", flag_descriptions::kShelfHoverPreviewsName, flag_descriptions::kShelfHoverPreviewsDescription, kOsCrOS, SINGLE_VALUE_TYPE(chromeos::switches::kShelfHoverPreviews)}, @@ -2806,6 +2810,9 @@ {"arc-boot-completed-broadcast", flag_descriptions::kArcBootCompleted, flag_descriptions::kArcBootCompletedDescription, kOsCrOS, FEATURE_VALUE_TYPE(arc::kBootCompletedBroadcastFeature)}, + {"arc-input-method", flag_descriptions::kArcInputMethodName, + flag_descriptions::kArcInputMethodDescription, kOsCrOS, + FEATURE_VALUE_TYPE(arc::kEnableInputMethodFeature)}, {"arc-native-bridge-experiment", flag_descriptions::kArcNativeBridgeExperimentName, flag_descriptions::kArcNativeBridgeExperimentDescription, kOsCrOS, @@ -3055,10 +3062,9 @@ #endif #if defined(OS_CHROMEOS) - {"enable-chromevox-arc-support", - flag_descriptions::kEnableChromevoxArcSupportName, - flag_descriptions::kEnableChromevoxArcSupportDescription, kOsCrOS, - SINGLE_VALUE_TYPE(chromeos::switches::kEnableChromeVoxArcSupport)}, + {"ChromeVoxArcSupport", flag_descriptions::kChromeVoxArcSupportName, + flag_descriptions::kChromeVoxArcSupportDescription, kOsCrOS, + FEATURE_VALUE_TYPE(chromeos::features::kChromeVoxArcSupport)}, #endif // defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/android/DEPS b/chrome/browser/android/DEPS index ed8369f..f1764553 100644 --- a/chrome/browser/android/DEPS +++ b/chrome/browser/android/DEPS
@@ -2,13 +2,13 @@ "-components/devtools_bridge", "+cc/layers/layer.h", "+chrome_jni_registration/chrome_jni_registration.h", + "+components/embedder_suport", "+components/ntp_snippets", "+components/spellcheck/browser", "+components/sync/android", "+components/sync/test/fake_server/android", "+components/toolbar", "+components/viz/common/gpu/context_provider.h", - "+components/web_contents_delegate_android", "+device/vr/buildflags/buildflags.h", "+sandbox/linux/seccomp-bpf/sandbox_bpf.h", "+sandbox/linux/seccomp-bpf-helpers",
diff --git a/chrome/browser/android/bottombar/overlay_panel_content.cc b/chrome/browser/android/bottombar/overlay_panel_content.cc index 14b98a04..9bcd7736 100644 --- a/chrome/browser/android/bottombar/overlay_panel_content.cc +++ b/chrome/browser/android/bottombar/overlay_panel_content.cc
@@ -16,10 +16,10 @@ #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/ui/android/view_android_helper.h" #include "chrome/common/chrome_render_frame.mojom.h" +#include "components/embedder_support/android/delegate/web_contents_delegate_android.h" #include "components/history/core/browser/history_service.h" #include "components/navigation_interception/intercept_navigation_delegate.h" #include "components/variations/variations_associated_data.h" -#include "components/web_contents_delegate_android/web_contents_delegate_android.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/browser_controls_state.h"
diff --git a/chrome/browser/android/document/document_web_contents_delegate.cc b/chrome/browser/android/document/document_web_contents_delegate.cc index bd91615..d1f5c65 100644 --- a/chrome/browser/android/document/document_web_contents_delegate.cc +++ b/chrome/browser/android/document/document_web_contents_delegate.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/android/document/document_web_contents_delegate.h" -#include "components/web_contents_delegate_android/web_contents_delegate_android.h" +#include "components/embedder_support/android/delegate/web_contents_delegate_android.h" #include "content/public/browser/web_contents.h" #include "jni/DocumentWebContentsDelegate_jni.h"
diff --git a/chrome/browser/android/document/document_web_contents_delegate.h b/chrome/browser/android/document/document_web_contents_delegate.h index 3537cb06..2c3e345 100644 --- a/chrome/browser/android/document/document_web_contents_delegate.h +++ b/chrome/browser/android/document/document_web_contents_delegate.h
@@ -7,7 +7,7 @@ #include <stdint.h> -#include "components/web_contents_delegate_android/web_contents_delegate_android.h" +#include "components/embedder_support/android/delegate/web_contents_delegate_android.h" // Stub WebContentsDelegateAndroid that is meant to be a temporary substitute // for a real WebContentsDelegate for the (expectedly short) period between when
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.h b/chrome/browser/android/tab_web_contents_delegate_android.h index d645103..8a4f33c0 100644 --- a/chrome/browser/android/tab_web_contents_delegate_android.h +++ b/chrome/browser/android/tab_web_contents_delegate_android.h
@@ -6,7 +6,7 @@ #define CHROME_BROWSER_ANDROID_TAB_WEB_CONTENTS_DELEGATE_ANDROID_H_ #include "base/files/file_path.h" -#include "components/web_contents_delegate_android/web_contents_delegate_android.h" +#include "components/embedder_support/android/delegate/web_contents_delegate_android.h" #include "content/public/browser/bluetooth_chooser.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/android/vr/OWNERS b/chrome/browser/android/vr/OWNERS index 7e60dea..26161de 100644 --- a/chrome/browser/android/vr/OWNERS +++ b/chrome/browser/android/vr/OWNERS
@@ -1,13 +1,12 @@ -bajones@chromium.org -bshe@chromium.org -girard@chromium.org -mthiesse@chromium.org -cjgrant@chromium.org -vollick@chromium.org asimjour@chromium.org +cjgrant@chromium.org +mthiesse@chromium.org tiborg@chromium.org +vollick@chromium.org -# WebVR-related including VrShellGl +# WebXR-related, including VrShellGl. klausw@chromium.org +# TEAM: xr-dev@chromium.org # COMPONENT: UI>Browser>VR +# OS: Android
diff --git a/chrome/browser/android/vr/arcore_device/OWNERS b/chrome/browser/android/vr/arcore_device/OWNERS new file mode 100644 index 0000000..25a82d9 --- /dev/null +++ b/chrome/browser/android/vr/arcore_device/OWNERS
@@ -0,0 +1,9 @@ +billorr@chromium.org +ddorwin@chromium.org +klausw@chromium.org +mthiesse@chromium.org +vollick@chromium.org + +# TEAM: xr-dev@chromium.org +# COMPONENT: Blink>WebXR>AR +# OS: Android
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index 3662e32e..4a586334 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -1898,7 +1898,6 @@ interstitial_main_frame->GetRenderViewHost()->GetWidget(); content::WaitForHitTestDataOrChildSurfaceReady(interstitial_main_frame); - content::RenderFrameSubmissionObserver frame_observer(guest_web_contents); EXPECT_NE(interstitial_widget, content::GetFocusedRenderWidgetHost(guest_web_contents)); @@ -1913,15 +1912,16 @@ content::RouteMouseEvent(outer_web_contents, &event); // Wait a frame. - frame_observer.WaitForAnyFrameSubmission(); + content::MainThreadFrameObserver observer(interstitial_widget); + observer.Wait(); // Send mouse up. - content::InputEventAckWaiter waiter(interstitial_widget, - blink::WebInputEvent::kMouseUp); event.SetType(blink::WebInputEvent::kMouseUp); event.SetPositionInWidget(10, 10); content::RouteMouseEvent(outer_web_contents, &event); - waiter.Wait(); + + // Wait another frame. + observer.Wait(); EXPECT_EQ(interstitial_widget, content::GetFocusedRenderWidgetHost(guest_web_contents));
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc index 7e8f21a..49211550 100644 --- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -1165,11 +1165,13 @@ content::WebContents* embedder_web_contents = GetFirstAppWindowWebContents(); content::WebContents* guest_web_contents = GetGuestViewManager()->WaitForSingleGuestCreated(); - content::RenderFrameSubmissionObserver embedder_observer( - embedder_web_contents); - content::RenderFrameSubmissionObserver guest_observer(guest_web_contents); - embedder_observer.WaitForMetadataChange(); - guest_observer.WaitForMetadataChange(); + + content::MainThreadFrameObserver embedder_observer( + embedder_web_contents->GetMainFrame()->GetView()->GetRenderWidgetHost()); + content::MainThreadFrameObserver guest_observer( + guest_web_contents->GetMainFrame()->GetView()->GetRenderWidgetHost()); + embedder_observer.Wait(); + guest_observer.Wait(); ExtensionTestMessageListener listener{"WebViewTest.WEBVIEW_LOADED", false}; EXPECT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
diff --git a/chrome/browser/chrome_content_renderer_manifest_overlay.json b/chrome/browser/chrome_content_renderer_manifest_overlay.json index df0e1dc..d7ec48b 100644 --- a/chrome/browser/chrome_content_renderer_manifest_overlay.json +++ b/chrome/browser/chrome_content_renderer_manifest_overlay.json
@@ -19,6 +19,7 @@ "blink.mojom.DisplayCutoutClient", "blink.mojom.document_metadata.CopylessPaste", "blink.mojom.PauseSubresourceLoadingHandle", + "blink.mojom.PreviewsResourceLoadingHintsReceiver", "chrome.mojom.ChromeRenderFrame", "chrome.mojom.ContentSettingsRenderer", "chrome.mojom.PrerenderDispatcher",
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc index 54a278e..1580a496d 100644 --- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc +++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
@@ -12,7 +12,7 @@ #include "base/memory/singleton.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h" -#include "chromeos/chromeos_switches.h" +#include "chromeos/chromeos_features.h" #include "components/arc/arc_bridge_service.h" #include "components/arc/arc_browser_context_keyed_service_factory_base.h" #include "components/arc/arc_service_manager.h" @@ -80,33 +80,6 @@ accessibility_manager->OnViewFocusedInArc(bounds_in_screen); } -arc::mojom::AccessibilityFilterType GetFilterTypeForProfile(Profile* profile) { - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - chromeos::switches::kEnableChromeVoxArcSupport)) { - return arc::mojom::AccessibilityFilterType::ALL; - } - - chromeos::AccessibilityManager* accessibility_manager = - chromeos::AccessibilityManager::Get(); - if (!accessibility_manager) - return arc::mojom::AccessibilityFilterType::OFF; - - // TODO(yawano): Support the case where primary user is in background. - if (accessibility_manager->profile() != profile) - return arc::mojom::AccessibilityFilterType::OFF; - - if (accessibility_manager->IsSpokenFeedbackEnabled() || - accessibility_manager->IsSelectToSpeakEnabled() || - accessibility_manager->IsSwitchAccessEnabled()) { - return arc::mojom::AccessibilityFilterType::ALL; - } - - if (accessibility_manager->IsFocusHighlightEnabled()) - return arc::mojom::AccessibilityFilterType::FOCUS; - - return arc::mojom::AccessibilityFilterType::OFF; -} - } // namespace namespace arc { @@ -508,6 +481,38 @@ UpdateWindowProperties(GetActiveWindow()); } +arc::mojom::AccessibilityFilterType +ArcAccessibilityHelperBridge::GetFilterTypeForProfile(Profile* profile) { + if (use_filter_type_all_for_test_) + return arc::mojom::AccessibilityFilterType::ALL; + + chromeos::AccessibilityManager* accessibility_manager = + chromeos::AccessibilityManager::Get(); + if (!accessibility_manager) + return arc::mojom::AccessibilityFilterType::OFF; + + // TODO(yawano): Support the case where primary user is in background. + if (accessibility_manager->profile() != profile) + return arc::mojom::AccessibilityFilterType::OFF; + + if (accessibility_manager->IsSelectToSpeakEnabled() || + accessibility_manager->IsSwitchAccessEnabled()) { + return arc::mojom::AccessibilityFilterType::ALL; + } + + if (accessibility_manager->IsSpokenFeedbackEnabled()) { + return base::FeatureList::IsEnabled( + chromeos::features::kChromeVoxArcSupport) + ? arc::mojom::AccessibilityFilterType::ALL + : arc::mojom::AccessibilityFilterType::WHITELISTED_PACKAGE_NAME; + } + + if (accessibility_manager->IsFocusHighlightEnabled()) + return arc::mojom::AccessibilityFilterType::FOCUS; + + return arc::mojom::AccessibilityFilterType::OFF; +} + void ArcAccessibilityHelperBridge::UpdateFilterType() { arc::mojom::AccessibilityFilterType filter_type = GetFilterTypeForProfile(profile_);
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h index a199b77..1e92f0a 100644 --- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h +++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
@@ -97,6 +97,8 @@ return notification_key_to_tree_; } + void set_filter_type_all_for_test() { use_filter_type_all_for_test_ = true; } + protected: virtual aura::Window* GetActiveWindow(); @@ -110,6 +112,7 @@ void OnAccessibilityStatusChanged( const chromeos::AccessibilityStatusEventDetails& event_details); + arc::mojom::AccessibilityFilterType GetFilterTypeForProfile(Profile* profile); void UpdateFilterType(); void UpdateWindowProperties(aura::Window* window); void UpdateTreeIdOfNotificationSurface(const std::string& notification_key, @@ -130,6 +133,7 @@ notification_key_to_tree_; std::unique_ptr<chromeos::AccessibilityStatusSubscription> accessibility_status_subscription_; + bool use_filter_type_all_for_test_ = false; DISALLOW_COPY_AND_ASSIGN(ArcAccessibilityHelperBridge); };
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc index 1bb0302..180d3cac 100644 --- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc +++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
@@ -93,7 +93,7 @@ aura::client::kAccessibilityTouchExplorationPassThrough)); chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(true); - EXPECT_EQ(mojom::AccessibilityFilterType::ALL, + EXPECT_EQ(mojom::AccessibilityFilterType::WHITELISTED_PACKAGE_NAME, fake_accessibility_helper_instance_->filter_type()); // Touch exploration pass through of test_window_1 (current active window)
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc index 8b889d4..fe1c8c1f 100644 --- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc +++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
@@ -183,11 +183,10 @@ }; TEST_F(ArcAccessibilityHelperBridgeTest, TaskAndAXTreeLifecycle) { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - chromeos::switches::kEnableChromeVoxArcSupport); - TestArcAccessibilityHelperBridge* helper_bridge = accessibility_helper_bridge(); + helper_bridge->set_filter_type_all_for_test(); + const auto& task_id_to_tree = helper_bridge->task_id_to_tree_for_test(); ASSERT_EQ(0U, task_id_to_tree.size()); @@ -268,9 +267,6 @@ // mojo: notification 2 removed // wayland: surface 2 removed TEST_F(ArcAccessibilityHelperBridgeTest, NotificationEventArriveFirst) { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - chromeos::switches::kEnableChromeVoxArcSupport); - TestArcAccessibilityHelperBridge* helper_bridge = accessibility_helper_bridge(); arc_notification_surface_manager_->AddObserver(helper_bridge); @@ -364,9 +360,6 @@ // mojo: notification 1 created // mojo: notification 1 removed TEST_F(ArcAccessibilityHelperBridgeTest, NotificationSurfaceArriveFirst) { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - chromeos::switches::kEnableChromeVoxArcSupport); - TestArcAccessibilityHelperBridge* helper_bridge = accessibility_helper_bridge(); arc_notification_surface_manager_->AddObserver(helper_bridge); @@ -404,8 +397,7 @@ TEST_F(ArcAccessibilityHelperBridgeTest, TextSelectionChangeActivateNotificationWidget) { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - chromeos::switches::kEnableChromeVoxArcSupport); + accessibility_helper_bridge()->set_filter_type_all_for_test(); // Prepare notification surface. std::unique_ptr<MockArcNotificationSurface> surface = @@ -460,8 +452,7 @@ } TEST_F(ArcAccessibilityHelperBridgeTest, TextSelectionChangedFocusContentView) { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - chromeos::switches::kEnableChromeVoxArcSupport); + accessibility_helper_bridge()->set_filter_type_all_for_test(); // Prepare notification surface. std::unique_ptr<MockArcNotificationSurface> surface =
diff --git a/chrome/browser/chromeos/arc/voice_interaction/highlighter_controller_client.cc b/chrome/browser/chromeos/arc/voice_interaction/highlighter_controller_client.cc index b7012b0..b10a089e 100644 --- a/chrome/browser/chromeos/arc/voice_interaction/highlighter_controller_client.cc +++ b/chrome/browser/chromeos/arc/voice_interaction/highlighter_controller_client.cc
@@ -38,7 +38,7 @@ void HighlighterControllerClient::SimulateSelectionTimeoutForTesting() { DCHECK(delay_timer_ && delay_timer_->IsRunning()); - delay_timer_->user_task().Run(); + delay_timer_->FireNow(); delay_timer_.reset(); }
diff --git a/chrome/browser/chromeos/extensions/info_private_api.cc b/chrome/browser/chromeos/extensions/info_private_api.cc index d1fd222..f04d9b83 100644 --- a/chrome/browser/chromeos/extensions/info_private_api.cc +++ b/chrome/browser/chromeos/extensions/info_private_api.cc
@@ -10,6 +10,7 @@ #include <utility> #include "ash/public/cpp/ash_pref_names.h" +#include "ash/public/cpp/stylus_utils.h" #include "base/memory/ptr_util.h" #include "base/sys_info.h" #include "base/values.h" @@ -166,6 +167,17 @@ // Value to which deviceType property is set when the specific type is unknown. const char kDeviceTypeChromedevice[] = "chromedevice"; +// Key which corresponds to the stylusStatus property in JS. +const char kPropertyStylusStatus[] = "stylusStatus"; + +// Value to which stylusStatus property is set when the device does not support +// stylus input. +const char kStylusStatusUnsupported[] = "unsupported"; + +// Value to which stylusStatus property is set when the device supports stylus +// input. +const char kStylusStatusSupported[] = "supported"; + const struct { const char* api_name; const char* preference_name; @@ -331,6 +343,15 @@ } } + if (property_name == kPropertyStylusStatus) { + if (!ash::stylus_utils::HasStylusInput()) { + return std::make_unique<base::Value>(kStylusStatusUnsupported); + } + + // TODO(michaelpg): Return "seen" if stylus has been used. + return std::make_unique<base::Value>(kStylusStatusSupported); + } + if (property_name == kPropertyClientId) { return std::make_unique<base::Value>(GetClientId()); }
diff --git a/chrome/browser/chromeos/extensions/info_private_apitest.cc b/chrome/browser/chromeos/extensions/info_private_apitest.cc index 9217aed..b92e95d 100644 --- a/chrome/browser/chromeos/extensions/info_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/info_private_apitest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ash/public/cpp/ash_pref_names.h" +#include "ash/public/cpp/stylus_utils.h" #include "base/sys_info.h" #include "base/values.h" #include "chrome/browser/chromeos/arc/arc_util.h" @@ -127,6 +128,19 @@ << message_; } +IN_PROC_BROWSER_TEST_F(ChromeOSInfoPrivateTest, StylusUnsupported) { + ASSERT_TRUE(RunPlatformAppTestWithArg("chromeos_info_private/extended", + "stylus unsupported")) + << message_; +} + +IN_PROC_BROWSER_TEST_F(ChromeOSInfoPrivateTest, StylusSupported) { + ash::stylus_utils::SetHasStylusInputForTesting(); + ASSERT_TRUE(RunPlatformAppTestWithArg("chromeos_info_private/extended", + "stylus supported")) + << message_; +} + class ChromeOSArcInfoPrivateTest : public ChromeOSInfoPrivateTest { public: ChromeOSArcInfoPrivateTest() = default;
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc index 828216f2..aba1b52 100644 --- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -265,13 +265,7 @@ update_screen_->StartNetworkCheck(); // Force timer expiration. - { - base::Closure timed_callback = - update_screen_->GetErrorMessageTimerForTesting().user_task(); - ASSERT_FALSE(timed_callback.is_null()); - update_screen_->GetErrorMessageTimerForTesting().Reset(); - timed_callback.Run(); - } + update_screen_->GetErrorMessageTimerForTesting().FireNow(); NetworkPortalDetector::CaptivePortalState online_state; online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE; @@ -319,13 +313,7 @@ update_screen_->StartNetworkCheck(); // Force timer expiration. - { - base::Closure timed_callback = - update_screen_->GetErrorMessageTimerForTesting().user_task(); - ASSERT_FALSE(timed_callback.is_null()); - update_screen_->GetErrorMessageTimerForTesting().Reset(); - timed_callback.Run(); - } + update_screen_->GetErrorMessageTimerForTesting().FireNow(); // Change active network to the wifi behind proxy. NetworkPortalDetector::CaptivePortalState proxy_state; @@ -401,13 +389,7 @@ update_screen_->StartNetworkCheck(); // Force timer expiration. - { - base::Closure timed_callback = - update_screen_->GetErrorMessageTimerForTesting().user_task(); - ASSERT_FALSE(timed_callback.is_null()); - update_screen_->GetErrorMessageTimerForTesting().Reset(); - timed_callback.Run(); - } + update_screen_->GetErrorMessageTimerForTesting().FireNow(); // User re-selects the same network manually. In this case, hide // offline message and skip network check. Since ethernet is still
diff --git a/chrome/browser/download/download_request_limiter.cc b/chrome/browser/download/download_request_limiter.cc index 104e730..e3eddb50 100644 --- a/chrome/browser/download/download_request_limiter.cc +++ b/chrome/browser/download/download_request_limiter.cc
@@ -135,14 +135,23 @@ download_seen_ = false; ui_status_ = DOWNLOAD_UI_DEFAULT; - // If the navigation is renderer-initiated (but not user-initiated), ensure - // that a prompting or blocking limiter state is not reset, so - // window.location.href or meta refresh can't be abused to avoid the limiter. - // User-initiated navigations will trigger DidGetUserInteraction, which resets - // the limiter before the navigation starts. - if (navigation_handle->IsRendererInitiated() && - (status_ == PROMPT_BEFORE_DOWNLOAD || status_ == DOWNLOADS_NOT_ALLOWED)) { - return; + if (status_ == PROMPT_BEFORE_DOWNLOAD || status_ == DOWNLOADS_NOT_ALLOWED) { + std::string host = navigation_handle->GetURL().host(); + // If the navigation is renderer-initiated (but not user-initiated), ensure + // that a prompting or blocking limiter state is not reset, so + // window.location.href or meta refresh can't be abused to avoid the + // limiter. + if (navigation_handle->IsRendererInitiated()) { + if (!host.empty()) + restricted_hosts_.emplace(host); + return; + } + + // If this is a forward/back navigation, also don't reset a prompting or + // blocking limiter state unless a new host is encounted. This prevents a + // page to use history forward/backward to trigger multiple downloads. + if (IsNavigationRestricted(navigation_handle)) + return; } if (status_ == DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS || @@ -174,7 +183,8 @@ // DidStartNavigation. if (status_ == ALLOW_ONE_DOWNLOAD || (status_ == PROMPT_BEFORE_DOWNLOAD && - !navigation_handle->IsRendererInitiated())) { + !navigation_handle->IsRendererInitiated() && + !IsNavigationRestricted(navigation_handle))) { // When the user reloads the page without responding to the infobar, // they are expecting DownloadRequestLimiter to behave as if they had // just initially navigated to this page. See http://crbug.com/171372. @@ -383,6 +393,11 @@ if (!web_contents()) return; + if (status_ == PROMPT_BEFORE_DOWNLOAD || status_ == DOWNLOADS_NOT_ALLOWED) { + if (!initial_page_host_.empty()) + restricted_hosts_.emplace(initial_page_host_); + } + // We want to send a notification if the UI status has changed to ensure that // the omnibox decoration updates appropriately. This is effectively the same // as other permissions which might be in an allow state, but do not show UI @@ -396,6 +411,14 @@ content::NotificationService::NoDetails()); } +bool DownloadRequestLimiter::TabDownloadState::IsNavigationRestricted( + content::NavigationHandle* navigation_handle) { + std::string host = navigation_handle->GetURL().host(); + if (navigation_handle->GetPageTransition() & ui::PAGE_TRANSITION_FORWARD_BACK) + return restricted_hosts_.find(host) != restricted_hosts_.end(); + return false; +} + // DownloadRequestLimiter ------------------------------------------------------ DownloadRequestLimiter::DownloadRequestLimiter() : factory_(this) {}
diff --git a/chrome/browser/download/download_request_limiter.h b/chrome/browser/download/download_request_limiter.h index ab3d33f..e7ca1b2 100644 --- a/chrome/browser/download/download_request_limiter.h +++ b/chrome/browser/download/download_request_limiter.h
@@ -8,6 +8,7 @@ #include <stddef.h> #include <map> +#include <set> #include <string> #include <vector> @@ -171,6 +172,10 @@ void SetDownloadStatusAndNotifyImpl(DownloadStatus status, ContentSetting setting); + // Check if download is restricted (either requires prompting or is blocked) + // for the |navigation_handle|. + bool IsNavigationRestricted(content::NavigationHandle* navigation_handle); + content::WebContents* web_contents_; DownloadRequestLimiter* host_; @@ -192,6 +197,10 @@ // callbacks. std::vector<DownloadRequestLimiter::Callback> callbacks_; + // A list of hosts that won't cause tab's download state to change if the + // state is PROMPT_BEFORE_DOWNLOAD or DOWNLOADS_NOT_ALLOWED. + std::set<std::string> restricted_hosts_; + ScopedObserver<HostContentSettingsMap, content_settings::Observer> observer_;
diff --git a/chrome/browser/download/download_request_limiter_unittest.cc b/chrome/browser/download/download_request_limiter_unittest.cc index 431f472..0a598ca36 100644 --- a/chrome/browser/download/download_request_limiter_unittest.cc +++ b/chrome/browser/download/download_request_limiter_unittest.cc
@@ -453,6 +453,125 @@ download_request_limiter_->GetDownloadUiStatus(web_contents())); } +// Test that history back will not change the tab download state if all the +// previous navigations are renderer-initiated. +TEST_F(DownloadRequestLimiterTest, HistoryBack) { + NavigateAndCommit(GURL("http://foo.com/bar")); + LoadCompleted(); + + // Do one download so we end up in PROMPT. + CanDownload(); + ExpectAndResetCounts(1, 0, 0, __LINE__); + EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); + + // Renderer-initiated navigation to a different host shouldn't reset the + // state. + content::NavigationSimulator::NavigateAndCommitFromDocument( + GURL("http://foobar.com/bar"), web_contents()->GetMainFrame()); + LoadCompleted(); + EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); + + // History back shouldn't reset the state, either. + auto backward_navigation = + content::NavigationSimulator::CreateHistoryNavigation(-1 /* Offset */, + web_contents()); + backward_navigation->Start(); + backward_navigation->Commit(); + EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); + + // Browser-initiated navigation to a different host, which should reset the + // state. + NavigateAndCommit(GURL("http://foobar.com")); + LoadCompleted(); + EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); + CanDownload(); + ExpectAndResetCounts(1, 0, 0, __LINE__); + EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); + + // History back should reset the state as it is going to a different host. + backward_navigation = content::NavigationSimulator::CreateHistoryNavigation( + -1 /* Offset */, web_contents()); + backward_navigation->Start(); + backward_navigation->Commit(); + EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); +} + +// Tab download state shouldn't change when forward/back between to a +// renderer-initiated page. +TEST_F(DownloadRequestLimiterTest, HistoryForwardBack) { + NavigateAndCommit(GURL("http://foo.com/bar")); + LoadCompleted(); + + // Do one download so we end up in PROMPT. + CanDownload(); + ExpectAndResetCounts(1, 0, 0, __LINE__); + EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); + + // Renderer-initiated navigation to a different host shouldn't reset the + // state. + content::NavigationSimulator::NavigateAndCommitFromDocument( + GURL("http://foobar.com/bar"), web_contents()->GetMainFrame()); + LoadCompleted(); + EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); + + // History back shouldn't reset the state, either. + auto backward_navigation = + content::NavigationSimulator::CreateHistoryNavigation(-1 /* Offset */, + web_contents()); + backward_navigation->Start(); + backward_navigation->Commit(); + EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); + + // History forward shouldn't reset the state, as the host is encountered + // before. + auto forward_navigation = + content::NavigationSimulator::CreateHistoryNavigation(1 /* Offset */, + web_contents()); + forward_navigation->Start(); + forward_navigation->Commit(); + EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); + + // History backward again, nothing should change. + backward_navigation = content::NavigationSimulator::CreateHistoryNavigation( + -1 /* Offset */, web_contents()); + backward_navigation->Start(); + backward_navigation->Commit(); + EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, + download_request_limiter_->GetDownloadStatus(web_contents())); + EXPECT_EQ(DownloadRequestLimiter::DOWNLOAD_UI_DEFAULT, + download_request_limiter_->GetDownloadUiStatus(web_contents())); +} + TEST_F(DownloadRequestLimiterTest, DownloadRequestLimiter_ResetOnUserGesture) { NavigateAndCommit(GURL("http://foo.com/bar")); LoadCompleted();
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index e3a17ea..0cd773d 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -23,13 +23,6 @@ "../ui/toolbar/toolbar_actions_model.h", "../ui/toolbar/toolbar_actions_model_factory.cc", "../ui/toolbar/toolbar_actions_model_factory.h", - "../web_applications/web_app.cc", - "../web_applications/web_app.h", - "../web_applications/web_app_chromeos.cc", - "../web_applications/web_app_mac.h", - "../web_applications/web_app_mac.mm", - "../web_applications/web_app_win.cc", - "../web_applications/web_app_win.h", "active_install_data.cc", "active_install_data.h", "active_tab_permission_granter.cc", @@ -807,6 +800,7 @@ "//chrome/browser/media/router/discovery", "//chrome/browser/resource_coordinator:mojo_bindings", "//chrome/browser/safe_browsing", + "//chrome/browser/web_applications/extensions", "//chrome/common", "//chrome/common/extensions:mojo_bindings", "//chrome/common/extensions/api:api_registration",
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc index 797cc57..322cdabd 100644 --- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc +++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -15,8 +15,10 @@ #include "base/json/json_string_value_serializer.h" #include "base/macros.h" #include "base/memory/scoped_refptr.h" +#include "base/optional.h" #include "base/path_service.h" #include "base/rand_util.h" +#include "base/run_loop.h" #include "base/synchronization/lock.h" #include "base/test/metrics/histogram_tester.h" #include "base/threading/thread_restrictions.h" @@ -58,6 +60,7 @@ #include "extensions/common/api/declarative_net_request/test_utils.h" #include "extensions/common/constants.h" #include "extensions/common/extension_id.h" +#include "extensions/common/file_util.h" #include "extensions/common/url_pattern.h" #include "extensions/test/extension_test_message_listener.h" #include "ipc/ipc_message.h" @@ -117,12 +120,84 @@ DISALLOW_COPY_AND_ASSIGN(URLRequestMonitor); }; -// Helper to set the TestObserver for RulesetManager on the IO thread. -void SetRulesetManagerObserverOnIOThread(RulesetManager::TestObserver* observer, - scoped_refptr<InfoMap> info_map) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - info_map->GetRulesetManager()->SetObserverForTest(observer); -} +// Used to wait till the number of rulesets managed by the RulesetManager reach +// a certain count. +class RulesetCountWaiter : public RulesetManager::TestObserver { + public: + RulesetCountWaiter() = default; + + void WaitForRulesetCount(size_t count) { + { + base::AutoLock lock(lock_); + ASSERT_FALSE(expected_count_); + if (current_count_ == count) + return; + expected_count_ = count; + run_loop_ = std::make_unique<base::RunLoop>(); + } + + run_loop_->Run(); + } + + private: + // RulesetManager::TestObserver implementation. + void OnRulesetCountChanged(size_t count) override { + base::AutoLock lock(lock_); + current_count_ = count; + if (expected_count_ != count) + return; + + ASSERT_TRUE(run_loop_.get()); + + // The run-loop has either started or a task on the UI thread to start it is + // underway. RunLoop::Quit is thread-safe and should post a task to the UI + // thread to quit the run-loop. + run_loop_->Quit(); + expected_count_.reset(); + } + + // Accessed on both the UI and IO threads. Access is synchronized using + // |lock_|. + size_t current_count_ = 0; + base::Optional<size_t> expected_count_; + std::unique_ptr<base::RunLoop> run_loop_; + + base::Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(RulesetCountWaiter); +}; + +// Helper to set (and reset on destruction) the given +// RulesetManager::TestObserver on the IO thread. Lifetime of |observer| should +// be managed by clients. +class ScopedRulesetManagerTestObserver { + public: + ScopedRulesetManagerTestObserver(RulesetManager::TestObserver* observer, + scoped_refptr<InfoMap> info_map) + : info_map_(std::move(info_map)) { + SetRulesetManagerTestObserver(observer); + } + + ~ScopedRulesetManagerTestObserver() { + SetRulesetManagerTestObserver(nullptr); + } + + private: + void SetRulesetManagerTestObserver(RulesetManager::TestObserver* observer) { + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::BindOnce( + [](RulesetManager::TestObserver* observer, InfoMap* info_map) { + info_map->GetRulesetManager()->SetObserverForTest(observer); + }, + observer, base::RetainedRef(info_map_))); + content::RunAllTasksUntilIdle(); + } + + scoped_refptr<InfoMap> info_map_; + + DISALLOW_COPY_AND_ASSIGN(ScopedRulesetManagerTestObserver); +}; class DeclarativeNetRequestBrowserTest : public ExtensionBrowserTest, @@ -1127,13 +1202,9 @@ // script.js. URLRequestMonitor script_monitor( embedded_test_server()->GetURL("example.com", "/cached/script.js")); - scoped_refptr<InfoMap> info_map = - base::WrapRefCounted(ExtensionSystem::Get(profile())->info_map()); - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&SetRulesetManagerObserverOnIOThread, &script_monitor, - info_map)); - content::RunAllTasksUntilIdle(); + ScopedRulesetManagerTestObserver scoped_observer( + &script_monitor, + base::WrapRefCounted(ExtensionSystem::Get(profile())->info_map())); GURL url = embedded_test_server()->GetURL( "example.com", "/cached/page_with_cacheable_script.html"); @@ -1184,12 +1255,6 @@ EXPECT_TRUE( base::FeatureList::IsEnabled(network::features::kNetworkService) || script_monitor.GetAndResetRequestSeen(false)); - - // Clear RulesetManager's observer. - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::BindOnce(&SetRulesetManagerObserverOnIOThread, nullptr, info_map)); - content::RunAllTasksUntilIdle(); } // Tests that proxy requests aren't intercepted. See https://crbug.com/794674. @@ -1658,6 +1723,102 @@ } } +// Tests that we correctly reindex a corrupted ruleset. This is only tested for +// packed extensions, since the JSON ruleset is reindexed on each extension +// load for unpacked extensions, so corruption is not an issue. +IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest_Packed, + CorruptedIndexedRuleset) { + // Set-up an observer for RulesetMatcher to monitor the number of extension + // rulesets. + RulesetCountWaiter ruleset_count_waiter; + ScopedRulesetManagerTestObserver scoped_observer( + &ruleset_count_waiter, + base::WrapRefCounted(ExtensionSystem::Get(profile())->info_map())); + + const GURL url = embedded_test_server()->GetURL( + "google.com", "/pages_with_script/index.html"); + + // Verifies whether |url| was successfully loaded. + auto verify_page_load = [this, &url](bool success) { + ui_test_utils::NavigateToURL(browser(), url); + EXPECT_EQ(success, WasFrameWithScriptLoaded(GetMainFrame())); + + content::PageType expected_page_type = + success ? content::PAGE_TYPE_NORMAL : content::PAGE_TYPE_ERROR; + EXPECT_EQ(expected_page_type, GetPageType()); + }; + + // Initially no main frame requests should be blocked. + { + SCOPED_TRACE("Initial page load"); + verify_page_load(true); + } + + // Load an extension which blocks all main frame requests. + TestRule rule = CreateGenericRule(); + rule.condition->url_filter = std::string("*"); + rule.condition->resource_types = std::vector<std::string>({"main_frame"}); + ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules({rule})); + ruleset_count_waiter.WaitForRulesetCount(1); + + const ExtensionId extension_id = last_loaded_extension_id(); + const base::FilePath extension_path = + extension_service() + ->GetExtensionById(extension_id, false /*include_disabled*/) + ->path(); + + // Loading the extension should cause main frame requests to be blocked. + { + SCOPED_TRACE("Page load after loading extension"); + verify_page_load(false); + } + + // Overwrite the indexed ruleset file with arbitrary data to mimic corruption. + { + base::ScopedAllowBlockingForTesting scoped_allow_blocking; + std::string corrupted_data = "data"; + ASSERT_EQ(static_cast<int>(corrupted_data.size()), + base::WriteFile(file_util::GetIndexedRulesetPath(extension_path), + corrupted_data.c_str(), corrupted_data.size())); + } + + // The extension should still continue to work since it doesn't need the + // indexed ruleset while it is loaded. + verify_page_load(false); + + // Now reload the extension and verify that we detect indexed ruleset + // corruption and reindex the JSON ruleset. + { + DisableExtension(extension_id); + ruleset_count_waiter.WaitForRulesetCount(0); + + base::HistogramTester tester; + EnableExtension(extension_id); + ruleset_count_waiter.WaitForRulesetCount(1); + + // Verify that loading the ruleset would have failed initially due to + // checksum mismatch and later succeeded. + EXPECT_EQ(1, tester.GetBucketCount( + "Extensions.DeclarativeNetRequest.LoadRulesetResult", + RulesetMatcher::LoadRulesetResult:: + kLoadErrorRulesetVerification /*sample*/)); + EXPECT_EQ(1, + tester.GetBucketCount( + "Extensions.DeclarativeNetRequest.LoadRulesetResult", + RulesetMatcher::LoadRulesetResult::kLoadSuccess /*sample*/)); + + // Verify that reindexing succeeded. + tester.ExpectUniqueSample( + "Extensions.DeclarativeNetRequest.RulesetReindexSuccessful", + true /*sample*/, 1 /*count*/); + + // The reindexing of the ruleset should cause the extension to work + // correctly. + SCOPED_TRACE("Page load after ruleset corruption"); + verify_page_load(false); + } +} + // Test fixture to verify that host permissions for the request url and the // request initiator are properly checked. Loads an example.com url with four // sub-frames named frame_[1..4] from hosts frame_[1..4].com. The initiator for
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc index ae93d6c..27e3b46 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc +++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -873,8 +873,9 @@ switch (update.host_access) { case developer::HOST_ACCESS_ON_CLICK: - // TODO(devlin): We should also clear specific granted sites here. - // https://crbug.com/844128. + modifier.SetWithholdHostPermissions(true); + modifier.RemoveAllGrantedHostPermissions(); + break; case developer::HOST_ACCESS_ON_SPECIFIC_SITES: modifier.SetWithholdHostPermissions(true); break;
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc index 766f422..e5c2c388 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc +++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -137,6 +137,11 @@ void GetProfileConfiguration( std::unique_ptr<api::developer_private::ProfileInfo>* profile_info); + // Runs the API function to update host access for the given |extension| to + // |new_access|. + void RunUpdateHostAccess(const Extension& extension, + base::StringPiece new_access); + virtual bool ProfileIsSupervised() const { return false; } Browser* browser() { return browser_.get(); } @@ -317,6 +322,20 @@ api::developer_private::ProfileInfo::FromValue(*response_value); } +void DeveloperPrivateApiUnitTest::RunUpdateHostAccess( + const Extension& extension, + base::StringPiece new_access) { + SCOPED_TRACE(new_access); + ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture; + scoped_refptr<UIThreadExtensionFunction> function = base::MakeRefCounted< + api::DeveloperPrivateUpdateExtensionConfigurationFunction>(); + std::string args = + base::StringPrintf(R"([{"extensionId": "%s", "hostAccess": "%s"}])", + extension.id().c_str(), new_access.data()); + EXPECT_TRUE(api_test_utils::RunFunction(function.get(), args, profile())) + << function->GetError(); +} + void DeveloperPrivateApiUnitTest::SetUp() { ExtensionServiceTestBase::SetUp(); @@ -1396,32 +1415,83 @@ EXPECT_FALSE(modifier.HasWithheldHostPermissions()); - auto run_update_host_access = [this, - extension](base::StringPiece new_access) { - SCOPED_TRACE(new_access); - ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture; - scoped_refptr<UIThreadExtensionFunction> function = base::MakeRefCounted< - api::DeveloperPrivateUpdateExtensionConfigurationFunction>(); - std::string args = - base::StringPrintf(R"([{"extensionId": "%s", "hostAccess": "%s"}])", - extension->id().c_str(), new_access.data()); - EXPECT_TRUE(api_test_utils::RunFunction(function.get(), args, profile())) - << function->GetError(); - }; - - run_update_host_access("ON_CLICK"); + RunUpdateHostAccess(*extension, "ON_CLICK"); EXPECT_TRUE(modifier.HasWithheldHostPermissions()); - run_update_host_access("ON_ALL_SITES"); + RunUpdateHostAccess(*extension, "ON_ALL_SITES"); EXPECT_FALSE(modifier.HasWithheldHostPermissions()); - run_update_host_access("ON_SPECIFIC_SITES"); + RunUpdateHostAccess(*extension, "ON_SPECIFIC_SITES"); EXPECT_TRUE(modifier.HasWithheldHostPermissions()); +} - // TODO(devlin): Test behavior of specific granted hosts (e.g. in the case of - // `on specific sites` -> `on click`) once we revoke granted hosts in that - // transition. - // https://crbug.com/844128. +TEST_F(DeveloperPrivateApiUnitTest, + UpdateHostAccess_SpecificSitesRemovedOnTransitionToOnClick) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kRuntimeHostPermissions); + + scoped_refptr<const Extension> extension = + ExtensionBuilder("test").AddPermission("<all_urls>").Build(); + service()->AddExtension(extension.get()); + ScriptingPermissionsModifier modifier(profile(), extension.get()); + modifier.SetWithholdHostPermissions(true); + + RunUpdateHostAccess(*extension, "ON_SPECIFIC_SITES"); + const GURL example_com("https://example.com"); + modifier.GrantHostPermission(example_com); + EXPECT_TRUE(modifier.HasWithheldHostPermissions()); + EXPECT_TRUE(modifier.HasGrantedHostPermission(example_com)); + + RunUpdateHostAccess(*extension, "ON_CLICK"); + EXPECT_TRUE(modifier.HasWithheldHostPermissions()); + EXPECT_FALSE(modifier.HasGrantedHostPermission(example_com)); + + // NOTE(devlin): It's a bit unfortunate that by cycling between host access + // settings, a user loses any stored state. This would be painful if the user + // had set "always run on foo" for a dozen or so sites, and accidentally + // changed the setting. + // There are ways we could address this, such as introducing a tri-state for + // the preference and keeping a stored set of any granted host permissions, + // but this then results in a funny edge case: + // - User has "on specific sites" set, with access to example.com and + // chromium.org granted. + // - User changes to "on click" -> no sites are granted. + // - User visits google.com, and says "always run on this site." This changes + // the setting back to "on specific sites", and will implicitly re-grant + // example.com and chromium.org permissions, without any additional + // prompting. + // To avoid this, we just clear any granted permissions when the user + // transitions between states. Since this is definitely a power-user surface, + // this is likely okay. + RunUpdateHostAccess(*extension, "ON_SPECIFIC_SITES"); + EXPECT_TRUE(modifier.HasWithheldHostPermissions()); + EXPECT_FALSE(modifier.HasGrantedHostPermission(example_com)); +} + +TEST_F(DeveloperPrivateApiUnitTest, + UpdateHostAccess_SpecificSitesRemovedOnTransitionToAllSites) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kRuntimeHostPermissions); + + scoped_refptr<const Extension> extension = + ExtensionBuilder("test").AddPermission("<all_urls>").Build(); + service()->AddExtension(extension.get()); + ScriptingPermissionsModifier modifier(profile(), extension.get()); + modifier.SetWithholdHostPermissions(true); + + RunUpdateHostAccess(*extension, "ON_SPECIFIC_SITES"); + const GURL example_com("https://example.com"); + modifier.GrantHostPermission(example_com); + EXPECT_TRUE(modifier.HasWithheldHostPermissions()); + EXPECT_TRUE(modifier.HasGrantedHostPermission(example_com)); + + RunUpdateHostAccess(*extension, "ON_ALL_SITES"); + EXPECT_FALSE(modifier.HasWithheldHostPermissions()); + EXPECT_TRUE(modifier.HasGrantedHostPermission(example_com)); + + RunUpdateHostAccess(*extension, "ON_SPECIFIC_SITES"); + EXPECT_TRUE(modifier.HasWithheldHostPermissions()); + EXPECT_FALSE(modifier.HasGrantedHostPermission(example_com)); } class DeveloperPrivateZipInstallerUnitTest
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc index ce4c2358..2d68735 100644 --- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc +++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -211,7 +211,7 @@ if (!controller->enabled()) return true; return controller->SetDraggableArea( - gfx::Rect(rect.top, rect.left, rect.width, rect.height)); + gfx::Rect(rect.left, rect.top, rect.width, rect.height)); } bool ChromeVirtualKeyboardDelegate::SetRequestedKeyboardState(int state_enum) {
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc index c78b29cb..90d8c719 100644 --- a/chrome/browser/extensions/chrome_extensions_browser_client.cc +++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -290,6 +290,15 @@ ExternalProtocolHandler::PermitLaunchUrl(); } +bool ChromeExtensionsBrowserClient::IsInDemoMode() { +#if defined(OS_CHROMEOS) + // TODO(michaelpg): Implement for real. + return false; +#else + return false; +#endif +} + bool ChromeExtensionsBrowserClient::IsRunningInForcedAppMode() { return chrome::IsRunningInForcedAppMode(); }
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.h b/chrome/browser/extensions/chrome_extensions_browser_client.h index 49cef1d..1d11de87 100644 --- a/chrome/browser/extensions/chrome_extensions_browser_client.h +++ b/chrome/browser/extensions/chrome_extensions_browser_client.h
@@ -100,6 +100,7 @@ std::unique_ptr<ExtensionHostDelegate> CreateExtensionHostDelegate() override; bool DidVersionUpdate(content::BrowserContext* context) override; void PermitExternalProtocolHandler() override; + bool IsInDemoMode() override; bool IsRunningInForcedAppMode() override; bool IsAppModeForcedForApp(const ExtensionId& extension_id) override; bool IsLoggedInAsPublicAccount() override;
diff --git a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc index 6f9dc4a..68605012 100644 --- a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc +++ b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
@@ -210,7 +210,9 @@ {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})); return std::make_unique<gcm::GCMProfileService>( profile->GetPrefs(), profile->GetPath(), profile->GetRequestContext(), - nullptr /* url_loader_factory */, chrome::GetChannel(), + content::BrowserContext::GetDefaultStoragePartition(profile) + ->GetURLLoaderFactoryForBrowserProcess(), + chrome::GetChannel(), gcm::GetProductCategoryForSubtypes(profile->GetPrefs()), SigninManagerFactory::GetForProfile(profile), ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
diff --git a/chrome/browser/extensions/scripting_permissions_modifier.cc b/chrome/browser/extensions/scripting_permissions_modifier.cc index 40faaa1..119676c 100644 --- a/chrome/browser/extensions/scripting_permissions_modifier.cc +++ b/chrome/browser/extensions/scripting_permissions_modifier.cc
@@ -5,7 +5,6 @@ #include "chrome/browser/extensions/scripting_permissions_modifier.h" #include "base/feature_list.h" -#include "chrome/browser/extensions/extension_sync_service.h" #include "chrome/browser/extensions/permissions_updater.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" @@ -163,14 +162,6 @@ WithholdHostPermissions(); else GrantWithheldHostPermissions(); - - // If this was an update to permissions, we also need to sync the change. - // TODO(devlin): This isn't currently necessary. We should remove it and add - // it back. - ExtensionSyncService* sync_service = - ExtensionSyncService::Get(browser_context_); - if (sync_service) // |sync_service| can be null in unittests. - sync_service->SyncExtensionChangeIfNeeded(*extension_); } bool ScriptingPermissionsModifier::HasWithheldHostPermissions() const {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 1fc44e3..26cd8bf 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2862,6 +2862,9 @@ const char kArcCupsApiDescription[] = "Enables support of libcups APIs from ARC"; +const char kArcInputMethodName[] = "Enable ARC input methods."; +const char kArcInputMethodDescription[] = "Enable ARC input methods."; + const char kArcNativeBridgeExperimentName[] = "Enable native bridge experiment for ARC"; const char kArcNativeBridgeExperimentDescription[] = @@ -2950,6 +2953,10 @@ "different captive portals. This enables opening captive portal " "authorization dialog in a separate window, which ignores proxy settings."; +const char kChromeVoxArcSupportName[] = "ChromeVox ARC support"; +const char kChromeVoxArcSupportDescription[] = + "Use ChromeVox screen reader features in ARC"; + const char kCrOSComponentName[] = "Chrome OS Component"; const char kCrOSComponentDescription[] = "Disable the use of componentized escpr CUPS filter."; @@ -3001,10 +3008,6 @@ const char kEnableBackgroundBlurDescription[] = "Enables background blur for the Peeking Launcher and Tab Switcher."; -const char kEnableChromevoxArcSupportName[] = "ChromeVox ARC support"; -const char kEnableChromevoxArcSupportDescription[] = - "Enable ChromeVox screen reader features in ARC"; - const char kEnableDisplayZoomSettingName[] = "Enable display zoom settings"; const char kEnableDisplayZoomSettingDescription[] = "Allows the user to modify the display size or zoom via the chrome display " @@ -3304,6 +3307,10 @@ const char kUiModeClamshell[] = "Clamshell"; const char kUiModeAuto[] = "Auto (default)"; +const char kUnfilteredBluetoothDevicesName[] = "Unfiltered Bluetooth devices"; +const char kUnfilteredBluetoothDevicesDescription[] = + "Shows all Bluetooth devices in UI (System Tray/Settings Page.)"; + const char kUseMashName[] = "Out-of-process system UI (mash)"; const char kUseMashDescription[] = "Runs the mojo UI service (mus) and the ash window manager and system UI "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 67e26c8..a740d21 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1751,6 +1751,9 @@ extern const char kArcCupsApiName[]; extern const char kArcCupsApiDescription[]; +extern const char kArcInputMethodName[]; +extern const char kArcInputMethodDescription[]; + extern const char kArcNativeBridgeExperimentName[]; extern const char kArcNativeBridgeExperimentDescription[]; @@ -1808,6 +1811,9 @@ extern const char kCaptivePortalBypassProxyName[]; extern const char kCaptivePortalBypassProxyDescription[]; +extern const char kChromeVoxArcSupportName[]; +extern const char kChromeVoxArcSupportDescription[]; + extern const char kCrOSComponentName[]; extern const char kCrOSComponentDescription[]; @@ -1841,9 +1847,6 @@ extern const char kEnableBackgroundBlurName[]; extern const char kEnableBackgroundBlurDescription[]; -extern const char kEnableChromevoxArcSupportName[]; -extern const char kEnableChromevoxArcSupportDescription[]; - extern const char kEnableDisplayZoomSettingName[]; extern const char kEnableDisplayZoomSettingDescription[]; @@ -2020,6 +2023,9 @@ extern const char kUiModeClamshell[]; extern const char kUiModeAuto[]; +extern const char kUnfilteredBluetoothDevicesName[]; +extern const char kUnfilteredBluetoothDevicesDescription[]; + extern const char kUseMashName[]; extern const char kUseMashDescription[];
diff --git a/chrome/browser/gcm/gcm_profile_service_unittest.cc b/chrome/browser/gcm/gcm_profile_service_unittest.cc index e7bc07c..6a13ab8 100644 --- a/chrome/browser/gcm/gcm_profile_service_unittest.cc +++ b/chrome/browser/gcm/gcm_profile_service_unittest.cc
@@ -33,6 +33,7 @@ #include "components/signin/core/browser/signin_manager.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/storage_partition.h" #include "content/public/test/test_browser_thread_bundle.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" @@ -52,7 +53,9 @@ {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})); return std::make_unique<gcm::GCMProfileService>( profile->GetPrefs(), profile->GetPath(), profile->GetRequestContext(), - nullptr /* url_loader_factory */, chrome::GetChannel(), + content::BrowserContext::GetDefaultStoragePartition(profile) + ->GetURLLoaderFactoryForBrowserProcess(), + chrome::GetChannel(), gcm::GetProductCategoryForSubtypes(profile->GetPrefs()), SigninManagerFactory::GetForProfile(profile), ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc index 106c1a8..0146a7c 100644 --- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc +++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
@@ -59,6 +59,7 @@ #include "net/url_request/url_request_filter.h" #include "services/network/public/cpp/features.h" #include "testing/gmock/include/gmock/gmock-matchers.h" +#include "third_party/blink/public/common/service_worker/service_worker_utils.h" #if !BUILDFLAG(ENABLE_DICE_SUPPORT) #include "components/signin/core/browser/signin_header_helper.h" @@ -245,6 +246,9 @@ // The network service code path doesn't go through ResourceDispatcherHost. if (base::FeatureList::IsEnabled(network::features::kNetworkService)) return; + // Servicified service worker doesn't set NavigationData. + if (blink::ServiceWorkerUtils::IsServicificationEnabled()) + return; ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url()); {
diff --git a/chrome/browser/media/router/mojo/media_router_desktop.cc b/chrome/browser/media/router/mojo/media_router_desktop.cc index 02f46c8..b4bb0b2 100644 --- a/chrome/browser/media/router/mojo/media_router_desktop.cc +++ b/chrome/browser/media/router/mojo/media_router_desktop.cc
@@ -73,7 +73,6 @@ MediaRouterDesktop::MediaRouterDesktop(content::BrowserContext* context) : MediaRouterDesktop(context, DualMediaSinkService::GetInstance()) { - InitializeMediaRouteProviders(); #if defined(OS_WIN) CanFirewallUseLocalPorts( base::BindOnce(&MediaRouterDesktop::OnFirewallCheckComplete, @@ -213,14 +212,33 @@ } void MediaRouterDesktop::InitializeExtensionMediaRouteProviderProxy() { + if (!extension_provider_proxy_) { + extension_provider_proxy_ = + std::make_unique<ExtensionMediaRouteProviderProxy>(context()); + } mojom::MediaRouteProviderPtr extension_provider_proxy_ptr; - extension_provider_proxy_ = - std::make_unique<ExtensionMediaRouteProviderProxy>( - context(), mojo::MakeRequest(&extension_provider_proxy_ptr)); + extension_provider_proxy_->Bind( + mojo::MakeRequest(&extension_provider_proxy_ptr)); + extension_provider_proxy_ptr.set_connection_error_handler(base::BindOnce( + &MediaRouterDesktop::OnExtensionProviderError, base::Unretained(this))); media_route_providers_[MediaRouteProviderId::EXTENSION] = std::move(extension_provider_proxy_ptr); } +void MediaRouterDesktop::OnExtensionProviderError() { + // The message pipe for |extension_provider_proxy_| might error out due to + // Media Router extension causing dropped callbacks. Detect this case and + // recover by re-creating the pipe. + DVLOG(2) << "Extension MRP encountered error."; + if (extension_provider_error_count_ >= kMaxMediaRouteProviderErrorCount) + return; + + ++extension_provider_error_count_; + DVLOG(2) << "Reconnecting to extension MRP: " + << extension_provider_error_count_; + InitializeExtensionMediaRouteProviderProxy(); +} + void MediaRouterDesktop::InitializeWiredDisplayMediaRouteProvider() { mojom::MediaRouterPtr media_router_ptr; MediaRouterMojoImpl::BindToMojoRequest(mojo::MakeRequest(&media_router_ptr));
diff --git a/chrome/browser/media/router/mojo/media_router_desktop.h b/chrome/browser/media/router/mojo/media_router_desktop.h index c0aa802b..60df9a7 100644 --- a/chrome/browser/media/router/mojo/media_router_desktop.h +++ b/chrome/browser/media/router/mojo/media_router_desktop.h
@@ -32,6 +32,11 @@ public: ~MediaRouterDesktop() override; + // Max number of Mojo connection error counts on a MediaRouteProvider message + // pipe before MediaRouterDesktop treats it as a permanent error. Used for + // ExtensionMediaRouteProviderProxy only. + static constexpr int kMaxMediaRouteProviderErrorCount = 10; + // Sets up the MediaRouter instance owned by |context| to handle // MediaRouterObserver requests from the component extension given by // |extension|. Creates the MediaRouterMojoImpl instance if it does not @@ -60,7 +65,8 @@ friend class MediaRouterDesktopTestBase; friend class MediaRouterFactory; FRIEND_TEST_ALL_PREFIXES(MediaRouterDesktopTest, ProvideSinks); - + FRIEND_TEST_ALL_PREFIXES(MediaRouterDesktopTest, + ExtensionMrpRecoversFromConnectionError); // This constructor performs a firewall check on Windows and is not suitable // for use in unit tests; instead use the constructor below. explicit MediaRouterDesktop(content::BrowserContext* context); @@ -114,6 +120,10 @@ void InitializeCastMediaRouteProvider(); void InitializeDialMediaRouteProvider(); + // Invoked when a Mojo connection error is encountered with the message pipe + // to |extension_provider_proxy_|. + void OnExtensionProviderError(); + #if defined(OS_WIN) // Ensures that mDNS discovery is enabled in the MRPM extension. This can be // called many times but the MRPM will only be called once per registration @@ -160,6 +170,10 @@ bool should_enable_mdns_discovery_ = false; #endif + // The number of times a Mojo connection error is encountered with the + // message pipe to |extension_provider_proxy_|. + int extension_provider_error_count_ = 0; + base::WeakPtrFactory<MediaRouterDesktop> weak_factory_; DISALLOW_COPY_AND_ASSIGN(MediaRouterDesktop);
diff --git a/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc b/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc index e0889be..6be45a72 100644 --- a/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc +++ b/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc
@@ -201,4 +201,22 @@ TestJoinRoute(kCastPresentationIdPrefix + std::string("123")); } +TEST_F(MediaRouterDesktopTest, ExtensionMrpRecoversFromConnectionError) { + MediaRouterDesktop* media_router_desktop = + static_cast<MediaRouterDesktop*>(router()); + auto* extension_mrp_proxy = + media_router_desktop->extension_provider_proxy_.get(); + // |media_router_desktop| detects connection error and reconnects with + // |extension_mrp_proxy|. + for (int i = 0; i < MediaRouterDesktop::kMaxMediaRouteProviderErrorCount; + i++) { + extension_mrp_proxy->binding_.Unbind(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(extension_mrp_proxy->binding_.is_bound()); + } + extension_mrp_proxy->binding_.Unbind(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(extension_mrp_proxy->binding_.is_bound()); +} + } // namespace media_router
diff --git a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.cc b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.cc index e2bf625d..dc072ef 100644 --- a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.cc +++ b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.cc
@@ -15,15 +15,22 @@ namespace media_router { ExtensionMediaRouteProviderProxy::ExtensionMediaRouteProviderProxy( - content::BrowserContext* context, - mojom::MediaRouteProviderRequest request) - : binding_(this, std::move(request)), + content::BrowserContext* context) + : binding_(this), request_manager_( EventPageRequestManagerFactory::GetApiForBrowserContext(context)), weak_factory_(this) {} ExtensionMediaRouteProviderProxy::~ExtensionMediaRouteProviderProxy() = default; +void ExtensionMediaRouteProviderProxy::Bind( + mojom::MediaRouteProviderRequest request) { + // This method is called when the previous Binding became invalid. We close it + // first to make sure it is in a clean state. + binding_.Close(); + binding_.Bind(std::move(request)); +} + void ExtensionMediaRouteProviderProxy::CreateRoute( const std::string& media_source, const std::string& sink_id,
diff --git a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.h b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.h index 47eaeec..0d7ccd9 100644 --- a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.h +++ b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy.h
@@ -31,10 +31,13 @@ // the requests. class ExtensionMediaRouteProviderProxy : public mojom::MediaRouteProvider { public: - ExtensionMediaRouteProviderProxy(content::BrowserContext* context, - mojom::MediaRouteProviderRequest request); + explicit ExtensionMediaRouteProviderProxy(content::BrowserContext* context); ~ExtensionMediaRouteProviderProxy() override; + // Binds |request| to |this|. If |this| is already bound to a previous + // request, that previous request will be dropped. + void Bind(mojom::MediaRouteProviderRequest request); + // mojom::MediaRouteProvider implementation. Forwards the calls to // |media_route_provider_| through |request_manager_|. void CreateRoute(const std::string& media_source, @@ -102,6 +105,9 @@ void SetExtensionId(const std::string& extension_id); private: + FRIEND_TEST_ALL_PREFIXES(MediaRouterDesktopTest, + ExtensionMrpRecoversFromConnectionError); + // These methods call the corresponding |media_route_provider_| methods. // Passed to |request_manager_| as requests to be run when the Mojo connection // to the provider is established.
diff --git a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc index cebd90ad..d1adf2f 100644 --- a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc +++ b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc
@@ -64,8 +64,9 @@ std::move(request).Run(); })); - provider_proxy_ = std::make_unique<ExtensionMediaRouteProviderProxy>( - &profile_, mojo::MakeRequest(&provider_proxy_ptr_)); + provider_proxy_ = + std::make_unique<ExtensionMediaRouteProviderProxy>(&profile_); + provider_proxy_->Bind(mojo::MakeRequest(&provider_proxy_ptr_)); RegisterMockMediaRouteProvider(); }
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc index 7aeef806..9292687 100644 --- a/chrome/browser/net/system_network_context_manager.cc +++ b/chrome/browser/net/system_network_context_manager.cc
@@ -228,6 +228,7 @@ // SharedURLLoaderFactory implementation: std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); return std::make_unique<network::CrossThreadSharedURLLoaderFactoryInfo>( this); }
diff --git a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc index 0194d31d..bda0dd5 100644 --- a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc +++ b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
@@ -36,8 +36,7 @@ #include "components/offline_pages/core/offline_page_metadata_store.h" #include "components/offline_pages/core/request_header/offline_page_navigation_ui_data.h" #include "components/offline_pages/core/stub_system_download_manager.h" -#include "components/previews/core/previews_decider.h" -#include "components/previews/core/previews_experiments.h" +#include "components/previews/core/previews_user_data.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/resource_request_info.h" #include "content/public/browser/web_contents.h" @@ -246,41 +245,6 @@ DISALLOW_COPY_AND_ASSIGN(TestNetworkChangeNotifier); }; -class TestPreviewsDecider : public previews::PreviewsDecider { - public: - TestPreviewsDecider() : should_allow_preview_(false) {} - ~TestPreviewsDecider() override {} - - bool ShouldAllowPreview(const net::URLRequest& request, - previews::PreviewsType type) const override { - return should_allow_preview_; - } - - bool ShouldAllowPreviewAtECT( - const net::URLRequest& request, - previews::PreviewsType type, - net::EffectiveConnectionType effective_connection_type_threshold, - const std::vector<std::string>& host_blacklist_from_server, - bool ignore_long_term_black_list_rules) const override { - return should_allow_preview_; - } - - bool IsURLAllowedForPreview(const net::URLRequest& request, - previews::PreviewsType type) const override { - return should_allow_preview_; - } - - bool should_allow_preview() const { return should_allow_preview_; } - void set_should_allow_preview(bool should_allow_preview) { - should_allow_preview_ = should_allow_preview; - } - - private: - bool should_allow_preview_; - - DISALLOW_COPY_AND_ASSIGN(TestPreviewsDecider); -}; - // TODO(jianli, carlosk): This should be removed in favor of using with // OfflinePageTestArchiver. class TestOfflinePageArchiver : public OfflinePageArchiver { @@ -537,18 +501,18 @@ return is_offline_page_set_in_navigation_data_; } - TestPreviewsDecider* test_previews_decider() { - return test_previews_decider_.get(); - } - bool is_connected_with_good_network() { return network_change_notifier_->online() && // Exclude prohibitively slow network. - !test_previews_decider_->should_allow_preview() && + !allow_preview() && // Exclude flaky network. offline_page_header_.reason != OfflinePageHeader::Reason::NET_ERROR; } + void set_allow_preview(bool allow_preview) { allow_preview_ = allow_preview; } + + bool allow_preview() const { return allow_preview_; } + private: static std::unique_ptr<KeyedService> BuildTestOfflinePageModel( content::BrowserContext* context); @@ -585,7 +549,7 @@ // setting the state is done first from one thread and reading this state // can be from any other thread later. std::unique_ptr<TestNetworkChangeNotifier> network_change_notifier_; - std::unique_ptr<TestPreviewsDecider> test_previews_decider_; + bool allow_preview_ = false; // These should only be accessed purely from IO thread. base::ScopedTempDir private_archives_temp_base_dir_; @@ -606,8 +570,7 @@ last_offline_id_(0), response_(net::ERR_IO_PENDING), is_offline_page_set_in_navigation_data_(false), - network_change_notifier_(new TestNetworkChangeNotifier), - test_previews_decider_(new TestPreviewsDecider) {} + network_change_notifier_(new TestNetworkChangeNotifier) {} void OfflinePageRequestHandlerTestBase::SetUp() { // Create a test profile. @@ -1136,7 +1099,7 @@ // Install the interceptor. std::unique_ptr<net::URLRequestInterceptor> interceptor( - new OfflinePageRequestInterceptor(test_base_->test_previews_decider())); + new OfflinePageRequestInterceptor()); std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory_impl( new net::URLRequestJobFactoryImpl()); intercepting_job_factory_.reset(new TestURLRequestInterceptingJobFactory( @@ -1170,6 +1133,8 @@ url_request_delegate_.get()); request->set_method(method); + previews::PreviewsUserData::Create(request.get(), 1u); + content::ResourceRequestInfo::AllocateForTesting( request.get(), is_main_frame ? content::RESOURCE_TYPE_MAIN_FRAME @@ -1180,7 +1145,9 @@ /*render_frame_id=*/1, /*is_main_frame=*/true, /*allow_download=*/true, - /*is_async=*/true, content::PREVIEWS_OFF, + /*is_async=*/true, + test_base_->allow_preview() ? content::OFFLINE_PAGE_ON + : content::PREVIEWS_OFF, std::make_unique<ChromeNavigationUIData>()); return request; @@ -1348,9 +1315,9 @@ return; url_loader_->SetTabIdGetterForTesting(base::BindRepeating(&GetTabId, kTabId)); - url_loader_->SetShouldAllowPreviewCallbackForTesting(base::BindRepeating( - &TestPreviewsDecider::should_allow_preview, - base::Unretained(test_base_->test_previews_decider()))); + url_loader_->SetShouldAllowPreviewCallbackForTesting( + base::BindRepeating(&OfflinePageRequestHandlerTestBase::allow_preview, + base::Unretained(test_base_))); } void OfflinePageURLLoaderBuilder::InterceptRequest( @@ -1525,7 +1492,7 @@ TYPED_TEST(OfflinePageRequestHandlerTest, LoadOfflinePageOnProhibitivelySlowNetwork) { this->SimulateHasNetworkConnectivity(true); - this->test_previews_decider()->set_should_allow_preview(true); + this->set_allow_preview(true); int64_t offline_id = this->SaveInternalPage(kUrl, GURL(), kFilename1, kFileSize1, std::string()); @@ -1541,7 +1508,7 @@ TYPED_TEST(OfflinePageRequestHandlerTest, DontLoadReloadOfflinePageOnProhibitivelySlowNetwork) { this->SimulateHasNetworkConnectivity(true); - this->test_previews_decider()->set_should_allow_preview(true); + this->set_allow_preview(true); int64_t offline_id = this->SaveInternalPage(kUrl, GURL(), kFilename1, kFileSize1, std::string()); @@ -1565,7 +1532,7 @@ TYPED_TEST(OfflinePageRequestHandlerTest, PageNotFoundOnProhibitivelySlowNetwork) { this->SimulateHasNetworkConnectivity(true); - this->test_previews_decider()->set_should_allow_preview(true); + this->set_allow_preview(true); int64_t offline_id = this->SaveInternalPage(kUrl, GURL(), kFilename1, kFileSize1, std::string()); @@ -1902,7 +1869,7 @@ TYPED_TEST(OfflinePageRequestHandlerTest, FileSizeMismatchOnProhibitivelySlowNetwork) { this->SimulateHasNetworkConnectivity(true); - this->test_previews_decider()->set_should_allow_preview(true); + this->set_allow_preview(true); // Save an offline page in public location with mismatched file size. int64_t offline_id = this->SavePublicPage(kUrl, GURL(), kFilename1, @@ -1970,7 +1937,7 @@ TYPED_TEST(OfflinePageRequestHandlerTest, DigestMismatchOnProhibitivelySlowNetwork) { this->SimulateHasNetworkConnectivity(true); - this->test_previews_decider()->set_should_allow_preview(true); + this->set_allow_preview(true); // Save an offline page in public location with mismatched digest. int64_t offline_id = this->SavePublicPage(kUrl, GURL(), kFilename1,
diff --git a/chrome/browser/offline_pages/offline_page_request_interceptor.cc b/chrome/browser/offline_pages/offline_page_request_interceptor.cc index 8355a6e..1f66c09 100644 --- a/chrome/browser/offline_pages/offline_page_request_interceptor.cc +++ b/chrome/browser/offline_pages/offline_page_request_interceptor.cc
@@ -6,15 +6,12 @@ #include "base/supports_user_data.h" #include "chrome/browser/offline_pages/offline_page_request_job.h" -#include "components/previews/core/previews_decider.h" namespace offline_pages { -OfflinePageRequestInterceptor::OfflinePageRequestInterceptor( - previews::PreviewsDecider* previews_decider) - : previews_decider_(previews_decider) {} +OfflinePageRequestInterceptor::OfflinePageRequestInterceptor() = default; -OfflinePageRequestInterceptor::~OfflinePageRequestInterceptor() {} +OfflinePageRequestInterceptor::~OfflinePageRequestInterceptor() = default; net::URLRequestJob* OfflinePageRequestInterceptor::MaybeInterceptRequest( net::URLRequest* request, @@ -22,8 +19,7 @@ // OfflinePageRequestJob::Create may return a nullptr if the interception // is not needed for some sort of requests, like non-main resource request, // non-http request and more. - return OfflinePageRequestJob::Create(request, network_delegate, - previews_decider_); + return OfflinePageRequestJob::Create(request, network_delegate); } } // namespace offline_pages
diff --git a/chrome/browser/offline_pages/offline_page_request_interceptor.h b/chrome/browser/offline_pages/offline_page_request_interceptor.h index 9999791..d91b2d0 100644 --- a/chrome/browser/offline_pages/offline_page_request_interceptor.h +++ b/chrome/browser/offline_pages/offline_page_request_interceptor.h
@@ -14,10 +14,6 @@ class URLRequestJob; } -namespace previews { -class PreviewsDecider; -} - namespace offline_pages { // An interceptor to hijack requests and potentially service them based on @@ -25,8 +21,7 @@ class OfflinePageRequestInterceptor : public net::URLRequestInterceptor { public: // Embedder must guarantee that |previews_decider| outlives |this|. - explicit OfflinePageRequestInterceptor( - previews::PreviewsDecider* previews_decider); + OfflinePageRequestInterceptor(); ~OfflinePageRequestInterceptor() override; private: @@ -35,9 +30,6 @@ net::URLRequest* request, net::NetworkDelegate* network_delegate) const override; - // Used to determine if an URLRequest is eligible for offline previews. - previews::PreviewsDecider* previews_decider_; - DISALLOW_COPY_AND_ASSIGN(OfflinePageRequestInterceptor); };
diff --git a/chrome/browser/offline_pages/offline_page_request_job.cc b/chrome/browser/offline_pages/offline_page_request_job.cc index c91ac454..b1bf1bc2 100644 --- a/chrome/browser/offline_pages/offline_page_request_job.cc +++ b/chrome/browser/offline_pages/offline_page_request_job.cc
@@ -10,7 +10,7 @@ #include "base/time/time.h" #include "chrome/browser/offline_pages/offline_page_utils.h" #include "chrome/browser/renderer_host/chrome_navigation_ui_data.h" -#include "components/previews/core/previews_decider.h" +#include "components/previews/core/previews_user_data.h" #include "content/public/browser/resource_request_info.h" #include "content/public/common/resource_type.h" #include "net/url_request/url_request.h" @@ -27,7 +27,8 @@ OfflinePageRequestInfo() : use_default_(false) {} ~OfflinePageRequestInfo() override {} - static OfflinePageRequestInfo* GetFromRequest(net::URLRequest* request) { + static OfflinePageRequestInfo* GetFromRequest( + const net::URLRequest* request) { return static_cast<OfflinePageRequestInfo*>( request->GetUserData(&kUserDataKey)); } @@ -48,8 +49,7 @@ // static OfflinePageRequestJob* OfflinePageRequestJob::Create( net::URLRequest* request, - net::NetworkDelegate* network_delegate, - previews::PreviewsDecider* previews_decider) { + net::NetworkDelegate* network_delegate) { const content::ResourceRequestInfo* resource_request_info = content::ResourceRequestInfo::ForRequest(request); if (!resource_request_info) @@ -81,15 +81,13 @@ std::make_unique<OfflinePageRequestInfo>()); } - return new OfflinePageRequestJob(request, network_delegate, previews_decider); + return new OfflinePageRequestJob(request, network_delegate); } OfflinePageRequestJob::OfflinePageRequestJob( net::URLRequest* request, - net::NetworkDelegate* network_delegate, - previews::PreviewsDecider* previews_decider) - : net::URLRequestJob(request, network_delegate), - previews_decider_(previews_decider) {} + net::NetworkDelegate* network_delegate) + : net::URLRequestJob(request, network_delegate) {} OfflinePageRequestJob::~OfflinePageRequestJob() {} @@ -164,6 +162,11 @@ DCHECK(info); info->set_use_default(true); + // Clear info in PreviewsUserData. + auto* previews_data = previews::PreviewsUserData::GetData(*request()); + if (previews_data) + previews_data->set_offline_preview_used(false); + net::URLRequestJob::NotifyRestartRequired(); } @@ -199,9 +202,21 @@ } bool OfflinePageRequestJob::ShouldAllowPreview() const { - return previews_decider_ && - previews_decider_->ShouldAllowPreview(*(request()), - previews::PreviewsType::OFFLINE); + const content::ResourceRequestInfo* info = + content::ResourceRequestInfo::ForRequest(request()); + auto* previews_data = previews::PreviewsUserData::GetData(*request()); + + // Trust PreviewsState, but only when previews_data is created. PreviewsData + // is created when the other PreviewsTypes are queried, so it should exist. + bool preview_allowed = previews_data && info && + (info->GetPreviewsState() & content::OFFLINE_PAGE_ON); + + // This takes advantage of the fact that this is only checked when attempting + // to serve a preview. This state is cleared if FallbackToDefault is called. + if (previews_data) + previews_data->set_offline_preview_used(preview_allowed); + + return preview_allowed; } int OfflinePageRequestJob::GetPageTransition() const {
diff --git a/chrome/browser/offline_pages/offline_page_request_job.h b/chrome/browser/offline_pages/offline_page_request_job.h index 9d23729de..dcb46ba 100644 --- a/chrome/browser/offline_pages/offline_page_request_job.h +++ b/chrome/browser/offline_pages/offline_page_request_job.h
@@ -12,10 +12,6 @@ #include "chrome/browser/offline_pages/offline_page_request_handler.h" #include "net/url_request/url_request_job.h" -namespace previews { -class PreviewsDecider; -} - namespace offline_pages { class OfflinePageRequestHandler; @@ -27,10 +23,8 @@ // Creates and returns a job to serve the offline page. Nullptr is returned if // offline page cannot or should not be served. Embedder must gaurantee that // |previews_decider| outlives the returned instance. - static OfflinePageRequestJob* Create( - net::URLRequest* request, - net::NetworkDelegate* network_delegate, - previews::PreviewsDecider* previews_decider); + static OfflinePageRequestJob* Create(net::URLRequest* request, + net::NetworkDelegate* network_delegate); ~OfflinePageRequestJob() override; @@ -42,8 +36,7 @@ private: OfflinePageRequestJob(net::URLRequest* request, - net::NetworkDelegate* network_delegate, - previews::PreviewsDecider* previews_decider); + net::NetworkDelegate* network_delegate); // net::URLRequestJob overrides: void Start() override; @@ -68,9 +61,6 @@ OfflinePageRequestHandler::Delegate::TabIdGetter GetTabIdGetter() const override; - // Used to determine if an URLRequest is eligible for offline previews. - previews::PreviewsDecider* previews_decider_; - std::unique_ptr<OfflinePageRequestHandler> request_handler_; OfflinePageRequestHandler::Delegate::WebContentsGetter web_contents_getter_;
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc index 4003016..0b1cc92 100644 --- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc +++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
@@ -602,7 +602,8 @@ content::RenderFrameHost* render_frame_host, const mojom::PageLoadTiming& timing, const mojom::PageLoadMetadata& metadata, - const mojom::PageLoadFeatures& new_features) { + const mojom::PageLoadFeatures& new_features, + const mojom::PageLoadDataUse& new_data_use) { // We may receive notifications from frames that have been navigated away // from. We simply ignore them. if (GetMainFrame(render_frame_host) != web_contents()->GetMainFrame()) { @@ -635,17 +636,19 @@ if (committed_load_) { committed_load_->metrics_update_dispatcher()->UpdateMetrics( - render_frame_host, timing, metadata, new_features); + render_frame_host, timing, metadata, new_features, new_data_use); } } void MetricsWebContentsObserver::UpdateTiming( const mojom::PageLoadTimingPtr timing, const mojom::PageLoadMetadataPtr metadata, - const mojom::PageLoadFeaturesPtr new_features) { + const mojom::PageLoadFeaturesPtr new_features, + const mojom::PageLoadDataUsePtr new_data_use) { content::RenderFrameHost* render_frame_host = page_load_metrics_binding_.GetCurrentTargetFrame(); - OnTimingUpdated(render_frame_host, *timing, *metadata, *new_features); + OnTimingUpdated(render_frame_host, *timing, *metadata, *new_features, + *new_data_use); } bool MetricsWebContentsObserver::ShouldTrackNavigation(
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.h b/chrome/browser/page_load_metrics/metrics_web_contents_observer.h index 045dfea6..83990ed 100644 --- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.h +++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.h
@@ -145,7 +145,8 @@ void OnTimingUpdated(content::RenderFrameHost* render_frame_host, const mojom::PageLoadTiming& timing, const mojom::PageLoadMetadata& metadata, - const mojom::PageLoadFeatures& new_features); + const mojom::PageLoadFeatures& new_features, + const mojom::PageLoadDataUse& new_data_use); // Informs the observers of the currently committed load that the event // corresponding to |event_key| has occurred. This should not be called within @@ -157,9 +158,10 @@ friend class content::WebContentsUserData<MetricsWebContentsObserver>; // page_load_metrics::mojom::PageLoadMetrics implementation. - void UpdateTiming(mojom::PageLoadTimingPtr timing, - mojom::PageLoadMetadataPtr metadata, - mojom::PageLoadFeaturesPtr new_features) override; + void UpdateTiming(const mojom::PageLoadTimingPtr timing, + const mojom::PageLoadMetadataPtr metadata, + const mojom::PageLoadFeaturesPtr new_features, + const mojom::PageLoadDataUsePtr new_data_use) override; void HandleFailedNavigationForTrackedLoad( content::NavigationHandle* navigation_handle,
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc index f421082..6ca129e6 100644 --- a/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc
@@ -256,9 +256,9 @@ void SimulateTimingUpdateWithoutFiringDispatchTimer( const mojom::PageLoadTiming& timing, content::RenderFrameHost* render_frame_host) { - observer()->OnTimingUpdated(render_frame_host, timing, - mojom::PageLoadMetadata(), - mojom::PageLoadFeatures()); + observer()->OnTimingUpdated( + render_frame_host, timing, mojom::PageLoadMetadata(), + mojom::PageLoadFeatures(), mojom::PageLoadDataUse()); } void AttachObserver() {
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc index bfe3ff0..ba640d9 100644 --- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc +++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_tester.cc
@@ -88,7 +88,7 @@ const mojom::PageLoadMetadata& metadata, const mojom::PageLoadFeatures& new_features) { observer_->OnTimingUpdated(web_contents()->GetMainFrame(), timing, metadata, - new_features); + new_features, mojom::PageLoadDataUse()); // If sending the timing update caused the PageLoadMetricsUpdateDispatcher to // schedule a buffering timer, then fire it now so metrics are dispatched to // observers.
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc index 9c14fd4..4106204 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -68,6 +68,7 @@ #include "net/dns/mock_host_resolver.h" #include "net/http/failing_http_transaction_factory.h" #include "net/http/http_cache.h" +#include "net/test/embedded_test_server/controllable_http_response.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/url_request/url_request_failed_job.h" #include "net/test/url_request/url_request_mock_http_job.h" @@ -126,6 +127,11 @@ page_expected_fields_.Set(field); } + void AddMinimumPageLoadDataUseExpectation( + int expected_minimum_page_load_data_use) { + expected_minimum_page_load_data_use_ = expected_minimum_page_load_data_use; + } + // Whether the given TimingField was observed in the page. bool DidObserveInPage(TimingField field) { return observed_page_fields_.IsSet(field); @@ -189,6 +195,15 @@ run_loop_->Quit(); } + void OnDataUseObserved(int64_t received_data_length, + int64_t data_reduction_proxy_bytes_saved) { + current_page_load_data_use_ += received_data_length; + if (expectations_satisfied() && run_loop_) + run_loop_->Quit(); + } + + int64_t current_page_load_data_use() { return current_page_load_data_use_; } + private: // PageLoadMetricsObserver used by the PageLoadMetricsWaiter to observe // metrics updates. @@ -214,6 +229,13 @@ waiter_->OnLoadedResource(extra_request_complete_info); } + void OnDataUseObserved(int64_t received_data_length, + int64_t data_reduction_proxy_bytes_saved) override { + if (waiter_) + waiter_->OnDataUseObserved(received_data_length, + data_reduction_proxy_bytes_saved); + } + private: const base::WeakPtr<PageLoadMetricsWaiter> waiter_; }; @@ -305,7 +327,10 @@ } bool expectations_satisfied() const { - return subframe_expected_fields_.Empty() && page_expected_fields_.Empty(); + return subframe_expected_fields_.Empty() && page_expected_fields_.Empty() && + (expected_minimum_page_load_data_use_ == 0 || + current_page_load_data_use_ >= + expected_minimum_page_load_data_use_); } std::unique_ptr<base::RunLoop> run_loop_; @@ -315,6 +340,9 @@ TimingFieldBitSet observed_page_fields_; + int64_t expected_minimum_page_load_data_use_ = 0; + int64_t current_page_load_data_use_ = 0; + bool attach_on_tracker_creation_ = false; bool did_add_observer_ = false; @@ -1011,8 +1039,8 @@ histogram_tester_.ExpectUniqueSample( internal::kHistogramFirstMeaningfulPaintStatus, internal::FIRST_MEANINGFUL_PAINT_RECORDED, 1); - histogram_tester_.ExpectTotalCount( - internal::kHistogramFirstMeaningfulPaint, 1); + histogram_tester_.ExpectTotalCount(internal::kHistogramFirstMeaningfulPaint, + 1); histogram_tester_.ExpectTotalCount( internal::kHistogramParseStartToFirstMeaningfulPaint, 1); } @@ -1037,8 +1065,8 @@ histogram_tester_.ExpectUniqueSample( internal::kHistogramFirstMeaningfulPaintStatus, internal::FIRST_MEANINGFUL_PAINT_DID_NOT_REACH_NETWORK_STABLE, 1); - histogram_tester_.ExpectTotalCount( - internal::kHistogramFirstMeaningfulPaint, 0); + histogram_tester_.ExpectTotalCount(internal::kHistogramFirstMeaningfulPaint, + 0); histogram_tester_.ExpectTotalCount( internal::kHistogramParseStartToFirstMeaningfulPaint, 0); } @@ -1996,3 +2024,90 @@ ASSERT_NO_FATAL_FAILURE(WaitForTabsToLoad(new_browser)); ExpectFirstPaintMetricsTotalCount(1); } + +// TODO(rajendrant): Add tests for data reduction proxy savings, and tests for +// page loads in brand new renderers that the navigation response is recorded +// (e.g. do window.open('/some-cross-site-page')). +IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, ReceivedDataLength) { + ASSERT_TRUE(embedded_test_server()->Start()); + + auto waiter = CreatePageLoadMetricsWaiter(); + waiter->AddPageExpectation(TimingField::LOAD_EVENT); + ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL( + "/page_load_metrics/large.html")); + waiter->AddMinimumPageLoadDataUseExpectation(10000); + waiter->Wait(); +} + +IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, + ReceivedDataLengthControlledLoad) { + const char kHttpResponseHeader[] = + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html; charset=utf-8\r\n" + "\r\n"; + + auto main_html_response = + std::make_unique<net::test_server::ControllableHttpResponse>( + embedded_test_server(), "/mock_page.html", + true /*relative_url_is_prefix*/); + auto css_response = + std::make_unique<net::test_server::ControllableHttpResponse>( + embedded_test_server(), "/mock_css.css", + true /*relative_url_is_prefix*/); + ASSERT_TRUE(embedded_test_server()->Start()); + + auto waiter = CreatePageLoadMetricsWaiter(); + + browser()->OpenURL(content::OpenURLParams( + embedded_test_server()->GetURL("/mock_page.html"), content::Referrer(), + WindowOpenDisposition::CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false)); + + main_html_response->WaitForRequest(); + main_html_response->Send(kHttpResponseHeader); + main_html_response->Send( + "<html><link rel=\"stylesheet\" href=\"mock_css.css\">"); + main_html_response->Send(std::string(1000, ' ')); + // TODO(rajendrant): Verify that 1000 bytes are received at this point before + // the request completes. This is hard to verify now since + // MojoAsyncResourceHandler throttles the transfer size updates, and calls + // only when a read is called after 1 second from previous update. + + main_html_response->Send("</html>"); + main_html_response->Send(std::string(1000, ' ')); + main_html_response->Done(); + waiter->AddMinimumPageLoadDataUseExpectation(2000); + waiter->Wait(); + + css_response->WaitForRequest(); + css_response->Send(kHttpResponseHeader); + css_response->Send(std::string(1000, ' ')); + css_response->Done(); + waiter->AddMinimumPageLoadDataUseExpectation(3000); + waiter->Wait(); +} + +IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, + ReceivedDataLengthCrossSiteIframe) { + embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data"); + content::SetupCrossSiteRedirector(embedded_test_server()); + ASSERT_TRUE(embedded_test_server()->Start()); + + auto waiter = CreatePageLoadMetricsWaiter(); + waiter->AddPageExpectation(TimingField::LOAD_EVENT); + ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL( + "foo.com", "/cross_site_iframe_factory.html?foo")); + waiter->Wait(); + int64_t one_frame_page_size = waiter->current_page_load_data_use(); + + waiter = CreatePageLoadMetricsWaiter(); + waiter->AddPageExpectation(TimingField::LOAD_EVENT); + ui_test_utils::NavigateToURL( + browser(), + embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b,c,d(e,f,g))")); + // Verify that 7 iframes are fetched, with some amount of tolerance since + // favicon is fetched only once. + waiter->AddMinimumPageLoadDataUseExpectation(7 * (one_frame_page_size - 100)); + waiter->Wait(); +}
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.h b/chrome/browser/page_load_metrics/page_load_metrics_observer.h index 35798425..ce97795a 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
@@ -420,6 +420,14 @@ virtual void OnFeaturesUsageObserved(const mojom::PageLoadFeatures& features, const PageLoadExtraInfo& extra_info) {} + // Invoked when data use is observed for the page load across all frames. + // These bytes are the additional bytes reported since the last call to + // OnDataUseObserved. |received_data_length| is the received network bytes. + // |data_reduction_proxy_bytes_saved| is the bytes saved by the data reduction + // proxy, which could be negative if the proxy had inflated the resource. + virtual void OnDataUseObserved(int64_t received_data_length, + int64_t data_reduction_proxy_bytes_saved) {} + // Invoked when a media element starts playing. virtual void MediaStartedPlaying( const content::WebContentsObserver::MediaPlayerInfo& video_type,
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.cc b/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.cc index 418470e..7389407 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.cc
@@ -430,7 +430,8 @@ content::RenderFrameHost* render_frame_host, const mojom::PageLoadTiming& new_timing, const mojom::PageLoadMetadata& new_metadata, - const mojom::PageLoadFeatures& new_features) { + const mojom::PageLoadFeatures& new_features, + const mojom::PageLoadDataUse& new_data_use) { if (render_frame_host->GetLastCommittedURL().SchemeIs( extensions::kExtensionScheme)) { // Extensions can inject child frames into a page. We don't want to track @@ -446,6 +447,7 @@ UpdateSubFrameTiming(render_frame_host, new_timing); } client_->UpdateFeaturesUsage(new_features); + client_->UpdateDataUse(new_data_use); } void PageLoadMetricsUpdateDispatcher::UpdateFeatures(
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h b/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h index 7d1f5bfd..70728700 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h +++ b/chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h
@@ -109,6 +109,7 @@ virtual void OnSubframeMetadataChanged() = 0; virtual void UpdateFeaturesUsage( const mojom::PageLoadFeatures& new_features) = 0; + virtual void UpdateDataUse(const mojom::PageLoadDataUse& new_data_use) = 0; }; // The |client| instance must outlive this object. @@ -121,7 +122,8 @@ void UpdateMetrics(content::RenderFrameHost* render_frame_host, const mojom::PageLoadTiming& new_timing, const mojom::PageLoadMetadata& new_metadata, - const mojom::PageLoadFeatures& new_features); + const mojom::PageLoadFeatures& new_features, + const mojom::PageLoadDataUse& new_data_use); // This method is only intended to be called for PageLoadFeatures being // recorded directly from the browser process. Features coming from the @@ -158,6 +160,8 @@ void MaybeDispatchTimingUpdates(bool did_merge_new_timing_value); void DispatchTimingUpdates(); + void UpdateDataUse(const mojom::PageLoadDataUse& new_data_use); + // The client is guaranteed to outlive this object. Client* const client_;
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc index 817c2512..eedce78 100644 --- a/chrome/browser/page_load_metrics/page_load_tracker.cc +++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -643,4 +643,12 @@ } } +void PageLoadTracker::UpdateDataUse( + const mojom::PageLoadDataUse& new_data_use) { + for (const auto& observer : observers_) { + observer->OnDataUseObserved(new_data_use.received_data_length, + new_data_use.data_reduction_proxy_bytes_saved); + } +} + } // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.h b/chrome/browser/page_load_metrics/page_load_tracker.h index da20db9..4c52200 100644 --- a/chrome/browser/page_load_metrics/page_load_tracker.h +++ b/chrome/browser/page_load_metrics/page_load_tracker.h
@@ -180,6 +180,7 @@ void OnSubframeMetadataChanged() override; void UpdateFeaturesUsage( const mojom::PageLoadFeatures& new_features) override; + void UpdateDataUse(const mojom::PageLoadDataUse& new_datause) override; void Redirect(content::NavigationHandle* navigation_handle); void WillProcessNavigationResponse(
diff --git a/chrome/browser/previews/previews_browsertest.cc b/chrome/browser/previews/previews_browsertest.cc index 105414b..436615d9 100644 --- a/chrome/browser/previews/previews_browsertest.cc +++ b/chrome/browser/previews/previews_browsertest.cc
@@ -231,8 +231,8 @@ void SetNoScriptWhitelist( std::vector<std::string> whitelisted_noscript_sites) { const optimization_guide::ComponentInfo& component_info = - test_component_creator_.CreateComponentInfoWithNoScriptWhitelist( - whitelisted_noscript_sites); + test_component_creator_.CreateComponentInfoWithWhitelist( + optimization_guide::proto::NOSCRIPT, whitelisted_noscript_sites); g_browser_process->optimization_guide_service()->ProcessHints( component_info);
diff --git a/chrome/browser/previews/previews_infobar_tab_helper.cc b/chrome/browser/previews/previews_infobar_tab_helper.cc index 9534499..cd1e07e 100644 --- a/chrome/browser/previews/previews_infobar_tab_helper.cc +++ b/chrome/browser/previews/previews_infobar_tab_helper.cc
@@ -100,6 +100,8 @@ offline_pages::OfflinePageTabHelper::FromWebContents(web_contents()); if (tab_helper && tab_helper->GetOfflinePreviewItem()) { + DCHECK_EQ(previews::PreviewsType::OFFLINE, + previews_user_data_->committed_previews_type()); if (navigation_handle->IsErrorPage()) { // TODO(ryansturm): Add UMA for errors. return;
diff --git a/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc b/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc index a8681d2..4f0038f 100644 --- a/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc +++ b/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc
@@ -261,6 +261,8 @@ true); base::RunLoop().RunUntilIdle(); + SetCommittedPreviewsType(previews::PreviewsType::OFFLINE); + CallDidFinishNavigation(); EXPECT_EQ(1U, infobar_service()->infobar_count());
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc new file mode 100644 index 0000000..c8ab4c9 --- /dev/null +++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
@@ -0,0 +1,286 @@ +// 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. + +#include "base/command_line.h" +#include "base/run_loop.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_feature_list.h" +#include "build/build_config.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/metrics/subprocess_metrics_provider.h" +#include "chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "components/optimization_guide/optimization_guide_service.h" +#include "components/optimization_guide/test_component_creator.h" +#include "components/previews/core/previews_black_list.h" +#include "components/previews/core/previews_features.h" +#include "content/public/test/browser_test_utils.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" + +namespace { + +// Retries fetching |histogram_name| until it contains at least |count| samples. +void RetryForHistogramUntilCountReached(base::HistogramTester* histogram_tester, + const std::string& histogram_name, + size_t count) { + base::RunLoop().RunUntilIdle(); + for (size_t attempt = 0; attempt < 3; ++attempt) { + const std::vector<base::Bucket> buckets = + histogram_tester->GetAllSamples(histogram_name); + size_t total_count = 0; + for (const auto& bucket : buckets) + total_count += bucket.count; + if (total_count >= count) + return; + content::FetchHistogramsFromChildProcesses(); + SubprocessMetricsProvider::MergeHistogramDeltasForTesting(); + base::RunLoop().RunUntilIdle(); + } +} + +} // namespace + +// This test class sets up everything but does not enable any features. +class ResourceLoadingNoFeaturesBrowserTest : public InProcessBrowserTest { + public: + ResourceLoadingNoFeaturesBrowserTest() = default; + + ~ResourceLoadingNoFeaturesBrowserTest() override = default; + + void SetUpOnMainThread() override { + // Set up https server with resource monitor. + https_server_.reset( + new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS)); + https_server_->ServeFilesFromSourceDirectory("chrome/test/data/previews"); + https_server_->RegisterRequestMonitor(base::BindRepeating( + &ResourceLoadingNoFeaturesBrowserTest::MonitorResourceRequest, + base::Unretained(this))); + ASSERT_TRUE(https_server_->Start()); + + https_url_ = https_server_->GetURL("/resource_loading_hints.html"); + ASSERT_TRUE(https_url_.SchemeIs(url::kHttpsScheme)); + + https_no_transform_url_ = https_server_->GetURL( + "/resource_loading_hints_with_no_transform_header.html"); + ASSERT_TRUE(https_no_transform_url_.SchemeIs(url::kHttpsScheme)); + + // Set up http server with resource monitor and redirect handler. + http_server_.reset( + new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTP)); + http_server_->ServeFilesFromSourceDirectory("chrome/test/data/previews"); + http_server_->RegisterRequestMonitor(base::BindRepeating( + &ResourceLoadingNoFeaturesBrowserTest::MonitorResourceRequest, + base::Unretained(this))); + http_server_->RegisterRequestHandler(base::BindRepeating( + &ResourceLoadingNoFeaturesBrowserTest::HandleRedirectRequest, + base::Unretained(this))); + ASSERT_TRUE(http_server_->Start()); + + http_url_ = http_server_->GetURL("/resource_loading_hints.html"); + ASSERT_TRUE(http_url_.SchemeIs(url::kHttpScheme)); + + redirect_url_ = http_server_->GetURL("/redirect.html"); + ASSERT_TRUE(redirect_url_.SchemeIs(url::kHttpScheme)); + } + + void SetUpCommandLine(base::CommandLine* cmd) override { + cmd->AppendSwitch("enable-spdy-proxy-auth"); + cmd->AppendSwitchASCII("force-effective-connection-type", "Slow-2G"); + } + + void SetResourceLoadingHintsWhitelist( + std::vector<std::string> whitelisted_resource_loading_hints_sites) { + const optimization_guide::ComponentInfo& component_info = + test_component_creator_.CreateComponentInfoWithWhitelist( + optimization_guide::proto::RESOURCE_LOADING, + whitelisted_resource_loading_hints_sites); + g_browser_process->optimization_guide_service()->ProcessHints( + component_info); + + // Wait for hints to be processed by PreviewsOptimizationGuide. + base::RunLoop().RunUntilIdle(); + } + + const GURL& https_url() const { return https_url_; } + const GURL& https_no_transform_url() const { return https_no_transform_url_; } + const GURL& http_url() const { return http_url_; } + const GURL& redirect_url() const { return redirect_url_; } + + protected: + base::test::ScopedFeatureList scoped_feature_list_; + + private: + // Called by |https_server_|. + void MonitorResourceRequest(const net::test_server::HttpRequest& request) {} + + std::unique_ptr<net::test_server::HttpResponse> HandleRedirectRequest( + const net::test_server::HttpRequest& request) { + std::unique_ptr<net::test_server::BasicHttpResponse> response; + if (request.GetURL().spec().find("redirect") != std::string::npos) { + response.reset(new net::test_server::BasicHttpResponse); + response->set_code(net::HTTP_FOUND); + response->AddCustomHeader("Location", https_url().spec()); + } + return std::move(response); + } + + optimization_guide::testing::TestComponentCreator test_component_creator_; + + std::unique_ptr<net::EmbeddedTestServer> https_server_; + std::unique_ptr<net::EmbeddedTestServer> http_server_; + GURL https_url_; + GURL https_no_transform_url_; + GURL http_url_; + GURL redirect_url_; + + DISALLOW_COPY_AND_ASSIGN(ResourceLoadingNoFeaturesBrowserTest); +}; + +// This test class enables ResourceLoadingHints with OptimizationHints. +class ResourceLoadingHintsBrowserTest + : public ResourceLoadingNoFeaturesBrowserTest { + public: + ResourceLoadingHintsBrowserTest() = default; + + ~ResourceLoadingHintsBrowserTest() override = default; + + void SetUp() override { + // Enabling NoScript should have no effect since resource loading takes + // priority over NoScript. + scoped_feature_list_.InitWithFeatures( + {previews::features::kPreviews, previews::features::kNoScriptPreviews, + previews::features::kOptimizationHints, + previews::features::kResourceLoadingHints}, + {}); + ResourceLoadingNoFeaturesBrowserTest::SetUp(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ResourceLoadingHintsBrowserTest); +}; + +// Previews InfoBar (which these tests triggers) does not work on Mac. +// See crbug.com/782322 for details. Also occasional flakes on win7 +// (crbug.com/789542). +#if !defined(OS_MACOSX) && !defined(OS_WIN) +#define MAYBE_ResourceLoadingHintsHttpsWhitelisted \ + ResourceLoadingHintsHttpsWhitelisted +#define MAYBE_ResourceLoadingHintsHttpsWhitelistedRedirectToHttps \ + ResourceLoadingHintsHttpsWhitelistedRedirectToHttps +#else +#define MAYBE_ResourceLoadingHintsHttpsWhitelisted \ + DISABLED_ResourceLoadingHintsHttpsWhitelisted +#define MAYBE_ResourceLoadingHintsHttpsWhitelistedRedirectToHttps \ + DISABLED_ResourceLoadingHintsHttpsWhitelistedRedirectToHttps +#endif + +IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest, + MAYBE_ResourceLoadingHintsHttpsWhitelisted) { + // Whitelist test URL for resource loading hints. + SetResourceLoadingHintsWhitelist({https_url().host()}); + base::HistogramTester histogram_tester; + + ui_test_utils::NavigateToURL(browser(), https_url()); + + RetryForHistogramUntilCountReached( + &histogram_tester, "ResourceLoadingHints.CountBlockedSubresourcePatterns", + 1); + histogram_tester.ExpectBucketCount( + "Previews.EligibilityReason.ResourceLoadingHints", + static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1); + histogram_tester.ExpectBucketCount( + "Previews.InfoBarAction.ResourceLoadingHints", 0, 1); + histogram_tester.ExpectBucketCount( + "ResourceLoadingHints.CountBlockedSubresourcePatterns", 1, 1); + + // Load the same webpage to ensure that the resource loading hints are sent + // again. + ui_test_utils::NavigateToURL(browser(), https_url()); + RetryForHistogramUntilCountReached( + &histogram_tester, "ResourceLoadingHints.CountBlockedSubresourcePatterns", + 2); + histogram_tester.ExpectBucketCount( + "Previews.EligibilityReason.ResourceLoadingHints", + static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 2); + histogram_tester.ExpectBucketCount( + "Previews.InfoBarAction.ResourceLoadingHints", 0, 2); + histogram_tester.ExpectBucketCount( + "ResourceLoadingHints.CountBlockedSubresourcePatterns", 1, 2); +} + +IN_PROC_BROWSER_TEST_F( + ResourceLoadingHintsBrowserTest, + MAYBE_ResourceLoadingHintsHttpsWhitelistedRedirectToHttps) { + SetResourceLoadingHintsWhitelist({https_url().host()}); + base::HistogramTester histogram_tester; + ui_test_utils::NavigateToURL(browser(), redirect_url()); + + RetryForHistogramUntilCountReached( + &histogram_tester, "ResourceLoadingHints.CountBlockedSubresourcePatterns", + 1); + histogram_tester.ExpectBucketCount( + "Previews.EligibilityReason.ResourceLoadingHints", + static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1); + histogram_tester.ExpectTotalCount( + "Previews.InfoBarAction.ResourceLoadingHints", 1); + histogram_tester.ExpectBucketCount( + "ResourceLoadingHints.CountBlockedSubresourcePatterns", 1, 1); +} + +IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest, + ResourceLoadingHintsHttpsNoWhitelisted) { + base::HistogramTester histogram_tester; + // The URL is not whitelisted. + ui_test_utils::NavigateToURL(browser(), https_url()); + + base::RunLoop().RunUntilIdle(); + histogram_tester.ExpectBucketCount( + "Previews.EligibilityReason.ResourceLoadingHints", + static_cast<int>( + previews::PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER), + 1); + histogram_tester.ExpectTotalCount( + "Previews.InfoBarAction.ResourceLoadingHints", 0); + histogram_tester.ExpectTotalCount( + "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0); +} + +IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest, + ResourceLoadingHintsHttp) { + // Whitelist test HTTP URL for resource loading hints. + SetResourceLoadingHintsWhitelist({https_url().host()}); + base::HistogramTester histogram_tester; + + ui_test_utils::NavigateToURL(browser(), http_url()); + base::RunLoop().RunUntilIdle(); + + histogram_tester.ExpectBucketCount( + "Previews.EligibilityReason.ResourceLoadingHints", + static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1); + histogram_tester.ExpectTotalCount( + "Previews.InfoBarAction.ResourceLoadingHints", 0); + histogram_tester.ExpectTotalCount( + "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0); +} + +IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest, + ResourceLoadingHintsHttpsWhitelistedNoTransform) { + // Whitelist test URL for resource loading hints. + SetResourceLoadingHintsWhitelist({https_url().host()}); + base::HistogramTester histogram_tester; + + ui_test_utils::NavigateToURL(browser(), https_no_transform_url()); + base::RunLoop().RunUntilIdle(); + + histogram_tester.ExpectBucketCount( + "Previews.EligibilityReason.ResourceLoadingHints", + static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1); + histogram_tester.ExpectTotalCount( + "Previews.InfoBarAction.ResourceLoadingHints", 0); + histogram_tester.ExpectTotalCount( + "ResourceLoadingHints.CountBlockedSubresourcePatterns", 0); +}
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc new file mode 100644 index 0000000..9296ece --- /dev/null +++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc
@@ -0,0 +1,77 @@ +// 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. + +#include "chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "chrome/browser/loader/chrome_navigation_data.h" +#include "chrome/browser/profiles/profile.h" +#include "components/previews/content/previews_content_util.h" +#include "components/previews/core/previews_experiments.h" +#include "components/previews/core/previews_user_data.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" +#include "services/service_manager/public/cpp/interface_provider.h" +#include "third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom.h" +#include "url/gurl.h" + +DEFINE_WEB_CONTENTS_USER_DATA_KEY(ResourceLoadingHintsWebContentsObserver); + +ResourceLoadingHintsWebContentsObserver:: + ~ResourceLoadingHintsWebContentsObserver() {} + +ResourceLoadingHintsWebContentsObserver:: + ResourceLoadingHintsWebContentsObserver(content::WebContents* web_contents) + : content::WebContentsObserver(web_contents) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); +} + +void ResourceLoadingHintsWebContentsObserver::DidFinishNavigation( + content::NavigationHandle* navigation_handle) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (!navigation_handle->IsInMainFrame() || + !navigation_handle->HasCommitted() || + navigation_handle->IsSameDocument() || navigation_handle->IsErrorPage()) { + return; + } + + // Store Previews information for this navigation. + ChromeNavigationData* nav_data = static_cast<ChromeNavigationData*>( + navigation_handle->GetNavigationData()); + if (!nav_data || !nav_data->previews_user_data()) + return; + + previews::PreviewsUserData* previews_user_data = + nav_data->previews_user_data(); + + if (previews_user_data->committed_previews_type() != + previews::PreviewsType::RESOURCE_LOADING_HINTS) { + return; + } + + DCHECK(previews::params::IsResourceLoadingHintsEnabled()); + SendResourceLoadingHints(navigation_handle); +} + +void ResourceLoadingHintsWebContentsObserver::SendResourceLoadingHints( + content::NavigationHandle* navigation_handle) const { + // Hints should be sent only after the renderer frame has committed. + DCHECK(navigation_handle->HasCommitted()); + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + DCHECK(navigation_handle->GetURL().SchemeIsHTTPOrHTTPS()); + + blink::mojom::PreviewsResourceLoadingHintsReceiverPtr hints_receiver_ptr; + web_contents()->GetMainFrame()->GetRemoteInterfaces()->GetInterface( + &hints_receiver_ptr); + blink::mojom::PreviewsResourceLoadingHintsPtr hints_ptr = + blink::mojom::PreviewsResourceLoadingHints::New(); + + // TOOD(tbansal): https://crbug.com/856243. Send an actual list of resource + // URLs to block. + hints_ptr->subresources_to_block.push_back(std::string()); + hints_receiver_ptr->SetResourceLoadingHints(std::move(hints_ptr)); +}
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h new file mode 100644 index 0000000..8f15a18 --- /dev/null +++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h
@@ -0,0 +1,41 @@ +// 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. + +#ifndef CHROME_BROWSER_PREVIEWS_RESOURCE_LOADING_HINTS_RESOURCE_LOADING_HINTS_WEB_CONTENTS_OBSERVER_H_ +#define CHROME_BROWSER_PREVIEWS_RESOURCE_LOADING_HINTS_RESOURCE_LOADING_HINTS_WEB_CONTENTS_OBSERVER_H_ + +#include "base/macros.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" + +// Observes navigation events and sends the resource loading hints mojo message +// to the renderer. +class ResourceLoadingHintsWebContentsObserver + : public content::WebContentsObserver, + public content::WebContentsUserData< + ResourceLoadingHintsWebContentsObserver> { + public: + ~ResourceLoadingHintsWebContentsObserver() override; + + private: + friend class content::WebContentsUserData< + ResourceLoadingHintsWebContentsObserver>; + + explicit ResourceLoadingHintsWebContentsObserver( + content::WebContents* web_contents); + + // Overridden from content::WebContentsObserver. If the navigation is of type + // resource loading hints preview, then this method sends the resource loading + // hints mojo message to the renderer. + void DidFinishNavigation( + content::NavigationHandle* navigation_handle) override; + + // Sends resource loading hints to the renderer. + void SendResourceLoadingHints( + content::NavigationHandle* navigation_handle) const; + + DISALLOW_COPY_AND_ASSIGN(ResourceLoadingHintsWebContentsObserver); +}; + +#endif // CHROME_BROWSER_PREVIEWS_RESOURCE_LOADING_HINTS_RESOURCE_LOADING_HINTS_WEB_CONTENTS_OBSERVER_H_
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc index 6e6d35c..626eec0 100644 --- a/chrome/browser/profiles/profile_impl_io_data.cc +++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -512,8 +512,7 @@ // Install the Offline Page Interceptor. #if BUILDFLAG(ENABLE_OFFLINE_PAGES) request_interceptors.push_back( - std::make_unique<offline_pages::OfflinePageRequestInterceptor>( - previews_decider_impl())); + std::make_unique<offline_pages::OfflinePageRequestInterceptor>()); #endif // The data reduction proxy interceptor should be as close to the network
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css index b87a48b..b01d0447 100644 --- a/chrome/browser/resources/local_ntp/most_visited_single.css +++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -394,6 +394,7 @@ .md-tile:hover { background-color: rgba(33, 32, 36, 0.06); + transition-duration: 0ms; } body.dark-theme .md-tile:hover { @@ -402,6 +403,7 @@ .md-tile:hover > .md-menu { opacity: 1; + transition-duration: 0ms; } .md-tile:active,
diff --git a/chrome/browser/resources/md_extensions/detail_view.html b/chrome/browser/resources/md_extensions/detail_view.html index b7c90ce..caa9d9e 100644 --- a/chrome/browser/resources/md_extensions/detail_view.html +++ b/chrome/browser/resources/md_extensions/detail_view.html
@@ -4,6 +4,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html"> <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html"> <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html"> +<link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_tooltip_icon.html"> <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html"> @@ -15,7 +16,6 @@ <link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> @@ -234,7 +234,7 @@ <div id="runtime-warnings" aria-describedby="a11yAssociation" hidden$="[[!data.runtimeWarnings.length]]" class="section continuation warning control-line"> - <iron-icon class="warning-icon" icon="error"></iron-icon> + <iron-icon class="warning-icon" icon="cr:error"></iron-icon> <span> <template is="dom-repeat" items="[[data.runtimeWarnings]]"> [[item]]
diff --git a/chrome/browser/resources/md_extensions/drop_overlay.html b/chrome/browser/resources/md_extensions/drop_overlay.html index c32bcde..3eb0139 100644 --- a/chrome/browser/resources/md_extensions/drop_overlay.html +++ b/chrome/browser/resources/md_extensions/drop_overlay.html
@@ -1,11 +1,11 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html"> +<link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/html/cr/ui/drag_wrapper.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html"> <link rel="import" href="drag_and_drop_handler.html"> <dom-module id="extensions-drop-overlay"> @@ -43,7 +43,7 @@ } </style> <div id="container"> - <iron-icon icon="extension"></iron-icon> + <iron-icon icon="cr:extension"></iron-icon> <div id="text">$i18n{dropToInstall}</div> </div> </template>
diff --git a/chrome/browser/resources/md_extensions/error_page.html b/chrome/browser/resources/md_extensions/error_page.html index 3561de2..aa4b986 100644 --- a/chrome/browser/resources/md_extensions/error_page.html +++ b/chrome/browser/resources/md_extensions/error_page.html
@@ -2,6 +2,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_behavior.html"> <link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html"> +<link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> @@ -9,7 +10,7 @@ <link rel="import" href="chrome://resources/html/cr/ui/focus_outline_manager.html"> <link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> @@ -36,11 +37,11 @@ flex-shrink: 0; } - iron-icon[icon=warning] { + iron-icon[icon='cr:warning'] { --iron-icon-fill-color: var(--paper-orange-500); } - iron-icon[icon=error] { + iron-icon[icon='cr:error'] { --iron-icon-fill-color: var(--paper-red-700); } @@ -191,7 +192,7 @@ on-keydown="onErrorItemAction_" tabindex="0" role="button" aria-expanded$="[[isAriaExpanded_( index, selectedEntry_)]]"> - <iron-icon icon$="[[computeErrorIcon_(item)]]" + <iron-icon icon$="cr:[[computeErrorIcon_(item)]]" title$="[[computeErrorTypeLabel_(item)]]"> </iron-icon> <div id$="[[item.id]]" class="error-message">
diff --git a/chrome/browser/resources/md_extensions/icons.html b/chrome/browser/resources/md_extensions/icons.html index f05904be..9af6920 100644 --- a/chrome/browser/resources/md_extensions/icons.html +++ b/chrome/browser/resources/md_extensions/icons.html
@@ -18,43 +18,9 @@ <path d="M20,5H4A2,2,0,0,0,2,7V17a2,2,0,0,0,2,2H20a2,2,0,0,0,2-2V7A2,2,0,0,0,20,5ZM9,17a5,5,0,1,1,5-5A5,5,0,0,1,9,17Zm11,1a1,1,0,1,1,1-1A1,1,0,0,1,20,18ZM20,8a1,1,0,1,1,1-1A1,1,0,0,1,20,8Z"></path> </g> - <!-- SVG from Google. --> - <g id="store" width="24px" height="24px" viewBox="0 0 192 192"> - <defs> - <path id="a" d="M8 20v140c0 6.6 5.4 12 12 12h152c6.6 0 12-5.4 12-12V20H8zm108 32H76c-4.42 0-8-3.58-8-8s3.58-8 8-8h40c4.42 0 8 3.58 8 8s-3.58 8-8 8z"></path> - </defs> - <clipPath id="b"> - <use xlink:href="#a" overflow="visible"></use> - </clipPath> - <path clip-path="url(#b)" fill="#eee" d="M8 20h176v152H8z"></path> - <path fill="#fff" d="M116 36H76c-4.42 0-8 3.58-8 8s3.58 8 8 8h40c4.42 0 8-3.58 8-8s-3.58-8-8-8z" clip-path="url(#b)"></path> - <g clip-path="url(#b)"> - <defs> - <circle id="c" cx="96" cy="160" r="76"></circle> - </defs> - <clipPath id="d"> - <use xlink:href="#c" overflow="visible"></use> - </clipPath> - <path d="M32.07 84v93.27h34.01L96 125.45h76V84zm0 0v93.27h34.01L96 125.45h76V84z" clip-path="url(#d)" fill="#DB4437"></path> - <path d="M20 236h72.34l33.58-33.58v-25.14l-59.84-.01L20 98.24zm0 0h72.34l33.58-33.58v-25.14l-59.84-.01L20 98.24z" clip-path="url(#d)" fill="#0F9D58"></path> - <path d="M96 125.45l29.92 51.82L92.35 236H172V125.45zm0 0l29.92 51.82L92.35 236H172V125.45z" clip-path="url(#d)" fill="#FFCD40"></path> - <g clip-path="url(#d)"> - <circle fill="#F1F1F1" cx="96" cy="160" r="34.55"></circle> - <circle fill="#4285F4" cx="96" cy="160" r="27.64"></circle> - </g> - </g> - <path clip-path="url(#b)" fill="#212121" fill-opacity=".05" d="M8 20h176v76H8z"></path> - <path fill="#212121" fill-opacity=".02" d="M8 95h176v1H8z"></path> - <path fill="#fff" fill-opacity=".05" d="M8 96h176v1H8z"></path> - <path fill="#212121" fill-opacity=".02" d="M116 52H76c-4.25 0-7.72-3.32-7.97-7.5-.02.17-.03.33-.03.5 0 4.42 3.58 8 8 8h40c4.42 0 8-3.58 8-8 0-.17-.01-.33-.03-.5-.25 4.18-3.72 7.5-7.97 7.5zM8 20v1h176v-1H8z"></path> - <path fill="#231F20" fill-opacity=".1" d="M76 36h40c4.25 0 7.72 3.32 7.97 7.5.01-.17.03-.33.03-.5 0-4.42-3.58-8-8-8H76c-4.42 0-8 3.58-8 8 0 .17.01.33.03.5.25-4.18 3.72-7.5 7.97-7.5zm96 135H20c-6.6 0-12-5.4-12-12v1c0 6.6 5.4 12 12 12h152c6.6 0 12-5.4 12-12v-1c0 6.6-5.4 12-12 12z"></path> - <radialGradient id="e" cx="7.502" cy="19.344" r="227.596" gradientUnits="userSpaceOnUse"> - <stop offset="0" stop-color="#fff" stop-opacity=".1"></stop> - <stop offset="1" stop-color="#fff" stop-opacity="0"></stop> - </radialGradient> - <path fill="url(#e)" d="M8 20v140c0 6.6 5.4 12 12 12h152c6.6 0 12-5.4 12-12V20H8zm108 32H76c-4.42 0-8-3.58-8-8s3.58-8 8-8h40c4.42 0 8 3.58 8 8s-3.58 8-8 8z"></path> - <path fill="none" d="M0 0h192v192H0z"></path> - </g> + <!-- Copied from iron-icons. --> + <g id="input"><path d="M21 3.01H3c-1.1 0-2 .9-2 2V9h2V4.99h18v14.03H3V15H1v4.01c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98v-14c0-1.11-.9-2-2-2zM11 16l4-4-4-4v3H1v2h10v3z"></path></g> + <g id="business"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"></path></g> </defs> </svg> </iron-iconset-svg>
diff --git a/chrome/browser/resources/md_extensions/item.html b/chrome/browser/resources/md_extensions/item.html index fe5e68d..a080e0f 100644 --- a/chrome/browser/resources/md_extensions/item.html +++ b/chrome/browser/resources/md_extensions/item.html
@@ -3,6 +3,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html"> <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html"> <link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html"> +<link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/action_link.html"> @@ -10,13 +11,12 @@ <link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> -<link rel="import" href="item_behavior.html"> <link rel="import" href="icons.html"> +<link rel="import" href="item_behavior.html"> <link rel="import" href="item_util.html"> <link rel="import" href="strings.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/communication-icons.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-tooltip/paper-tooltip.html"> <link rel="import" href="navigation_helper.html"> @@ -259,7 +259,7 @@ <template is="dom-if" if="[[hasWarnings_(data.disableReasons.*, data.*)]]"> <div id="warnings"> - <iron-icon id="error-icon" icon="error"></iron-icon> + <iron-icon id="error-icon" icon="cr:error"></iron-icon> <span id="runtime-warnings" aria-describedby="a11yAssociation" hidden$="[[!data.runtimeWarnings.length]]"> <template is="dom-repeat" items="[[data.runtimeWarnings]]">
diff --git a/chrome/browser/resources/md_extensions/item.js b/chrome/browser/resources/md_extensions/item.js index 6ecad23..3dec1563 100644 --- a/chrome/browser/resources/md_extensions/item.js +++ b/chrome/browser/resources/md_extensions/item.js
@@ -269,12 +269,12 @@ computeSourceIndicatorIcon_: function() { switch (extensions.getItemSource(this.data)) { case SourceType.POLICY: - return 'communication:business'; + return 'extensions-icons:business'; case SourceType.SIDELOADED: - return 'input'; + return 'extensions-icons:input'; case SourceType.UNKNOWN: // TODO(dpapad): Ask UX for a better icon for this case. - return 'input'; + return 'extensions-icons:input'; case SourceType.UNPACKED: return 'extensions-icons:unpacked'; case SourceType.WEBSTORE:
diff --git a/chrome/browser/resources/settings/about_page/about_page.html b/chrome/browser/resources/settings/about_page/about_page.html index b0a041b..0b9361e77 100644 --- a/chrome/browser/resources/settings/about_page/about_page.html +++ b/chrome/browser/resources/settings/about_page/about_page.html
@@ -64,7 +64,7 @@ fill: var(--google-blue-500); } - iron-icon[icon='settings:error'] { + iron-icon[icon='cr:error'] { fill: var(--google-red-700); }
diff --git a/chrome/browser/resources/settings/about_page/about_page.js b/chrome/browser/resources/settings/about_page/about_page.js index d2dbea9b..1ddbddc 100644 --- a/chrome/browser/resources/settings/about_page/about_page.js +++ b/chrome/browser/resources/settings/about_page/about_page.js
@@ -387,14 +387,14 @@ // If this platform has reached the end of the line, display an error icon // and ignore UpdateStatus. if (this.obsoleteSystemInfo_.endOfLine) - return 'settings:error'; + return 'cr:error'; // </if> switch (this.currentUpdateStatusEvent_.status) { case UpdateStatus.DISABLED_BY_ADMIN: return 'cr20:domain'; case UpdateStatus.FAILED: - return 'settings:error'; + return 'cr:error'; case UpdateStatus.UPDATED: case UpdateStatus.NEARLY_UPDATED: return 'settings:check-circle';
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html index e3a07cf5..7117925 100644 --- a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html +++ b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html
@@ -1,6 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html"> +<link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html"> @@ -12,6 +13,7 @@ <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="../controls/controlled_button.html"> <link rel="import" href="../controls/settings_toggle_button.html"> +<link rel="import" href="../icons.html"> <link rel="import" href="../settings_shared_css.html"> <link rel="import" href="chrome_cleanup_proxy.html"> <link rel="import" href="items_to_remove_list.html"> @@ -125,6 +127,12 @@ title="$i18n{chromeCleanupDetailsRegistryEntries}" items-to-show="[[scannerResults_.registryKeys]]"> </items-to-remove-list> + <items-to-remove-list + id="extensions-list" + hidden="[[!hasExtensionsToShow_]]" + title="$i18n{chromeCleanupDetailsExtensions}" + items-to-show="[[scannerResults_.extensions]]"> + </items-to-remove-list> <div class="settings-box continuation"> <div class="secondary"> $i18nRaw{chromeCleanupDetailsExplanation}
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.js b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.js index 86ce99e..5b54332c 100644 --- a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.js +++ b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.js
@@ -89,6 +89,7 @@ * @typedef {{ * files: Array<string>, * registryKeys: Array<string>, + * extensions: Array<string>, * }} */ settings.ChromeCleanerScannerResults; @@ -191,7 +192,7 @@ scannerResults_: { type: Array, value: function() { - return {'files': [], 'registryKeys': []}; + return {'files': [], 'registryKeys': [], 'extensions': []}; }, }, @@ -208,6 +209,12 @@ }, /** @private */ + hasExtensionsToShow_: { + type: Boolean, + computed: 'computeHasExtensionsToShow_(scannerResults_)', + }, + + /** @private */ statusIcon_: { type: String, value: '', @@ -235,7 +242,8 @@ }, /** @private {!settings.ChromeCleanerScannerResults} */ - emptyChromeCleanerScannerResults_: {'files': [], 'registryKeys': []}, + emptyChromeCleanerScannerResults_: + {'files': [], 'registryKeys': [], 'extensions': []}, /** @private {?settings.ChromeCleanupProxy} */ browserProxy_: null, @@ -359,6 +367,18 @@ }, /** + * Returns true if user-initiated cleanups are enabled and there are + * extensions to show to the user. + * @param {!settings.ChromeCleanerScannerResults} scannerResults The cleanup + * items to be presented to the user. + * @return {boolean} + * @private + */ + computeHasExtensionsToShow_(scannerResults) { + return scannerResults.extensions.length > 0; + }, + + /** * Listener of event 'chrome-cleanup-on-idle'. * @param {string} idleReason * @private @@ -630,7 +650,8 @@ this.browserProxy_ .getItemsToRemovePluralString( this.scannerResults_.files.length + - this.scannerResults_.registryKeys.length) + this.scannerResults_.registryKeys.length + + this.scannerResults_.extensions.length) .then(setShowItemsLabel); }, @@ -654,7 +675,7 @@ // Card's icon indicates a warning (in case of failure). WARNING: { - statusIcon: 'settings:error', + statusIcon: 'cr:error', statusIconClassName: 'status-icon-warning', },
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.html b/chrome/browser/resources/settings/controls/settings_toggle_button.html index 9534a9d..8a28bb0 100644 --- a/chrome/browser/resources/settings/controls/settings_toggle_button.html +++ b/chrome/browser/resources/settings/controls/settings_toggle_button.html
@@ -19,10 +19,6 @@ border-top: none; } - :host(.three-line) { - min-height: var(--settings-row-three-line-min-height); - } - :host([elide-label]), :host([elide-label]) #outerRow, :host([elide-label]) #outerRow > div.flex { @@ -35,8 +31,10 @@ #outerRow { align-items: center; + box-sizing: border-box; display: flex; min-height: var(--settings-row-two-line-min-height); + padding: 12px 0; width: 100%; }
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html index 405111b..6915b61 100644 --- a/chrome/browser/resources/settings/icons.html +++ b/chrome/browser/resources/settings/icons.html
@@ -79,7 +79,6 @@ <g id="devices-other"><path d="M3 6h18V4H3c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4v-2H3V6zm10 6H9v1.78c-.61.55-1 1.33-1 2.22s.39 1.67 1 2.22V20h4v-1.78c.61-.55 1-1.34 1-2.22s-.39-1.67-1-2.22V12zm-2 5.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM22 8h-6c-.5 0-1 .5-1 1v10c0 .5.5 1 1 1h6c.5 0 1-.5 1-1V9c0-.5-.5-1-1-1zm-1 10h-4v-8h4v8z"></path></g> </if> <g id="done"><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"></path></g> - <g id="error"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"></path></g> <g id="exit-to-app"><path d="M10.09 15.59L11.5 17l5-5-5-5-1.41 1.41L12.67 11H3v2h9.67l-2.58 2.59zM19 3H5c-1.11 0-2 .9-2 2v4h2V5h14v14H5v-4H3v4c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"></path></g> <if expr="chromeos"> <g id="fingerprint"><path d="M17.81 4.47c-.08 0-.16-.02-.23-.06C15.66 3.42 14 3 12.01 3c-1.98 0-3.86.47-5.57 1.41-.24.13-.54.04-.68-.2-.13-.24-.04-.55.2-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67-.09.18-.26.28-.44.28zM3.5 9.72c-.1 0-.2-.03-.29-.09-.23-.16-.28-.47-.12-.7.99-1.4 2.25-2.5 3.75-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54-.12.7-.23.16-.54.11-.7-.12-.9-1.26-2.04-2.25-3.39-2.94-2.87-1.47-6.54-1.47-9.4.01-1.36.7-2.5 1.7-3.4 2.96-.08.14-.23.21-.39.21zm6.25 12.07c-.13 0-.26-.05-.35-.15-.87-.87-1.34-1.43-2.01-2.64-.69-1.23-1.05-2.73-1.05-4.34 0-2.97 2.54-5.39 5.66-5.39s5.66 2.42 5.66 5.39c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-2.42-2.09-4.39-4.66-4.39-2.57 0-4.66 1.97-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71-.11.1-.24.15-.37.15zm7.17-1.85c-1.19 0-2.24-.3-3.1-.89-1.49-1.01-2.38-2.65-2.38-4.39 0-.28.22-.5.5-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64-.03 1.04-.1.27-.05.53.13.58.41.05.27-.13.53-.41.58-.57.11-1.07.12-1.21.12zM14.91 22c-.04 0-.09-.01-.13-.02-1.59-.44-2.63-1.03-3.72-2.1-1.4-1.39-2.17-3.24-2.17-5.22 0-1.62 1.38-2.94 3.08-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08-.87 2.08-1.94c0-3.77-3.25-6.83-7.25-6.83-2.84 0-5.44 1.58-6.61 4.03-.39.81-.59 1.76-.59 2.8 0 .78.07 2.01.67 3.61.1.26-.03.55-.29.64-.26.1-.55-.04-.64-.29-.49-1.31-.73-2.61-.73-3.96 0-1.2.23-2.29.68-3.24 1.33-2.79 4.28-4.6 7.51-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62-1.38 2.94-3.08 2.94s-3.08-1.32-3.08-2.94c0-1.07-.93-1.94-2.08-1.94s-2.08.87-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61-.05.23-.26.38-.47.38z"></path></g> @@ -87,7 +86,6 @@ <g id="headset"><path d="M12 1c-4.97 0-9 4.03-9 9v7c0 1.66 1.34 3 3 3h3v-8H5v-2c0-3.87 3.13-7 7-7s7 3.13 7 7v2h-4v8h3c1.66 0 3-1.34 3-3v-7c0-4.97-4.03-9-9-9z"></path></g> </if> <g id="help-outline"><path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"></path></g> - <g id="info"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"></path></g> <g id="info-outline"><path d="M11 17h2v-6h-2v6zm1-15C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zM11 9h2V7h-2v2z"></path></g> <if expr="chromeos"> <g id="keyboard"><path d="M20 5H4c-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-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z"></path></g> @@ -138,7 +136,6 @@ <g id="volume-up"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"></path></g> <g id="vpn-key"><path d="M12.65 10C11.83 7.67 9.61 6 7 6c-3.31 0-6 2.69-6 6s2.69 6 6 6c2.61 0 4.83-1.67 5.65-4H17v4h4v-4h2v-4H12.65zM7 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"></path></g> <if expr="chromeos"> - <g id="warning"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"></path></g> <g id="end-of-life"><path d="M4.574 2.916H4.55l.01.01.014-.01zM2.5 4.968v.023a.18.18 0 0 1 .01-.013l-.01-.01zm14.585 10.49v-.024l-.01.013.01.01zm.223 1.817l-.933-.95-4.106-4.11L8.026 7.99 3.675 3.635l-.942-.941-.712-.713L1 3.002l1.733 1.733A9.056 9.056 0 0 0 1.05 9.98c0 1.95.628 3.748 1.683 5.22.574.8 1.274 1.501 2.074 2.075a8.918 8.918 0 0 0 5.218 1.684 8.918 8.918 0 0 0 5.218-1.684L16.991 19l1.02-1.021-.703-.704zM15.243 2.684A8.922 8.922 0 0 0 10.025 1a8.922 8.922 0 0 0-5.218 1.684c-.005.003 4.135 4.16 4.135 4.16l1.083-1.814L15.042 11h-1.846l4.11 4.214a8.939 8.939 0 0 0 .011-10.456 9.021 9.021 0 0 0-2.074-2.074zM12 15H7.012v-3.989L4.5 11l2.227-1.876L12 14.6v.4z" fill="#DB4437" fill-rule="evenodd"></path></g> </if> <if expr="not chromeos">
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html index 8ed20d0..75a6eb9 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.html +++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -99,7 +99,7 @@ margin-top: 8px; } - iron-icon[icon='settings:error'] { + iron-icon[icon='cr:error'] { @apply --cr-icon-height-width; --iron-icon-fill-color: var(--google-red-700); -webkit-margin-end: 8px; @@ -275,7 +275,7 @@ [[item.language.displayName]] <div hidden="[[!errorsGreaterThan_( item.downloadDictionaryFailureCount, 0)]]"> - <iron-icon icon="settings:error"></iron-icon> + <iron-icon icon="cr:error"></iron-icon> $i18n{languagesDictionaryDownloadError} </div> <div hidden="[[!errorsGreaterThan_(
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html index 617a85e..c9f66d0 100644 --- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html +++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
@@ -67,7 +67,6 @@ </div> </template> <settings-toggle-button id="autosigninCheckbox" - class="three-line" pref="{{prefs.credentials_enable_autosignin}}" label="$i18n{passwordsAutosigninLabel}" sub-label="$i18n{passwordsAutosigninDescription}">
diff --git a/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html b/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html index 60c3e30..87adadc 100644 --- a/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html +++ b/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html
@@ -70,7 +70,7 @@ </div> <div id="problemDiv" class="settings-box first" invisible$="[[!problemMessage_]]"> - <iron-icon icon="settings:warning"></iron-icon> + <iron-icon icon="cr:warning"></iron-icon> <span class="middle">[[problemMessage_]]</span> </div> </div>
diff --git a/chrome/browser/resources/settings/settings.html b/chrome/browser/resources/settings/settings.html index 40207595..954e342b 100644 --- a/chrome/browser/resources/settings/settings.html +++ b/chrome/browser/resources/settings/settings.html
@@ -21,7 +21,7 @@ </style> </head> <body> - <settings-ui></settings-ui> + <settings-ui tabindex="-1"></settings-ui> <link rel="stylesheet" href="chrome://resources/css/md_colors.css"> <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> <link rel="import" href="chrome://resources/html/polymer.html">
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html index 72ac2cc..645b59f8 100644 --- a/chrome/browser/resources/settings/settings_ui/settings_ui.html +++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -29,6 +29,7 @@ @apply --layout-fit; display: flex; flex-direction: column; + outline: none; } cr-drawer {
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js index 5a36797..4464e116e 100644 --- a/chrome/browser/resources/settings/settings_ui/settings_ui.js +++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -80,6 +80,15 @@ 'refresh-pref': 'onRefreshPref_', }, + /** + * Tracks if any cr-dialog is open anywhere in the UI. An assumption is being + * made that only one cr-dialog is open at a time. If this assumption changes + * |dialogOpen_| should be replaced with a count of the number of dialogs that + * are open. + * @private {boolean} + */ + dialogOpen_: false, + /** @override */ created: function() { settings.initializeRouteFromUrl(); @@ -164,6 +173,15 @@ this.addEventListener('hide-container', () => { this.$.container.style.visibility = 'hidden'; }); + + this.addEventListener('cr-dialog-open', () => { + this.dialogOpen_ = true; + }); + + this.addEventListener('close', e => { + if (e.composedPath()[0].nodeName == 'CR-DIALOG') + this.dialogOpen_ = false; + }); }, /** @override */ @@ -227,8 +245,7 @@ // Override settings.FindShortcutBehavior methods. canHandleFindShortcut: function() { - return !this.$.drawer.open && - !document.querySelector('* /deep/ cr-dialog[open]'); + return !this.$.drawer.open && !this.dialogOpen_; }, handleFindShortcut: function() {
diff --git a/chrome/browser/resources/vr/OWNERS b/chrome/browser/resources/vr/OWNERS index 7125346..33672fa4 100644 --- a/chrome/browser/resources/vr/OWNERS +++ b/chrome/browser/resources/vr/OWNERS
@@ -1,3 +1,5 @@ +cjgrant@chromium.org tiborg@chromium.org -# COMPONENT: UI>Browser>VR \ No newline at end of file +# TEAM: xr-dev@chromium.org +# COMPONENT: UI>Browser>VR
diff --git a/chrome/browser/search/background/ntp_background.proto b/chrome/browser/search/background/ntp_background.proto index c48cb99..0650ee6f 100644 --- a/chrome/browser/search/background/ntp_background.proto +++ b/chrome/browser/search/background/ntp_background.proto
@@ -110,3 +110,30 @@ // Set to true if there was an error on the server. optional bool error_on_server = 5; } + +// The Photos API returns metadata about photos within an album as a +// SettingPreviewResponse. See NtpBackgroundService::FetchAlbumPhotos for the +// API's usage. This is a server-defined message. +message SettingPreviewResponse { + // Deprecated or unused tag numbers + reserved 1; + + // A preview image for each photo. + message Preview { optional string preview_url = 1; } + repeated Preview preview = 2; + + // A resume token can be used to get the next page of results. + optional string resume_token = 3; + + // An error_msg is set when the status is not 'SUCCESS'. + optional ErrorCode status = 4 [default = SUCCESS]; + optional string error_msg = 5; +} + +// Server-defined ErrorCodes for the Photos API. +enum ErrorCode { + UNKNOWN = 0; + SUCCESS = 1; + BAD_REQUEST = 2; + SERVER_ERROR = 3; +}
diff --git a/chrome/browser/search/background/ntp_background_data.cc b/chrome/browser/search/background/ntp_background_data.cc index 58a0073..b861b7b 100644 --- a/chrome/browser/search/background/ntp_background_data.cc +++ b/chrome/browser/search/background/ntp_background_data.cc
@@ -106,3 +106,27 @@ return album_info; } + +AlbumPhoto::AlbumPhoto() = default; +// TODO(crbug.com/851990) Handle urls with existing image options. +AlbumPhoto::AlbumPhoto(const std::string& photo_url, + const std::string& default_image_options) + : thumbnail_photo_url(GURL(photo_url)), + photo_url(GURL(photo_url + ((photo_url.find('=') == std::string::npos) + ? default_image_options + : std::string()))) {} +AlbumPhoto::AlbumPhoto(const AlbumPhoto&) = default; +AlbumPhoto::AlbumPhoto(AlbumPhoto&&) = default; +AlbumPhoto::~AlbumPhoto() = default; + +AlbumPhoto& AlbumPhoto::operator=(const AlbumPhoto&) = default; +AlbumPhoto& AlbumPhoto::operator=(AlbumPhoto&&) = default; + +bool operator==(const AlbumPhoto& lhs, const AlbumPhoto& rhs) { + return lhs.thumbnail_photo_url == rhs.thumbnail_photo_url && + lhs.photo_url == rhs.photo_url; +} + +bool operator!=(const AlbumPhoto& lhs, const AlbumPhoto& rhs) { + return !(lhs == rhs); +}
diff --git a/chrome/browser/search/background/ntp_background_data.h b/chrome/browser/search/background/ntp_background_data.h index 215ab343..9263c837 100644 --- a/chrome/browser/search/background/ntp_background_data.h +++ b/chrome/browser/search/background/ntp_background_data.h
@@ -87,9 +87,12 @@ static AlbumInfo CreateFromProto(const ntp::background::AlbumMetaData& album); - // A unique identifier for the album. + // A unique identifier for the album. This is required when requesting the + // album. int64_t album_id; - // A generic photo container ID based on the photo provider. + // A generic photo container ID based on the photo provider. For Google + // Photos, this corresponds to media keys for the collection. It is also + // required when requesting the album. std::string photo_container_id; // A human-readable name for the album. std::string album_name; @@ -100,4 +103,27 @@ bool operator==(const AlbumInfo& lhs, const AlbumInfo& rhs); bool operator!=(const AlbumInfo& lhs, const AlbumInfo& rhs); +// Represents a photo within an album. +struct AlbumPhoto { + AlbumPhoto(); + // default_image_options are applied to the image.image_url() if options + // (specifying resolution, cropping, etc) are not already present. + AlbumPhoto(const std::string& photo_url, + const std::string& default_image_options); + AlbumPhoto(const AlbumPhoto&); + AlbumPhoto(AlbumPhoto&&); + ~AlbumPhoto(); + + AlbumPhoto& operator=(const AlbumPhoto&); + AlbumPhoto& operator=(AlbumPhoto&&); + + // The thumbnail image URL, typically lower resolution than the photo_url. + GURL thumbnail_photo_url; + // The image URL. + GURL photo_url; +}; + +bool operator==(const AlbumPhoto& lhs, const AlbumPhoto& rhs); +bool operator!=(const AlbumPhoto& lhs, const AlbumPhoto& rhs); + #endif // CHROME_BROWSER_SEARCH_BACKGROUND_NTP_BACKGROUND_DATA_H_
diff --git a/chrome/browser/search/background/ntp_background_service.cc b/chrome/browser/search/background/ntp_background_service.cc index 1333b95..9a145203 100644 --- a/chrome/browser/search/background/ntp_background_service.cc +++ b/chrome/browser/search/background/ntp_background_service.cc
@@ -32,6 +32,16 @@ "https://clients3.google.com/cast/chromecast/home/photo-album-metadata?" "f.req=%5B%2C%22512%22%2C%22512%22%2C%2250%22%2C%2C%2Ctrue%2C%2C%222%22" "%2C%220%22%5D&rt=b"; +// The url to download metadata of photos within an album. A proto-format +// response is requested, since it is easy to parse. +constexpr char kAlbumPhotosBaseUrl[] = + "https://clients3.google.com/cast/chromecast/home/settings/preview?rt=b"; +// The format used to specify additional parameters to the Photos API. This +// requests photos for a to-be-specified album_id and photo_container_id, with +// a max page size of 100. +// TODO(crbug.com/855934): support pagination parameter. +const char kPhotosUrlRequestFormat[] = "[\"2\", [\"%s\",,,\"%s\"],,\"100\"]"; + // The virtual device id required in GET request header for albums requests. constexpr char kVirtualDeviceIdParam[] = "CAST-APP-DEVICE-ID"; constexpr char kVirtualDeviceIdValue[] = "CCCCCCCC01F9618E8D8126398CF4218E"; @@ -41,6 +51,7 @@ // The options to be added to an image URL, specifying resolution, cropping, // etc. Options appear on an image URL after the '=' character. +// TODO(crbug.com/851990): Set options based on display resolution capability. constexpr char kImageOptions[] = "=w3840-h2160-p-k-no-nd-mv"; constexpr char kScopePhotos[] = "https://www.googleapis.com/auth/photos"; @@ -53,6 +64,7 @@ const base::Optional<GURL>& collections_api_url_override, const base::Optional<GURL>& collection_images_api_url_override, const base::Optional<GURL>& albums_api_url_override, + const base::Optional<GURL>& photos_api_base_url_override, const base::Optional<std::string>& image_options_override) : url_loader_factory_(url_loader_factory), identity_manager_(identity_manager) { @@ -62,6 +74,8 @@ collection_images_api_url_ = collection_images_api_url_override.value_or(GURL(kCollectionImagesUrl)); albums_api_url_ = albums_api_url_override.value_or(GURL(kAlbumsUrl)); + photos_api_base_url_ = + photos_api_base_url_override.value_or(GURL(kAlbumPhotosBaseUrl)); image_options_ = image_options_override.value_or(kImageOptions); } @@ -164,7 +178,7 @@ void NtpBackgroundService::FetchCollectionImageInfo( const std::string& collection_id) { - if (image_info_loader_ != nullptr) + if (collections_image_info_loader_ != nullptr) return; net::NetworkTrafficAnnotationTag traffic_annotation = @@ -210,10 +224,11 @@ resource_request->method = "POST"; resource_request->load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; - image_info_loader_ = network::SimpleURLLoader::Create( + collections_image_info_loader_ = network::SimpleURLLoader::Create( std::move(resource_request), traffic_annotation); - image_info_loader_->AttachStringForUpload(serialized_proto, kProtoMimeType); - image_info_loader_->DownloadToString( + collections_image_info_loader_->AttachStringForUpload(serialized_proto, + kProtoMimeType); + collections_image_info_loader_->DownloadToString( url_loader_factory_.get(), base::BindOnce(&NtpBackgroundService::OnCollectionImageInfoFetchComplete, base::Unretained(this)), @@ -225,7 +240,7 @@ collection_images_.clear(); // The loader will be deleted when the request is handled. std::unique_ptr<network::SimpleURLLoader> loader_deleter( - std::move(image_info_loader_)); + std::move(collections_image_info_loader_)); if (!response_body) { // This represents network errors (i.e. the server did not provide a @@ -260,19 +275,20 @@ OAuth2TokenService::ScopeSet scopes{kScopePhotos}; token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForPrimaryAccount( "ntp_backgrounds_service", scopes, - base::BindOnce(&NtpBackgroundService::GetAccessTokenCallback, + base::BindOnce(&NtpBackgroundService::GetAccessTokenForAlbumCallback, base::Unretained(this)), identity::PrimaryAccountAccessTokenFetcher::Mode::kImmediate); } -void NtpBackgroundService::GetAccessTokenCallback(GoogleServiceAuthError error, - std::string token) { +void NtpBackgroundService::GetAccessTokenForAlbumCallback( + GoogleServiceAuthError error, + std::string token) { token_fetcher_.reset(); if (error != GoogleServiceAuthError::AuthErrorNone()) { DLOG(WARNING) << "Failed to retrieve token with error: " << error.ToString(); - // TODO(ramyan): Communicate error to caller. https://crbug.com/851296 + NotifyObservers(FetchComplete::ALBUM_INFO); return; } @@ -353,6 +369,112 @@ NotifyObservers(FetchComplete::ALBUM_INFO); } +void NtpBackgroundService::FetchAlbumPhotos( + const std::string& album_id, + const std::string& photo_container_id) { + // We're still waiting for the last request to come back. + if (token_fetcher_ || albums_photo_info_loader_) + return; + + requested_album_id_ = album_id; + requested_photo_container_id_ = photo_container_id; + OAuth2TokenService::ScopeSet scopes{kScopePhotos}; + token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForPrimaryAccount( + "ntp_backgrounds_service", scopes, + base::BindOnce(&NtpBackgroundService::GetAccessTokenForPhotosCallback, + base::Unretained(this)), + identity::PrimaryAccountAccessTokenFetcher::Mode::kImmediate); +} + +void NtpBackgroundService::GetAccessTokenForPhotosCallback( + GoogleServiceAuthError error, + std::string token) { + token_fetcher_.reset(); + + if (error != GoogleServiceAuthError::AuthErrorNone()) { + DLOG(WARNING) << "Failed to retrieve token with error: " + << error.ToString(); + NotifyObservers(FetchComplete::ALBUM_PHOTOS); + return; + } + + net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("google_photos_metadata_download", + R"( + semantics { + sender: "Desktop NTP Background Selector" + description: + "The Chrome Desktop New Tab Page background selector allows " + "signed-in users to select images from their Google Photos albums. " + "The photos in an album are obtained from the Backdrop service." + trigger: + "Clicking the the settings (gear) icon on the New Tab page." + data: + "The Backdrop protocol buffer messages and an access token with " + "limited scope to obtain the user's Google Photos data." + destination: GOOGLE_OWNED_SERVICE + } + policy { + cookies_allowed: NO + setting: + "Users can control this feature by selecting a non-Google default " + "search engine in Chrome settings under 'Search Engine'." + chrome_policy { + DefaultSearchProviderEnabled { + policy_options {mode: MANDATORY} + DefaultSearchProviderEnabled: false + } + } + })"); + + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->url = GetAlbumPhotosApiUrl(); + resource_request->method = "GET"; + resource_request->load_flags = + net::LOAD_DO_NOT_SEND_AUTH_DATA | net::LOAD_DO_NOT_SEND_COOKIES; + resource_request->headers.SetHeader( + kAuthHeaderParam, base::StringPrintf(kAuthHeaderValue, token.c_str())); + + albums_photo_info_loader_ = network::SimpleURLLoader::Create( + std::move(resource_request), traffic_annotation); + albums_photo_info_loader_->DownloadToString( + url_loader_factory_.get(), + base::BindOnce(&NtpBackgroundService::OnAlbumPhotosFetchComplete, + base::Unretained(this)), + 1024 * 1024); +} + +void NtpBackgroundService::OnAlbumPhotosFetchComplete( + std::unique_ptr<std::string> response_body) { + album_photos_.clear(); + // The loader will be deleted when the request is handled. + std::unique_ptr<network::SimpleURLLoader> loader_deleter( + std::move(albums_photo_info_loader_)); + + if (!response_body) { + // This represents network errors (i.e. the server did not provide a + // response). + DLOG(WARNING) << "Request failed with error: " + << loader_deleter->NetError(); + NotifyObservers(FetchComplete::ALBUM_PHOTOS); + return; + } + + ntp::background::SettingPreviewResponse photos_response; + if (!photos_response.ParseFromString(*response_body)) { + DLOG(WARNING) << "Deserializing personal photos response proto failed."; + NotifyObservers(FetchComplete::ALBUM_PHOTOS); + return; + } + + for (int i = 0; i < photos_response.preview_size(); ++i) { + album_photos_.emplace_back(photos_response.preview(i).preview_url(), + image_options_); + } + + NotifyObservers(FetchComplete::ALBUM_PHOTOS); +} + void NtpBackgroundService::AddObserver(NtpBackgroundServiceObserver* observer) { observers_.AddObserver(observer); } @@ -362,6 +484,7 @@ observers_.RemoveObserver(observer); } +// TODO(crbug.com/851296): Communicate errors to callers. void NtpBackgroundService::NotifyObservers(FetchComplete fetch_complete) { for (auto& observer : observers_) { switch (fetch_complete) { @@ -374,10 +497,30 @@ case FetchComplete::ALBUM_INFO: observer.OnAlbumInfoAvailable(); break; + case FetchComplete::ALBUM_PHOTOS: + observer.OnAlbumPhotosAvailable(); + break; } } } +GURL NtpBackgroundService::FormatAlbumPhotosBaseApiUrl( + const std::string& album_id, + const std::string& photo_container_id) const { + GURL api_url = photos_api_base_url_; + + api_url = net::AppendQueryParameter( + api_url, "f.req", + base::StringPrintf(kPhotosUrlRequestFormat, album_id.c_str(), + photo_container_id.c_str())); + return api_url; +} + +GURL NtpBackgroundService::GetAlbumPhotosApiUrl() const { + return FormatAlbumPhotosBaseApiUrl(requested_album_id_, + requested_photo_container_id_); +} + GURL NtpBackgroundService::GetCollectionsLoadURLForTesting() const { return collections_api_url_; } @@ -389,3 +532,9 @@ GURL NtpBackgroundService::GetAlbumsURLForTesting() const { return albums_api_url_; } + +GURL NtpBackgroundService::GetAlbumPhotosApiUrlForTesting( + const std::string& album_id, + const std::string& photo_container_id) const { + return FormatAlbumPhotosBaseApiUrl(album_id, photo_container_id); +}
diff --git a/chrome/browser/search/background/ntp_background_service.h b/chrome/browser/search/background/ntp_background_service.h index d476f2e..aa06034 100644 --- a/chrome/browser/search/background/ntp_background_service.h +++ b/chrome/browser/search/background/ntp_background_service.h
@@ -15,6 +15,7 @@ #include "chrome/browser/search/background/ntp_background_data.h" #include "chrome/browser/search/background/ntp_background_service_observer.h" #include "components/keyed_service/core/keyed_service.h" +#include "net/base/url_util.h" #include "url/gurl.h" class GoogleServiceAuthError; @@ -39,6 +40,7 @@ const base::Optional<GURL>& collections_api_url_override, const base::Optional<GURL>& collection_images_api_url_override, const base::Optional<GURL>& albums_api_url_override, + const base::Optional<GURL>& photos_api_base_url_override, const base::Optional<std::string>& image_options_override); ~NtpBackgroundService() override; @@ -61,6 +63,13 @@ // called on the observers. void FetchAlbumInfo(); + // Initially requests an access token for the signed-in user, and then + // requests an asynchronous fetch of photos using the access token, if it is + // available. After the fetch completes, OnAlbumPhotosAvailable will be called + // on the observers. + void FetchAlbumPhotos(const std::string& album_id, + const std::string& photo_container_id); + // Add/remove observers. All observers must unregister themselves before the // NtpBackgroundService is destroyed. void AddObserver(NtpBackgroundServiceObserver* observer); @@ -79,21 +88,29 @@ // Returns the currently cached AlbumInfo, if any. const std::vector<AlbumInfo>& album_info() const { return album_info_; } + // Returns the currently cached AlbumPhotos, if any. + const std::vector<AlbumPhoto>& album_photos() const { return album_photos_; } + GURL GetCollectionsLoadURLForTesting() const; GURL GetImagesURLForTesting() const; GURL GetAlbumsURLForTesting() const; + GURL GetAlbumPhotosApiUrlForTesting( + const std::string& album_id, + const std::string& photo_container_id) const; private: GURL collections_api_url_; GURL collection_images_api_url_; GURL albums_api_url_; + GURL photos_api_base_url_; std::string image_options_; // Used to download the proto from the Backdrop service. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; std::unique_ptr<network::SimpleURLLoader> collections_loader_; - std::unique_ptr<network::SimpleURLLoader> image_info_loader_; + std::unique_ptr<network::SimpleURLLoader> collections_image_info_loader_; std::unique_ptr<network::SimpleURLLoader> albums_loader_; + std::unique_ptr<network::SimpleURLLoader> albums_photo_info_loader_; identity::IdentityManager* const identity_manager_; // The current OAuth2 token fetcher. @@ -112,22 +129,36 @@ void OnCollectionImageInfoFetchComplete( const std::unique_ptr<std::string> response_body); - void GetAccessTokenCallback(GoogleServiceAuthError error, std::string token); + void GetAccessTokenForAlbumCallback(GoogleServiceAuthError error, + std::string token); // Callback that processes the response from the FetchAlbumInfo request, // refreshing the contents of album_info_ with server-provided data. void OnAlbumInfoFetchComplete( const std::unique_ptr<std::string> response_body); + void GetAccessTokenForPhotosCallback(GoogleServiceAuthError error, + std::string token); + + // Callback that processes the response from SettingPreviewRequest, refreshing + // the contents of album_photos_ with server-provided data. + void OnAlbumPhotosFetchComplete( + const std::unique_ptr<std::string> response_body); + enum class FetchComplete { // Indicates that asynchronous fetch of CollectionInfo has completed. COLLECTION_INFO, // Indicates that asynchronous fetch of CollectionImages has completed. COLLECTION_IMAGE_INFO, // Indicates that asynchronous fetch of AlbumInfo has completed. - ALBUM_INFO + ALBUM_INFO, + // Indicates that asynchronous fetch of AlbumPhotos has completed. + ALBUM_PHOTOS }; void NotifyObservers(FetchComplete fetch_complete); + GURL GetAlbumPhotosApiUrl() const; + GURL FormatAlbumPhotosBaseApiUrl(const std::string& album_id, + const std::string& photo_container_id) const; std::vector<CollectionInfo> collection_info_; @@ -136,6 +167,10 @@ std::vector<AlbumInfo> album_info_; + std::vector<AlbumPhoto> album_photos_; + std::string requested_album_id_; + std::string requested_photo_container_id_; + DISALLOW_COPY_AND_ASSIGN(NtpBackgroundService); };
diff --git a/chrome/browser/search/background/ntp_background_service_factory.cc b/chrome/browser/search/background/ntp_background_service_factory.cc index 0cb68166..fa07d8c 100644 --- a/chrome/browser/search/background/ntp_background_service_factory.cc +++ b/chrome/browser/search/background/ntp_background_service_factory.cc
@@ -51,11 +51,14 @@ features::kNtpBackgrounds, "background-collection-images-api-url"); std::string albums_api_url = base::GetFieldTrialParamValueByFeature( features::kNtpBackgrounds, "background-albums-api-url"); + std::string photos_api_base_url = base::GetFieldTrialParamValueByFeature( + features::kNtpBackgrounds, "background-photos-api-url"); std::string image_options = base::GetFieldTrialParamValueByFeature( features::kNtpBackgrounds, "background-collections-image-options"); base::Optional<GURL> collection_api_url_override; base::Optional<GURL> collection_images_api_url_override; base::Optional<GURL> albums_api_url_override; + base::Optional<GURL> photos_api_base_url_override; base::Optional<std::string> image_options_override; if (!collections_api_url.empty()) { collection_api_url_override = GURL(collections_api_url); @@ -66,6 +69,9 @@ if (!albums_api_url.empty()) { albums_api_url_override = GURL(albums_api_url); } + if (!photos_api_base_url.empty()) { + photos_api_base_url_override = GURL(photos_api_base_url); + } if (!image_options.empty()) { image_options_override = image_options; } @@ -80,5 +86,5 @@ return new NtpBackgroundService( identity_manager, url_loader_factory, collection_api_url_override, collection_images_api_url_override, albums_api_url_override, - image_options_override); + photos_api_base_url_override, image_options_override); }
diff --git a/chrome/browser/search/background/ntp_background_service_observer.h b/chrome/browser/search/background/ntp_background_service_observer.h index ff364a2..76a41f2c 100644 --- a/chrome/browser/search/background/ntp_background_service_observer.h +++ b/chrome/browser/search/background/ntp_background_service_observer.h
@@ -9,26 +9,25 @@ class NtpBackgroundServiceObserver { public: // Called when the CollectionInfo is updated, usually as the result of a - // FetchCollectionInfo() call on the service. Note that this is called after - // each FetchCollectionInfo(), even if the network request failed, or if it - // didn't result in an actual change to the cached data. You can get the new - // data via NtpBackgroundService::collection_info(). + // FetchCollectionInfo() call on the service. You can get the new data via + // NtpBackgroundService::collection_info(). virtual void OnCollectionInfoAvailable() = 0; // Called when the CollectionImages are updated, usually as the result of a - // FetchCollectionImageInfo() call on the service. Note that this is called - // after each FetchCollectionImage(), even if the network request failed, or - // if it didn't result in an actual change to the cached data. You can get the - // new data via NtpBackgroundService::collection_images(). + // FetchCollectionImageInfo() call on the service. You can get the new data + // via NtpBackgroundService::collection_images(). virtual void OnCollectionImagesAvailable() = 0; // Called when the AlbumInfo is updated, usually as the result of a - // PersonalAlbumsRequestOption() call on the service. Note that this is called - // after each FetchAlbumInfo(), even if the network request failed, or if it - // didn't result in an actual change to the cached data. You can get the new + // PersonalAlbumsRequestOption() call on the service. You can get the new // data via NtpBackgroundService::album_info(). virtual void OnAlbumInfoAvailable() = 0; + // Called when the AlbumPhotos are updated, usually as the result of a + // SettingPreviewRequest() call on the service. You can get the new data via + // NtpBackgroundService::album_photos(). + virtual void OnAlbumPhotosAvailable() = 0; + // Called when the OnNtpBackgroundService is shutting down. Observers that // might outlive the service should use this to unregister themselves, and // clear out any pointers to the service they might hold.
diff --git a/chrome/browser/search/background/ntp_background_service_unittest.cc b/chrome/browser/search/background/ntp_background_service_unittest.cc index 5cd2ddf..337b7a63 100644 --- a/chrome/browser/search/background/ntp_background_service_unittest.cc +++ b/chrome/browser/search/background/ntp_background_service_unittest.cc
@@ -20,6 +20,7 @@ #include "url/gurl.h" using testing::Eq; +using testing::StartsWith; namespace { @@ -46,7 +47,8 @@ service_ = std::make_unique<NtpBackgroundService>( identity_env_.identity_manager(), test_shared_loader_factory_, - base::nullopt, base::nullopt, base::nullopt, kImageOptions); + base::nullopt, base::nullopt, base::nullopt, base::nullopt, + kImageOptions); } void SetUpResponseWithData(const GURL& load_url, @@ -80,11 +82,10 @@ ASSERT_TRUE(service()->collection_info().empty()); - base::RunLoop loop; service()->FetchCollectionInfo(); - loop.RunUntilIdle(); + base::RunLoop().RunUntilIdle(); - ASSERT_TRUE(service()->collection_info().empty()); + EXPECT_TRUE(service()->collection_info().empty()); } TEST_F(NtpBackgroundServiceTest, BadCollectionsResponse) { @@ -93,9 +94,8 @@ ASSERT_TRUE(service()->collection_info().empty()); - base::RunLoop loop; service()->FetchCollectionInfo(); - loop.RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_TRUE(service()->collection_info().empty()); } @@ -115,9 +115,8 @@ ASSERT_TRUE(service()->collection_info().empty()); - base::RunLoop loop; service()->FetchCollectionInfo(); - loop.RunUntilIdle(); + base::RunLoop().RunUntilIdle(); CollectionInfo collection_info; collection_info.collection_id = collection.collection_id(); @@ -133,11 +132,10 @@ ASSERT_TRUE(service()->collection_images().empty()); - base::RunLoop loop; service()->FetchCollectionImageInfo("shapes"); - loop.RunUntilIdle(); + base::RunLoop().RunUntilIdle(); - ASSERT_TRUE(service()->collection_images().empty()); + EXPECT_TRUE(service()->collection_images().empty()); } TEST_F(NtpBackgroundServiceTest, BadCollectionImagesResponse) { @@ -146,9 +144,8 @@ ASSERT_TRUE(service()->collection_images().empty()); - base::RunLoop loop; service()->FetchCollectionImageInfo("shapes"); - loop.RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_TRUE(service()->collection_images().empty()); } @@ -168,9 +165,8 @@ ASSERT_TRUE(service()->collection_images().empty()); - base::RunLoop loop; service()->FetchCollectionImageInfo("shapes"); - loop.RunUntilIdle(); + base::RunLoop().RunUntilIdle(); CollectionImage collection_image; collection_image.collection_id = "shapes"; @@ -211,12 +207,11 @@ ASSERT_TRUE(service()->collection_info().empty()); ASSERT_TRUE(service()->collection_images().empty()); - base::RunLoop loop; service()->FetchCollectionInfo(); service()->FetchCollectionImageInfo("shapes"); // Subsequent requests are ignored while the loader is in use. service()->FetchCollectionImageInfo("colors"); - loop.RunUntilIdle(); + base::RunLoop().RunUntilIdle(); CollectionInfo collection_info; collection_info.collection_id = collection.collection_id(); @@ -241,11 +236,10 @@ ASSERT_TRUE(service()->album_info().empty()); - base::RunLoop loop; service()->FetchAlbumInfo(); - loop.RunUntilIdle(); + base::RunLoop().RunUntilIdle(); - ASSERT_TRUE(service()->album_info().empty()); + EXPECT_TRUE(service()->album_info().empty()); } TEST_F(NtpBackgroundServiceTest, BadAlbumsResponse) { @@ -254,9 +248,8 @@ ASSERT_TRUE(service()->album_info().empty()); - base::RunLoop loop; service()->FetchAlbumInfo(); - loop.RunUntilIdle(); + base::RunLoop().RunUntilIdle(); EXPECT_TRUE(service()->album_info().empty()); } @@ -276,9 +269,8 @@ ASSERT_TRUE(service()->album_info().empty()); - base::RunLoop loop; service()->FetchAlbumInfo(); - loop.RunUntilIdle(); + base::RunLoop().RunUntilIdle(); AlbumInfo album_info; album_info.album_id = album.album_id(); @@ -289,3 +281,71 @@ EXPECT_FALSE(service()->album_info().empty()); EXPECT_THAT(service()->album_info().at(0), Eq(album_info)); } + +TEST_F(NtpBackgroundServiceTest, AlbumPhotosNetworkError) { + SetUpResponseWithNetworkError(service()->GetAlbumPhotosApiUrlForTesting( + "album_id", "photo_container_id")); + + ASSERT_TRUE(service()->album_photos().empty()); + + service()->FetchAlbumPhotos("album_id", "photo_container_id"); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(service()->album_photos().empty()); +} + +TEST_F(NtpBackgroundServiceTest, BadAlbumPhotosResponse) { + SetUpResponseWithData(service()->GetAlbumPhotosApiUrlForTesting( + "album_id", "photo_container_id"), + "bad serialized SettingPreviewResponse"); + + ASSERT_TRUE(service()->album_photos().empty()); + + service()->FetchAlbumPhotos("album_id", "photo_container_id"); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(service()->album_photos().empty()); +} + +TEST_F(NtpBackgroundServiceTest, AlbumPhotoErrorResponse) { + ntp::background::SettingPreviewResponse response; + response.set_status(ntp::background::ErrorCode::SERVER_ERROR); + response.set_error_msg("server error"); + std::string response_string; + response.SerializeToString(&response_string); + + SetUpResponseWithData(service()->GetAlbumPhotosApiUrlForTesting( + "album_id", "photo_container_id"), + response_string); + + ASSERT_TRUE(service()->album_photos().empty()); + + service()->FetchAlbumPhotos("album_id", "photo_container_id"); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(service()->album_photos().empty()); +} + +TEST_F(NtpBackgroundServiceTest, GoodAlbumPhotosResponse) { + ntp::background::SettingPreviewResponse::Preview preview; + preview.set_preview_url("https://wallpapers.co/some_image"); + ntp::background::SettingPreviewResponse response; + *response.add_preview() = preview; + std::string response_string; + response.SerializeToString(&response_string); + + SetUpResponseWithData(service()->GetAlbumPhotosApiUrlForTesting( + "album_id", "photo_container_id"), + response_string); + + ASSERT_TRUE(service()->album_photos().empty()); + + service()->FetchAlbumPhotos("album_id", "photo_container_id"); + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(service()->album_photos().empty()); + EXPECT_THAT(service()->album_photos().at(0).thumbnail_photo_url.spec(), + StartsWith(preview.preview_url())); + EXPECT_THAT(service()->album_photos().at(0).photo_url.spec(), + StartsWith(preview.preview_url())); +}
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc index c4eef85..812f86ca 100644 --- a/chrome/browser/search/local_ntp_source.cc +++ b/chrome/browser/search/local_ntp_source.cc
@@ -321,6 +321,20 @@ return albums; } +base::Value ConvertAlbumPhotosToDict( + const std::vector<AlbumPhoto>& album_photos) { + base::Value photos(base::Value::Type::LIST); + photos.GetList().reserve(album_photos.size()); + for (const AlbumPhoto& photo : album_photos) { + base::Value dict(base::Value::Type::DICTIONARY); + dict.SetKey("thumbnail_photo_url", + base::Value(photo.thumbnail_photo_url.spec())); + dict.SetKey("photo_url", base::Value(photo.photo_url.spec())); + photos.GetList().push_back(std::move(dict)); + } + return photos; +} + std::unique_ptr<base::DictionaryValue> ConvertOGBDataToDict( const OneGoogleBarData& og) { auto result = std::make_unique<base::DictionaryValue>(); @@ -673,7 +687,7 @@ callback); ntp_background_service_->FetchAlbumInfo(); } else { - // If there's no "collection_type" param, default to getting collections. + // If collection_type is not "album", default to getting collections. // TODO(ramyan): Explicitly require a collection_type when frontend // supports it. ntp_background_collections_requests_.emplace_back(base::TimeTicks::Now(), @@ -688,15 +702,38 @@ callback.Run(nullptr); return; } - std::string collection_id_param; + std::string collection_type_param; GURL path_url = GURL(chrome::kChromeSearchLocalNtpUrl).Resolve(path); - if (net::GetValueForKeyInQuery(path_url, "collection_id", - &collection_id_param)) { - ntp_background_image_info_requests_.emplace_back(base::TimeTicks::Now(), - callback); - ntp_background_service_->FetchCollectionImageInfo(collection_id_param); + if (net::GetValueForKeyInQuery(path_url, "collection_type", + &collection_type_param) && + (collection_type_param == "album")) { + std::string album_id_param; + std::string photo_container_id_param; + if (!net::GetValueForKeyInQuery(path_url, "album_id", &album_id_param) || + !net::GetValueForKeyInQuery(path_url, "photo_container_id", + &photo_container_id_param)) { + callback.Run(nullptr); + return; + } + ntp_background_photos_requests_.emplace_back(base::TimeTicks::Now(), + callback); + ntp_background_service_->FetchAlbumPhotos(album_id_param, + photo_container_id_param); } else { - callback.Run(nullptr); + // If collection_type is not "album", default to getting images for a + // collection. + // TODO(ramyan): Explicitly require a collection_type when frontend + // supports it. + std::string collection_id_param; + GURL path_url = GURL(chrome::kChromeSearchLocalNtpUrl).Resolve(path); + if (net::GetValueForKeyInQuery(path_url, "collection_id", + &collection_id_param)) { + ntp_background_image_info_requests_.emplace_back(base::TimeTicks::Now(), + callback); + ntp_background_service_->FetchCollectionImageInfo(collection_id_param); + } else { + callback.Run(nullptr); + } } return; } @@ -916,6 +953,30 @@ ntp_background_albums_requests_.clear(); } +void LocalNtpSource::OnAlbumPhotosAvailable() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + if (ntp_background_photos_requests_.empty()) + return; + + scoped_refptr<base::RefCountedString> result; + std::string js; + base::JSONWriter::Write( + ConvertAlbumPhotosToDict(ntp_background_service_->album_photos()), &js); + js = "var photos = " + js + ";"; + result = base::RefCountedString::TakeString(&js); + + base::TimeTicks now = base::TimeTicks::Now(); + for (const auto& request : ntp_background_photos_requests_) { + request.callback.Run(result); + base::TimeDelta delta = now - request.start_time; + UMA_HISTOGRAM_MEDIUM_TIMES( + "NewTabPage.BackgroundService.Photos.RequestLatency", delta); + // TODO(ramyan): Define and capture latency for failed requests. + } + ntp_background_photos_requests_.clear(); +} + void LocalNtpSource::OnNtpBackgroundServiceShuttingDown() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/search/local_ntp_source.h b/chrome/browser/search/local_ntp_source.h index 8a22225..11246b5f 100644 --- a/chrome/browser/search/local_ntp_source.h +++ b/chrome/browser/search/local_ntp_source.h
@@ -92,6 +92,7 @@ void OnCollectionInfoAvailable() override; void OnCollectionImagesAvailable() override; void OnAlbumInfoAvailable() override; + void OnAlbumPhotosAvailable() override; void OnNtpBackgroundServiceShuttingDown() override; // Overridden from OneGoogleBarServiceObserver: @@ -105,6 +106,7 @@ std::vector<NtpBackgroundRequest> ntp_background_collections_requests_; std::vector<NtpBackgroundRequest> ntp_background_image_info_requests_; std::vector<NtpBackgroundRequest> ntp_background_albums_requests_; + std::vector<NtpBackgroundRequest> ntp_background_photos_requests_; NtpBackgroundService* ntp_background_service_;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index cf7e83e..2a21e06e 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1237,9 +1237,9 @@ ] deps += [ "//chrome/browser:jni_headers", + "//components/embedder_support/android:web_contents_delegate", "//components/navigation_interception", "//components/subresource_filter/core/browser:browser", - "//components/web_contents_delegate_android", "//crypto:platform", "//device/usb/mojo", "//device/usb/public/cpp", @@ -1751,6 +1751,11 @@ if (!toolkit_views) { sources += [ "media_router/cloud_services_dialog.cc" ] } + + # TODO(loyso): Rework these dependencies. http://crbug.com/862049 + if (enable_extensions) { + deps += [ "//chrome/browser/web_applications" ] + } } if (is_chromeos) {
diff --git a/chrome/browser/ui/android/color_chooser_dialog_android.cc b/chrome/browser/ui/android/color_chooser_dialog_android.cc index 0459b14..0abbae6 100644 --- a/chrome/browser/ui/android/color_chooser_dialog_android.cc +++ b/chrome/browser/ui/android/color_chooser_dialog_android.cc
@@ -5,7 +5,7 @@ #include "chrome/browser/ui/browser_dialogs.h" // The actual android color chooser is at -// components/web_contents_delegate_android/color_chooser_android.cc +// components/embedder_support/android/delegate/color_chooser_android.cc namespace chrome {
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index 1bb23bc..1906f9d0 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -42,6 +42,7 @@ #include "chrome/browser/predictors/loading_predictor_tab_helper.h" #include "chrome/browser/prerender/prerender_tab_helper.h" #include "chrome/browser/previews/previews_infobar_tab_helper.h" +#include "chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/resource_coordinator/tab_helper.h" #include "chrome/browser/safe_browsing/trigger_creator.h" @@ -240,6 +241,7 @@ prerender::PrerenderTabHelper::CreateForWebContents(web_contents); PreviewsInfoBarTabHelper::CreateForWebContents(web_contents); RecentlyAudibleHelper::CreateForWebContents(web_contents); + ResourceLoadingHintsWebContentsObserver::CreateForWebContents(web_contents); safe_browsing::TriggerCreator::MaybeCreateTriggersForWebContents( profile, web_contents); SearchEngineTabHelper::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc index 961a27a..6ef7a55 100644 --- a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc +++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
@@ -32,6 +32,7 @@ #include "ui/views/controls/button/blue_button.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/label.h" +#include "ui/views/controls/separator.h" #include "ui/views/controls/styled_label.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/layout/box_layout.h" @@ -43,9 +44,19 @@ namespace { // Dimensions of the Google Pay logo. -const int kGooglePayLogoWidth = 57; +const int kGooglePayLogoWidth = 40; const int kGooglePayLogoHeight = 16; +const int kGooglePayLogoSeparatorHeight = 12; + +// Using custom padding instead of reusing left/right padding from +// INSETS_DIALOG_TITLE, because it gives too much spacing when there is a +// separator line between the icon and the title. +// TODO(ftirelo): This padding should come from the layout provider. +const int kTitleSeparatorPadding = 8; + +const SkColor kTitleSeparatorColor = SkColorSetRGB(0x9E, 0x9E, 0x9E); + std::unique_ptr<views::StyledLabel> CreateLegalMessageLineLabel( const LegalMessageLine& line, views::StyledLabelListener* listener) { @@ -171,6 +182,49 @@ return gfx::Size(width, GetHeightForWidth(width)); } +void SaveCardBubbleViews::AddedToWidget() { + // Use a custom title container if this is a server card. Done when this view + // is added to the widget, so the bubble frame view is guaranteed to exist. + if (GetCurrentFlowStep() != UPLOAD_SAVE_ONLY_STEP) + return; + + auto title_container = std::make_unique<views::View>(); + title_container->SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::kHorizontal, gfx::Insets(), kTitleSeparatorPadding)); + + // kGooglePayLogoIcon is square, and CreateTiledImage() will clip it whereas + // setting the icon size would rescale it incorrectly. + gfx::ImageSkia image = gfx::ImageSkiaOperations::CreateTiledImage( + gfx::CreateVectorIcon(kGooglePayLogoIcon, gfx::kPlaceholderColor), + /*x=*/0, /*y=*/0, kGooglePayLogoWidth, kGooglePayLogoHeight); + auto icon_view = std::make_unique<views::ImageView>(); + icon_view->SetImage(&image); + title_container->AddChildView(icon_view.release()); + + auto* separator = new views::Separator(); + separator->SetColor(kTitleSeparatorColor); + title_container->AddChildView(separator); + + auto title_label = std::make_unique<views::Label>( + GetWindowTitle(), views::style::CONTEXT_DIALOG_TITLE); + title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + title_label->SetMultiLine(true); + title_container->AddChildView(title_label.release()); + + GetBubbleFrameView()->SetTitleView(std::move(title_container)); + + // Add vertical padding to the separator doesn't expand to use all the + // available vertical space. This needs to be done after the title container + // is added to the bubble frame view, in order to use its preferred size. + const int separator_vertical_padding = + (GetBubbleFrameView()->title()->GetPreferredSize().height() - + kGooglePayLogoSeparatorHeight) / + 2; + separator->SetBorder(views::CreateEmptyBorder(gfx::Insets( + /*vertical=*/separator_vertical_padding, + /*horizontal=*/0))); +} + bool SaveCardBubbleViews::ShouldShowCloseButton() const { // The [X] is shown for Material UI. return ui::MaterialDesignController::IsSecondaryUiMaterial(); @@ -180,18 +234,6 @@ return controller_ ? controller_->GetWindowTitle() : base::string16(); } -gfx::ImageSkia SaveCardBubbleViews::GetWindowIcon() { - return gfx::ImageSkiaOperations::CreateTiledImage( - gfx::CreateVectorIcon(kGooglePayLogoWithVerticalSeparatorIcon, - gfx::kPlaceholderColor), - /*x=*/0, /*y=*/0, kGooglePayLogoWidth, kGooglePayLogoHeight); -} - -bool SaveCardBubbleViews::ShouldShowWindowIcon() const { - // We show the window icon (the Google Pay logo) in non-local save scenarios. - return GetCurrentFlowStep() != LOCAL_SAVE_ONLY_STEP; -} - void SaveCardBubbleViews::WindowClosing() { if (controller_) { controller_->OnBubbleClosed();
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.h b/chrome/browser/ui/views/autofill/save_card_bubble_views.h index 8ab9cb5..8eb7a0c 100644 --- a/chrome/browser/ui/views/autofill/save_card_bubble_views.h +++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.h
@@ -53,12 +53,11 @@ // views::View: gfx::Size CalculatePreferredSize() const override; + void AddedToWidget() override; // views::WidgetDelegate: bool ShouldShowCloseButton() const override; base::string16 GetWindowTitle() const override; - gfx::ImageSkia GetWindowIcon() override; - bool ShouldShowWindowIcon() const override; void WindowClosing() override; // views::StyledLabelListener: @@ -94,7 +93,7 @@ ~SaveCardBubbleViews() override; CurrentFlowStep GetCurrentFlowStep() const; - // Create the dialog's content view containing everything except for the + // Creates the dialog's content view containing everything except for the // footnote. std::unique_ptr<views::View> CreateMainContentView();
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.h index 057c05e..8414b3c1 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.h +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.h
@@ -68,7 +68,10 @@ }; void PaintThemedFrame(gfx::Canvas* canvas); - int GetTabStripRightInset() const; + + // Returns the width taken by any items after the tabstrip, to the edge of the + // window. Does not include any padding between the tabstrip and these items. + int GetAfterTabstripItemWidth() const; // Used to keep track of the update of kShowFullscreenToolbar preference. PrefChangeRegistrar pref_registrar_;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm index f77a49f..f4b6b58c 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
@@ -51,9 +51,10 @@ gfx::Rect BrowserNonClientFrameViewMac::GetBoundsForTabStrip( views::View* tabstrip) const { DCHECK(tabstrip); + gfx::Rect bounds = gfx::Rect(0, kTabstripTopInset, width(), tabstrip->GetPreferredSize().height()); - bounds.Inset(GetTabStripLeftInset(), 0, GetTabStripRightInset(), 0); + bounds.Inset(GetTabStripLeftInset(), 0, GetAfterTabstripItemWidth() + 4, 0); return bounds; } @@ -61,17 +62,16 @@ return browser_view()->IsTabStripVisible() ? kTabstripTopInset : 0; } -int BrowserNonClientFrameViewMac::GetTabStripRightInset() const { - constexpr int kTabstripRightInset = 4; // Margin for profile switcher. - int inset = kTabstripRightInset; - views::View* profile_switcher_view = GetProfileSwitcherButton(); - if (profile_switcher_view) { - inset += profile_switcher_view->GetPreferredSize().width(); - } else if (profile_indicator_icon()) { - inset += - profile_indicator_icon()->bounds().width() + GetAvatarIconPadding(); - } - return inset; +int BrowserNonClientFrameViewMac::GetAfterTabstripItemWidth() const { + int item_width; + views::View* profile_switcher_button = GetProfileSwitcherButton(); + if (profile_indicator_icon() && browser_view()->IsTabStripVisible()) + item_width = profile_indicator_icon()->width(); + else if (profile_switcher_button) + item_width = profile_switcher_button->GetPreferredSize().width(); + else + return 0; + return item_width + GetAvatarIconPadding(); } int BrowserNonClientFrameViewMac::GetThemeBackgroundXInset() const { @@ -194,15 +194,15 @@ void BrowserNonClientFrameViewMac::Layout() { DCHECK(browser_view()); - views::View* profile_switcher_view = GetProfileSwitcherButton(); + views::View* profile_switcher_button = GetProfileSwitcherButton(); if (profile_indicator_icon() && browser_view()->IsTabStripVisible()) { LayoutIncognitoButton(); // Mac lays out the incognito icon on the right, as the stoplight // buttons live in its Windows/Linux location. - profile_indicator_icon()->SetX(width() - GetTabStripRightInset()); - } else if (profile_switcher_view != nullptr) { - gfx::Size button_size = profile_switcher_view->GetPreferredSize(); - int button_x = width() - GetTabStripRightInset(); + profile_indicator_icon()->SetX(width() - GetAfterTabstripItemWidth()); + } else if (profile_switcher_button) { + gfx::Size button_size = profile_switcher_button->GetPreferredSize(); + int button_x = width() - GetAfterTabstripItemWidth(); int button_y = 0; TabStrip* tabstrip = browser_view()->tabstrip(); if (tabstrip && browser_view()->IsTabStripVisible()) { @@ -211,8 +211,8 @@ // Align the switcher's bottom to bottom of the new tab button; button_y = new_tab_button_bottom - button_size.height(); } - profile_switcher_view->SetBounds(button_x, button_y, button_size.width(), - button_size.height()); + profile_switcher_button->SetBounds(button_x, button_y, button_size.width(), + button_size.height()); } BrowserNonClientFrameView::Layout(); }
diff --git a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc index eef05396..652c528 100644 --- a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc +++ b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
@@ -41,21 +41,43 @@ } #if !defined(USE_AURA) - // For non-Aura platforms, forward mouse events intended for the omnibox to - // the Widget owning the omnibox. For Aura platforms, this is done with an - // event targeter set up in RoundedOmniboxResultsFrame::AddedToWidget(), - // below. - void OnMouseEvent(ui::MouseEvent* event) override { + // For non-Aura platforms, forward mouse events and cursor requests intended + // for the omnibox to the proper Widgets/Views. For Aura platforms, this is + // done with an event targeter set up in + // RoundedOmniboxResultsFrame::AddedToWidget(), below. + private: + struct OmniboxWidgetEventPair { + views::Widget* widget; + ui::MouseEvent event; + }; + + OmniboxWidgetEventPair GetOmniboxWidgetAndEvent(const ui::MouseEvent* event) { views::Widget* omnibox_widget = GetWidget()->GetTopLevelWidgetForNativeView( GetWidget()->GetNativeView()); DCHECK_NE(GetWidget(), omnibox_widget); - ui::MouseEvent omnibox_event(*event); + gfx::Point event_location = event->location(); views::View::ConvertPointToScreen(this, &event_location); views::View::ConvertPointFromScreen(omnibox_widget->GetRootView(), &event_location); + + ui::MouseEvent omnibox_event(*event); omnibox_event.set_location(event_location); - omnibox_widget->OnMouseEvent(&omnibox_event); + + return {omnibox_widget, omnibox_event}; + } + + void OnMouseEvent(ui::MouseEvent* event) override { + auto pair = GetOmniboxWidgetAndEvent(event); + pair.widget->OnMouseEvent(&pair.event); + } + + gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override { + auto pair = GetOmniboxWidgetAndEvent(&event); + views::View* omnibox_view = + pair.widget->GetRootView()->GetEventHandlerForPoint( + pair.event.location()); + return omnibox_view->GetCursor(pair.event); } #endif // !AURA };
diff --git a/chrome/browser/ui/webui/settings/chrome_cleanup_handler.cc b/chrome/browser/ui/webui/settings/chrome_cleanup_handler.cc index 7119710..4124e67 100644 --- a/chrome/browser/ui/webui/settings/chrome_cleanup_handler.cc +++ b/chrome/browser/ui/webui/settings/chrome_cleanup_handler.cc
@@ -44,13 +44,12 @@ return value; } -// Returns a ListValue containing a copy of the registry keys stored in -// |registry_keys|. -std::unique_ptr<base::ListValue> GetRegistryKeysAsListStorage( - const std::set<base::string16>& registry_keys) { +// Returns a ListValue containing a copy of the strings stored in |string_set|. +std::unique_ptr<base::ListValue> GetStringSetAsListStorage( + const std::set<base::string16>& string_set) { auto value = std::make_unique<base::ListValue>(); - for (const base::string16& key : registry_keys) - value->AppendString(key); + for (const base::string16& string : string_set) + value->AppendString(string); return value; } @@ -61,7 +60,9 @@ value.SetList("files", GetFilesAsListStorage(scanner_results.files_to_delete())); value.SetList("registryKeys", - GetRegistryKeysAsListStorage(scanner_results.registry_keys())); + GetStringSetAsListStorage(scanner_results.registry_keys())); + value.SetList("extensions", + GetStringSetAsListStorage(scanner_results.extension_names())); return value; }
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 636aad1..6ab3ef5b 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -857,6 +857,8 @@ LocalizedString localized_strings[] = { {"chromeCleanupPageTitle", IDS_SETTINGS_RESET_CLEAN_UP_COMPUTER_PAGE_TITLE}, + {"chromeCleanupDetailsExtensions", + IDS_SETTINGS_RESET_CLEANUP_DETAILS_EXTENSIONS}, {"chromeCleanupDetailsFilesAndPrograms", IDS_SETTINGS_RESET_CLEANUP_DETAILS_FILES_AND_PROGRAMS}, {"chromeCleanupDetailsRegistryEntries",
diff --git a/chrome/browser/vr/OWNERS b/chrome/browser/vr/OWNERS index 442d1ef..a89c9964 100644 --- a/chrome/browser/vr/OWNERS +++ b/chrome/browser/vr/OWNERS
@@ -1,15 +1,14 @@ -bajones@chromium.org -bshe@chromium.org -mthiesse@chromium.org -cjgrant@chromium.org -vollick@chromium.org asimjour@chromium.org +cjgrant@chromium.org +mthiesse@chromium.org tiborg@chromium.org +vollick@chromium.org -# WebVR-related +# WebXR-related. klausw@chromium.org -# Browser Test-related +# Browser Test-related. bsheedy@chromium.org +# TEAM: xr-dev@chromium.org # COMPONENT: UI>Browser>VR
diff --git a/chrome/browser/vr/service/OWNERS b/chrome/browser/vr/service/OWNERS new file mode 100644 index 0000000..84a66d7 --- /dev/null +++ b/chrome/browser/vr/service/OWNERS
@@ -0,0 +1,4 @@ +billorr@chromium.org + +# TEAM: xr-dev@chromium.org +# COMPONENT: Blink>WebXR
diff --git a/chrome/browser/vr/vector_icons/OWNERS b/chrome/browser/vr/vector_icons/OWNERS index d7ec991..5f591d70 100644 --- a/chrome/browser/vr/vector_icons/OWNERS +++ b/chrome/browser/vr/vector_icons/OWNERS
@@ -1 +1,4 @@ file://components/vector_icons/OWNERS + +# TEAM: xr-dev@chromium.org +# COMPONENT: UI>Browser>VR
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index 8b49ffa..2deb4ad 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -4,25 +4,32 @@ import("//extensions/buildflags/buildflags.gni") -assert(enable_extensions) - source_set("web_applications") { sources = [ - "extensions/pending_bookmark_app_manager.cc", - "extensions/pending_bookmark_app_manager.h", - "policy/web_app_policy_constants.cc", - "policy/web_app_policy_constants.h", - "policy/web_app_policy_manager.cc", - "policy/web_app_policy_manager.h", - "policy/web_app_policy_manager_factory.cc", - "policy/web_app_policy_manager_factory.h", + "web_app.cc", + "web_app.h", + "web_app_chromeos.cc", + "web_app_mac.h", + "web_app_mac.mm", + "web_app_win.cc", + "web_app_win.h", ] + if (is_desktop_linux) { + # Desktop linux, doesn't count ChromeOS. + sources += [ "web_app_linux.cc" ] + } + configs += [ "//build/config/compiler:wexit_time_destructors" ] + # TODO(loyso): Break this dependency cycle. + allow_circular_includes_from = [ "//chrome/browser/extensions" ] + deps = [ "//base", "//chrome/browser/extensions", + "//chrome/browser/web_applications/bookmark_apps", + "//chrome/browser/web_applications/components", "//chrome/common", "//components/keyed_service/content", "//components/prefs", @@ -30,3 +37,28 @@ "//url", ] } + +source_set("web_applications_unit_tests") { + testonly = true + + sources = [ + "web_app_mac_unittest.mm", + "web_app_unittest.cc", + ] + + deps = [ + ":web_applications", + "//chrome/browser/extensions", + "//extensions/browser", + "//skia", + "//testing/gmock", + ] +} + +source_set("unit_tests") { + testonly = true + deps = [ + ":web_applications_unit_tests", + "//chrome/browser/web_applications/bookmark_apps:unit_tests", + ] +}
diff --git a/chrome/browser/web_applications/bookmark_apps/BUILD.gn b/chrome/browser/web_applications/bookmark_apps/BUILD.gn new file mode 100644 index 0000000..a0d4c7fee --- /dev/null +++ b/chrome/browser/web_applications/bookmark_apps/BUILD.gn
@@ -0,0 +1,23 @@ +# 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. + +import("//extensions/buildflags/buildflags.gni") + +assert(enable_extensions) + +source_set("bookmark_apps") { + deps = [ + # TODO(ortuno): Move policy to bookmark_apps/policy + "//chrome/browser/web_applications/policy", + ] +} + +source_set("unit_tests") { + testonly = true + + deps = [ + # TODO(ortuno): Move policy to bookmark_apps/policy + "//chrome/browser/web_applications/policy:unit_tests", + ] +}
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn new file mode 100644 index 0000000..a168494 --- /dev/null +++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -0,0 +1,7 @@ +# 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. + +source_set("components") { + # TODO(loyso): Add os_shortcuts component here. +}
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn new file mode 100644 index 0000000..073b8be --- /dev/null +++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -0,0 +1,18 @@ +# 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. + +import("//extensions/buildflags/buildflags.gni") + +assert(enable_extensions) + +source_set("extensions") { + sources = [ + "pending_bookmark_app_manager.cc", + "pending_bookmark_app_manager.h", + ] + + deps = [ + "//chrome/browser/web_applications/components", + ] +}
diff --git a/chrome/browser/web_applications/policy/BUILD.gn b/chrome/browser/web_applications/policy/BUILD.gn new file mode 100644 index 0000000..eedea42 --- /dev/null +++ b/chrome/browser/web_applications/policy/BUILD.gn
@@ -0,0 +1,39 @@ +# 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. + +import("//extensions/buildflags/buildflags.gni") + +assert(enable_extensions) + +source_set("policy") { + sources = [ + "web_app_policy_constants.cc", + "web_app_policy_constants.h", + "web_app_policy_manager.cc", + "web_app_policy_manager.h", + "web_app_policy_manager_factory.cc", + "web_app_policy_manager_factory.h", + ] + + deps = [ + "//chrome/browser/extensions", + "//chrome/common", + "//components/keyed_service/content", + "//skia", + ] +} + +source_set("unit_tests") { + testonly = true + + sources = [ + "web_app_policy_manager_unittest.cc", + ] + + deps = [ + ":policy", + "//skia", + "//testing/gmock", + ] +}
diff --git a/chrome/common/extensions/api/chromeos_info_private.json b/chrome/common/extensions/api/chromeos_info_private.json index 7f34f7a..641d1ef0 100644 --- a/chrome/common/extensions/api/chromeos_info_private.json +++ b/chrome/common/extensions/api/chromeos_info_private.json
@@ -52,6 +52,12 @@ "type": "string", "enum": ["chromebase", "chromebit", "chromebook", "chromebox", "chromedevice"], "description": "Device type." + }, + { + "id": "StylusStatus", + "type": "string", + "enum": ["unsupported", "supported"], + "description": "Status of stylus." } ], "functions": [ @@ -85,6 +91,7 @@ "playStoreStatus": {"$ref": "PlayStoreStatus", "optional": true}, "managedDeviceStatus": {"$ref": "ManagedDeviceStatus", "optional": true}, "deviceType": {"$ref": "DeviceType", "optional": true}, + "stylusStatus": {"$ref": "StylusStatus", "optional": true}, "clientId" : {"type": "string", "optional": true, "description": "Device client id"}, "timezone" : {"type": "string", "optional": true, "description": "Timezone"}, "a11yLargeCursorEnabled" : {"type": "boolean", "optional": true, "description": "If true, ChromeOS is showing enlarged cursor."},
diff --git a/chrome/common/page_load_metrics/page_load_metrics.mojom b/chrome/common/page_load_metrics/page_load_metrics.mojom index 5222ebd..4842669 100644 --- a/chrome/common/page_load_metrics/page_load_metrics.mojom +++ b/chrome/common/page_load_metrics/page_load_metrics.mojom
@@ -151,10 +151,22 @@ array<int32> animated_css_properties; }; +// Data used for the page load. +struct PageLoadDataUse { + // Network bytes received for the page load. + int64 received_data_length = 0; + + // The number of bytes saved by the data reduction proxy. Will be zero when + // data reduction proxy is not used. Can be negative if the proxy inflated the + // resource. + int64 data_reduction_proxy_bytes_saved = 0; +}; + // Sent from renderer to browser process when the PageLoadTiming for the // associated frame changed. interface PageLoadMetrics { UpdateTiming(PageLoadTiming page_load_timing, PageLoadMetadata page_load_metadata, - PageLoadFeatures new_features); + PageLoadFeatures new_features, + PageLoadDataUse data_use); };
diff --git a/chrome/installer/linux/debian/build.sh b/chrome/installer/linux/debian/build.sh index 8234caf..306b59c 100755 --- a/chrome/installer/linux/debian/build.sh +++ b/chrome/installer/linux/debian/build.sh
@@ -278,6 +278,9 @@ arm ) export ARCHITECTURE="armhf" ;; + arm64 ) + export ARCHITECTURE="arm64" + ;; ia32 ) export ARCHITECTURE="i386" ;;
diff --git a/chrome/installer/linux/debian/calculate_package_deps.py b/chrome/installer/linux/debian/calculate_package_deps.py index 2bef1f6..84fdc25 100755 --- a/chrome/installer/linux/debian/calculate_package_deps.py +++ b/chrome/installer/linux/debian/calculate_package_deps.py
@@ -41,6 +41,9 @@ elif arch == 'arm': cmd.extend(['-l%s/usr/lib/arm-linux-gnueabihf' % sysroot, '-l%s/lib/arm-linux-gnueabihf' % sysroot]) +elif arch == 'arm64': + cmd.extend(['-l%s/usr/lib/aarch64-linux-gnu' % sysroot, + '-l%s/lib/aarch64-linux-gnu' % sysroot]) elif arch == 'mipsel': cmd.extend(['-l%s/usr/lib/mipsel-linux-gnu' % sysroot, '-l%s/lib/mipsel-linux-gnu' % sysroot])
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn index 724a981..0a1e575 100644 --- a/chrome/renderer/BUILD.gn +++ b/chrome/renderer/BUILD.gn
@@ -73,6 +73,8 @@ "net_benchmarking_extension.h", "page_load_metrics/metrics_render_frame_observer.cc", "page_load_metrics/metrics_render_frame_observer.h", + "page_load_metrics/page_resource_data_use.cc", + "page_load_metrics/page_resource_data_use.h", "page_load_metrics/page_timing_metrics_sender.cc", "page_load_metrics/page_timing_metrics_sender.h", "page_load_metrics/page_timing_sender.h",
diff --git a/chrome/renderer/page_load_metrics/fake_page_timing_sender.cc b/chrome/renderer/page_load_metrics/fake_page_timing_sender.cc index 1977d9b5..1026984cb 100644 --- a/chrome/renderer/page_load_metrics/fake_page_timing_sender.cc +++ b/chrome/renderer/page_load_metrics/fake_page_timing_sender.cc
@@ -17,8 +17,9 @@ void FakePageTimingSender::SendTiming( const mojom::PageLoadTimingPtr& timing, const mojom::PageLoadMetadataPtr& metadata, - mojom::PageLoadFeaturesPtr new_features) { - validator_->UpdateTiming(timing, metadata, new_features); + mojom::PageLoadFeaturesPtr new_features, + mojom::PageLoadDataUsePtr new_data_use) { + validator_->UpdateTiming(timing, metadata, new_features, new_data_use); } FakePageTimingSender::PageTimingValidator::PageTimingValidator() {} @@ -93,7 +94,8 @@ void FakePageTimingSender::PageTimingValidator::UpdateTiming( const mojom::PageLoadTimingPtr& timing, const mojom::PageLoadMetadataPtr& metadata, - const mojom::PageLoadFeaturesPtr& new_features) { + const mojom::PageLoadFeaturesPtr& new_features, + const mojom::PageLoadDataUsePtr& new_data_use) { actual_timings_.push_back(timing.Clone()); for (const auto feature : new_features->features) { EXPECT_EQ(actual_features_.find(feature), actual_features_.end())
diff --git a/chrome/renderer/page_load_metrics/fake_page_timing_sender.h b/chrome/renderer/page_load_metrics/fake_page_timing_sender.h index 117ca34..910e700 100644 --- a/chrome/renderer/page_load_metrics/fake_page_timing_sender.h +++ b/chrome/renderer/page_load_metrics/fake_page_timing_sender.h
@@ -70,7 +70,8 @@ void UpdateTiming(const mojom::PageLoadTimingPtr& timing, const mojom::PageLoadMetadataPtr& metadata, - const mojom::PageLoadFeaturesPtr& new_features); + const mojom::PageLoadFeaturesPtr& new_features, + const mojom::PageLoadDataUsePtr& new_data_use); private: std::vector<mojom::PageLoadTimingPtr> expected_timings_; @@ -86,7 +87,8 @@ ~FakePageTimingSender() override; void SendTiming(const mojom::PageLoadTimingPtr& timing, const mojom::PageLoadMetadataPtr& metadata, - mojom::PageLoadFeaturesPtr new_features) override; + mojom::PageLoadFeaturesPtr new_features, + mojom::PageLoadDataUsePtr new_data_use) override; private: PageTimingValidator* const validator_;
diff --git a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc index 99fe8d02..40131f3 100644 --- a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc +++ b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.cc
@@ -40,10 +40,12 @@ ~MojoPageTimingSender() override {} void SendTiming(const mojom::PageLoadTimingPtr& timing, const mojom::PageLoadMetadataPtr& metadata, - mojom::PageLoadFeaturesPtr new_features) override { + mojom::PageLoadFeaturesPtr new_features, + mojom::PageLoadDataUsePtr new_data_use) override { DCHECK(page_load_metrics_); page_load_metrics_->UpdateTiming(timing->Clone(), metadata->Clone(), - std::move(new_features)); + std::move(new_features), + std::move(new_data_use)); } private: @@ -88,22 +90,73 @@ void MetricsRenderFrameObserver::DidStartResponse( int request_id, const network::ResourceResponseHead& response_head, - content::ResourceType resource_type) {} + content::ResourceType resource_type) { + if (provisional_frame_resource_data_use_ && + content::IsResourceTypeFrame(resource_type)) { + // TODO(rajendrant): This frame request might start before the provisional + // load starts, and data use of the frame request might be missed in that + // case. There should be a guarantee that DidStartProvisionalLoad be called + // before DidStartResponse for the frame request. + provisional_frame_resource_data_use_->DidStartResponse(request_id, + response_head); + } else if (page_timing_metrics_sender_) { + page_timing_metrics_sender_->DidStartResponse(request_id, response_head); + } +} void MetricsRenderFrameObserver::DidCompleteResponse( int request_id, - const network::URLLoaderCompletionStatus& status) {} + const network::URLLoaderCompletionStatus& status) { + if (provisional_frame_resource_data_use_ && + provisional_frame_resource_data_use_->resource_id() == request_id) { + provisional_frame_resource_data_use_->DidCompleteResponse( + status, provisional_delta_data_use_.get()); + } else if (page_timing_metrics_sender_) { + page_timing_metrics_sender_->DidCompleteResponse(request_id, status); + } +} -void MetricsRenderFrameObserver::DidCancelResponse(int request_id) {} +void MetricsRenderFrameObserver::DidCancelResponse(int request_id) { + if (provisional_frame_resource_data_use_ && + provisional_frame_resource_data_use_->resource_id() == request_id) { + provisional_frame_resource_data_use_.reset(); + } else if (page_timing_metrics_sender_) { + page_timing_metrics_sender_->DidCancelResponse(request_id); + } +} void MetricsRenderFrameObserver::DidReceiveTransferSizeUpdate( int request_id, - int received_data_length) {} + int received_data_length) { + if (provisional_frame_resource_data_use_ && + provisional_frame_resource_data_use_->resource_id() == request_id) { + provisional_frame_resource_data_use_->DidReceiveTransferSizeUpdate( + received_data_length, provisional_delta_data_use_.get()); + } else if (page_timing_metrics_sender_) { + page_timing_metrics_sender_->DidReceiveTransferSizeUpdate( + request_id, received_data_length); + } +} void MetricsRenderFrameObserver::FrameDetached() { page_timing_metrics_sender_.reset(); } +void MetricsRenderFrameObserver::DidStartProvisionalLoad( + blink::WebDocumentLoader* document_loader) { + // Create a new data use tracker for the new provisional load. + provisional_frame_resource_data_use_ = + std::make_unique<PageResourceDataUse>(); + provisional_delta_data_use_ = mojom::PageLoadDataUse::New(); +} + +void MetricsRenderFrameObserver::DidFailProvisionalLoad( + const blink::WebURLError& error) { + // Clear the data use tracker for the provisional navigation that started. + provisional_frame_resource_data_use_.reset(); + provisional_delta_data_use_.reset(); +} + void MetricsRenderFrameObserver::DidCommitProvisionalLoad( bool is_new_navigation, bool is_same_document_navigation) { @@ -122,7 +175,9 @@ return; page_timing_metrics_sender_ = std::make_unique<PageTimingMetricsSender>( - CreatePageTimingSender(), CreateTimer(), GetTiming()); + CreatePageTimingSender(), CreateTimer(), GetTiming(), + std::move(provisional_frame_resource_data_use_), + std::move(provisional_delta_data_use_)); } void MetricsRenderFrameObserver::SendMetrics() {
diff --git a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h index c04f150..8959f55 100644 --- a/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h +++ b/chrome/renderer/page_load_metrics/metrics_render_frame_observer.h
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "chrome/common/page_load_metrics/page_load_timing.h" +#include "chrome/renderer/page_load_metrics/page_resource_data_use.h" #include "content/public/renderer/render_frame_observer.h" #include "third_party/blink/public/platform/web_loading_behavior_flag.h" @@ -47,6 +48,9 @@ int request_id, const network::URLLoaderCompletionStatus& status) override; void DidCancelResponse(int request_id) override; + void DidStartProvisionalLoad( + blink::WebDocumentLoader* document_loader) override; + void DidFailProvisionalLoad(const blink::WebURLError& error) override; void DidCommitProvisionalLoad(bool is_new_navigation, bool is_same_document_navigation) override; void OnDestruct() override; @@ -62,6 +66,15 @@ virtual std::unique_ptr<PageTimingSender> CreatePageTimingSender(); virtual bool HasNoRenderFrame() const; + // Collects the data use of the frame request for a provisional load until the + // load is committed. We want to collect data use for completed navigations in + // this class, but the various navigation callbacks do not provide enough data + // for us to use them for data attribution. Instead, we try to get this + // information from ongoing resource requests on the previous page (or right + // before this page loads in a new renderer). + std::unique_ptr<PageResourceDataUse> provisional_frame_resource_data_use_; + mojom::PageLoadDataUsePtr provisional_delta_data_use_; + // Will be null when we're not actively sending metrics. std::unique_ptr<PageTimingMetricsSender> page_timing_metrics_sender_;
diff --git a/chrome/renderer/page_load_metrics/metrics_render_frame_observer_unittest.cc b/chrome/renderer/page_load_metrics/metrics_render_frame_observer_unittest.cc index 3a0b3e9..8be20eb 100644 --- a/chrome/renderer/page_load_metrics/metrics_render_frame_observer_unittest.cc +++ b/chrome/renderer/page_load_metrics/metrics_render_frame_observer_unittest.cc
@@ -81,6 +81,7 @@ page_load_metrics::InitPageLoadTimingForTest(&timing); timing.navigation_start = nav_start; observer.ExpectPageLoadTiming(timing); + observer.DidStartProvisionalLoad(nullptr); observer.DidCommitProvisionalLoad(true, false); observer.GetMockTimer()->Fire(); @@ -103,6 +104,7 @@ page_load_metrics::InitPageLoadTimingForTest(&timing); timing.navigation_start = nav_start; observer.ExpectPageLoadTiming(timing); + observer.DidStartProvisionalLoad(nullptr); observer.DidCommitProvisionalLoad(true, false); observer.GetMockTimer()->Fire(); @@ -149,6 +151,7 @@ page_load_metrics::InitPageLoadTimingForTest(&timing); timing.navigation_start = nav_start; observer.ExpectPageLoadTiming(timing); + observer.DidStartProvisionalLoad(nullptr); observer.DidCommitProvisionalLoad(true, false); observer.GetMockTimer()->Fire(); @@ -175,6 +178,7 @@ observer.SetMockTimer(nullptr); observer.ExpectPageLoadTiming(timing_2); + observer.DidStartProvisionalLoad(nullptr); observer.DidCommitProvisionalLoad(true, false); observer.GetMockTimer()->Fire();
diff --git a/chrome/renderer/page_load_metrics/page_resource_data_use.cc b/chrome/renderer/page_load_metrics/page_resource_data_use.cc new file mode 100644 index 0000000..02ba8714 --- /dev/null +++ b/chrome/renderer/page_load_metrics/page_resource_data_use.cc
@@ -0,0 +1,54 @@ +// 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. + +#include "chrome/renderer/page_load_metrics/page_resource_data_use.h" + +#include "base/stl_util.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" +#include "services/network/public/cpp/resource_response.h" +#include "services/network/public/cpp/url_loader_completion_status.h" + +namespace page_load_metrics { + +PageResourceDataUse::PageResourceDataUse() + : resource_id_(-1), + data_reduction_proxy_compression_ratio_estimate_(1.0), + total_received_bytes_(0) {} + +PageResourceDataUse::~PageResourceDataUse() = default; + +void PageResourceDataUse::DidStartResponse( + int resource_id, + const network::ResourceResponseHead& response_head) { + resource_id_ = resource_id; + data_reduction_proxy_compression_ratio_estimate_ = + data_reduction_proxy::EstimateCompressionRatioFromHeaders(&response_head); + total_received_bytes_ = 0; +} + +void PageResourceDataUse::DidReceiveTransferSizeUpdate( + int received_data_length, + mojom::PageLoadDataUse* delta_data_use) { + delta_data_use->received_data_length += received_data_length; + delta_data_use->data_reduction_proxy_bytes_saved += + received_data_length * + (data_reduction_proxy_compression_ratio_estimate_ - 1.0); + total_received_bytes_ += received_data_length; +} + +bool PageResourceDataUse::DidCompleteResponse( + const network::URLLoaderCompletionStatus& status, + mojom::PageLoadDataUse* delta_data_use) { + // Report the difference in received bytes. + int64_t delta_bytes = status.encoded_data_length - total_received_bytes_; + if (delta_bytes > 0) { + delta_data_use->received_data_length += delta_bytes; + delta_data_use->data_reduction_proxy_bytes_saved += + delta_bytes * (data_reduction_proxy_compression_ratio_estimate_ - 1.0); + return true; + } + return false; +} + +} // namespace page_load_metrics
diff --git a/chrome/renderer/page_load_metrics/page_resource_data_use.h b/chrome/renderer/page_load_metrics/page_resource_data_use.h new file mode 100644 index 0000000..c115fb6 --- /dev/null +++ b/chrome/renderer/page_load_metrics/page_resource_data_use.h
@@ -0,0 +1,53 @@ +// 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. + +#ifndef CHROME_RENDERER_PAGE_LOAD_METRICS_PAGE_RESOURCE_DATA_USE_H_ +#define CHROME_RENDERER_PAGE_LOAD_METRICS_PAGE_RESOURCE_DATA_USE_H_ + +#include "base/macros.h" +#include "chrome/common/page_load_metrics/page_load_metrics.mojom.h" + +namespace network { +struct ResourceResponseHead; +struct URLLoaderCompletionStatus; +} // namespace network + +namespace page_load_metrics { + +// PageResourceDataUse contains the data use information of one resource. Data +// use is updated when resource size updates are called. +class PageResourceDataUse { + public: + PageResourceDataUse(); + ~PageResourceDataUse(); + + void DidStartResponse(int resource_id, + const network::ResourceResponseHead& response_head); + + // Updates any additional bytes of data use to |delta_data_use|. + void DidReceiveTransferSizeUpdate(int received_data_length, + mojom::PageLoadDataUse* delta_data_use); + + // Updates additional bytes to |delta_data_use| and returns whether it was + // updated. + bool DidCompleteResponse(const network::URLLoaderCompletionStatus& status, + mojom::PageLoadDataUse* delta_data_use); + + int resource_id() const { return resource_id_; } + + private: + int resource_id_; + + // Compression ratio estimated from the response headers if data saver was + // used. + double data_reduction_proxy_compression_ratio_estimate_; + + uint64_t total_received_bytes_; + + DISALLOW_ASSIGN(PageResourceDataUse); +}; + +} // namespace page_load_metrics + +#endif // CHROME_RENDERER_PAGE_LOAD_METRICS_PAGE_RESOURCE_DATA_USE_H_
diff --git a/chrome/renderer/page_load_metrics/page_timing_metrics_sender.cc b/chrome/renderer/page_load_metrics/page_timing_metrics_sender.cc index d283c75f..f2dd9ec 100644 --- a/chrome/renderer/page_load_metrics/page_timing_metrics_sender.cc +++ b/chrome/renderer/page_load_metrics/page_timing_metrics_sender.cc
@@ -9,10 +9,13 @@ #include "base/callback.h" #include "base/feature_list.h" #include "base/metrics/field_trial_params.h" +#include "base/stl_util.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "chrome/common/page_load_metrics/page_load_metrics_constants.h" #include "chrome/renderer/page_load_metrics/page_timing_sender.h" +#include "services/network/public/cpp/resource_response.h" +#include "services/network/public/cpp/url_loader_completion_status.h" namespace page_load_metrics { @@ -25,13 +28,20 @@ PageTimingMetricsSender::PageTimingMetricsSender( std::unique_ptr<PageTimingSender> sender, std::unique_ptr<base::OneShotTimer> timer, - mojom::PageLoadTimingPtr initial_timing) + mojom::PageLoadTimingPtr initial_timing, + std::unique_ptr<PageResourceDataUse> initial_request, + mojom::PageLoadDataUsePtr initial_data_use) : sender_(std::move(sender)), timer_(std::move(timer)), last_timing_(std::move(initial_timing)), metadata_(mojom::PageLoadMetadata::New()), new_features_(mojom::PageLoadFeatures::New()), + new_data_use_(std::move(initial_data_use)), buffer_timer_delay_ms_(kBufferTimerDelayMillis) { + page_resource_data_use_.emplace( + std::piecewise_construct, + std::forward_as_tuple(initial_request->resource_id()), + std::forward_as_tuple(*initial_request)); buffer_timer_delay_ms_ = base::GetFieldTrialParamByFeatureAsInt( kPageLoadMetricsTimerDelayFeature, "BufferTimerDelayMillis", kBufferTimerDelayMillis /* default value */); @@ -80,6 +90,56 @@ } } +void PageTimingMetricsSender::DidStartResponse( + int resource_id, + const network::ResourceResponseHead& response_head) { + DCHECK(!base::ContainsKey(page_resource_data_use_, resource_id)); + + auto resource_it = page_resource_data_use_.emplace( + std::piecewise_construct, std::forward_as_tuple(resource_id), + std::forward_as_tuple()); + resource_it.first->second.DidStartResponse(resource_id, response_head); +} + +void PageTimingMetricsSender::DidReceiveTransferSizeUpdate( + int resource_id, + int received_data_length) { + // Transfer size updates are called in a throttled manner. + const auto& resource_it = page_resource_data_use_.find(resource_id); + + // It is possible that resources are not in the map, if response headers were + // not received or for failed/cancelled resources. + if (resource_it == page_resource_data_use_.end()) + return; + + resource_it->second.DidReceiveTransferSizeUpdate(received_data_length, + new_data_use_.get()); + EnsureSendTimer(); +} + +void PageTimingMetricsSender::DidCompleteResponse( + int resource_id, + const network::URLLoaderCompletionStatus& status) { + auto resource_it = page_resource_data_use_.find(resource_id); + + // It is possible that resources are not in the map, if response headers were + // not received or for failed/cancelled resources. For data reduction proxy + // purposes treat these as having no savings. + if (resource_it == page_resource_data_use_.end()) { + auto new_resource_it = page_resource_data_use_.emplace( + std::piecewise_construct, std::forward_as_tuple(resource_id), + std::forward_as_tuple()); + resource_it = new_resource_it.first; + } + + if (resource_it->second.DidCompleteResponse(status, new_data_use_.get())) + EnsureSendTimer(); +} + +void PageTimingMetricsSender::DidCancelResponse(int resource_id) { + page_resource_data_use_.erase(resource_id); +} + void PageTimingMetricsSender::Send(mojom::PageLoadTimingPtr timing) { if (last_timing_->Equals(*timing)) return; @@ -110,8 +170,10 @@ void PageTimingMetricsSender::SendNow() { have_sent_ipc_ = true; - sender_->SendTiming(last_timing_, metadata_, std::move(new_features_)); + sender_->SendTiming(last_timing_, metadata_, std::move(new_features_), + std::move(new_data_use_)); new_features_ = mojom::PageLoadFeatures::New(); + new_data_use_ = mojom::PageLoadDataUse::New(); } } // namespace page_load_metrics
diff --git a/chrome/renderer/page_load_metrics/page_timing_metrics_sender.h b/chrome/renderer/page_load_metrics/page_timing_metrics_sender.h index 316ede2..15529ed1 100644 --- a/chrome/renderer/page_load_metrics/page_timing_metrics_sender.h +++ b/chrome/renderer/page_load_metrics/page_timing_metrics_sender.h
@@ -8,8 +8,10 @@ #include <bitset> #include <memory> +#include "base/containers/small_map.h" #include "base/macros.h" #include "chrome/common/page_load_metrics/page_load_timing.h" +#include "chrome/renderer/page_load_metrics/page_resource_data_use.h" #include "third_party/blink/public/mojom/use_counter/css_property_id.mojom.h" #include "third_party/blink/public/platform/web_feature.mojom-shared.h" #include "third_party/blink/public/platform/web_loading_behavior_flag.h" @@ -18,6 +20,11 @@ class OneShotTimer; } // namespace base +namespace network { +struct ResourceResponseHead; +struct URLLoaderCompletionStatus; +} // namespace network + namespace page_load_metrics { class PageTimingSender; @@ -29,12 +36,21 @@ public: PageTimingMetricsSender(std::unique_ptr<PageTimingSender> sender, std::unique_ptr<base::OneShotTimer> timer, - mojom::PageLoadTimingPtr initial_timing); + mojom::PageLoadTimingPtr initial_timing, + std::unique_ptr<PageResourceDataUse> initial_request, + mojom::PageLoadDataUsePtr initial_data_use); ~PageTimingMetricsSender(); void DidObserveLoadingBehavior(blink::WebLoadingBehaviorFlag behavior); void DidObserveNewFeatureUsage(blink::mojom::WebFeature feature); void DidObserveNewCssPropertyUsage(int css_property, bool is_animated); + void DidStartResponse(int resource_id, + const network::ResourceResponseHead& response_head); + void DidReceiveTransferSizeUpdate(int resource_id, int received_data_length); + void DidCompleteResponse(int resource_id, + const network::URLLoaderCompletionStatus& status); + void DidCancelResponse(int resource_id); + void Send(mojom::PageLoadTimingPtr timing); protected: @@ -55,6 +71,9 @@ // A list of newly observed features during page load, to be sent to the // browser. mojom::PageLoadFeaturesPtr new_features_; + // Additional data use observed during the page load. + mojom::PageLoadDataUsePtr new_data_use_; + std::bitset<static_cast<size_t>(blink::mojom::WebFeature::kNumberOfFeatures)> features_sent_; std::bitset<static_cast<size_t>(blink::mojom::kMaximumCSSSampleId + 1)> @@ -64,6 +83,9 @@ bool have_sent_ipc_ = false; + base::small_map<std::map<int, PageResourceDataUse>, 16> + page_resource_data_use_; + // Field trial for alternating page timing metrics sender buffer timer delay. // https://crbug.com/847269. int buffer_timer_delay_ms_;
diff --git a/chrome/renderer/page_load_metrics/page_timing_metrics_sender_unittest.cc b/chrome/renderer/page_load_metrics/page_timing_metrics_sender_unittest.cc index 710dbf8d..4e9f5dd 100644 --- a/chrome/renderer/page_load_metrics/page_timing_metrics_sender_unittest.cc +++ b/chrome/renderer/page_load_metrics/page_timing_metrics_sender_unittest.cc
@@ -21,7 +21,9 @@ mojom::PageLoadTimingPtr initial_timing) : PageTimingMetricsSender(std::move(page_timing_sender), std::make_unique<base::MockOneShotTimer>(), - std::move(initial_timing)) {} + std::move(initial_timing), + std::make_unique<PageResourceDataUse>(), + mojom::PageLoadDataUse::New()) {} base::MockOneShotTimer* mock_timer() const { return static_cast<base::MockOneShotTimer*>(timer());
diff --git a/chrome/renderer/page_load_metrics/page_timing_sender.h b/chrome/renderer/page_load_metrics/page_timing_sender.h index d858e02..b0e59214 100644 --- a/chrome/renderer/page_load_metrics/page_timing_sender.h +++ b/chrome/renderer/page_load_metrics/page_timing_sender.h
@@ -16,7 +16,8 @@ virtual ~PageTimingSender() {} virtual void SendTiming(const mojom::PageLoadTimingPtr& timing, const mojom::PageLoadMetadataPtr& metadata, - mojom::PageLoadFeaturesPtr new_features) = 0; + mojom::PageLoadFeaturesPtr new_features, + mojom::PageLoadDataUsePtr new_data_use) = 0; }; } // namespace page_load_metrics
diff --git a/chrome/services/file_util/public/mojom/safe_archive_analyzer.typemap b/chrome/services/file_util/public/mojom/safe_archive_analyzer.typemap index d453e3f7..3f1c04e 100644 --- a/chrome/services/file_util/public/mojom/safe_archive_analyzer.typemap +++ b/chrome/services/file_util/public/mojom/safe_archive_analyzer.typemap
@@ -8,7 +8,7 @@ traits_headers = [ "//chrome/services/file_util/public/mojom/safe_archive_analyzer_param_traits.h" ] -deps = [ +public_deps = [ "//chrome/common/safe_browsing:proto", "//components/safe_browsing:csd_proto", ]
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index c2354302..c7f5a11 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -684,6 +684,7 @@ "../browser/prerender/prerender_test_utils.h", "../browser/previews/previews_browsertest.cc", "../browser/previews/previews_service_browser_test.cc", + "../browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc", "../browser/process_singleton_browsertest.cc", "../browser/profile_resetter/profile_resetter_browsertest.cc", "../browser/profiles/host_zoom_map_browsertest.cc", @@ -2165,7 +2166,6 @@ "//tools/swarming_client/", ] - if (enable_mus) { deps += [ "//chrome:chrome_test" ] data_deps = [ @@ -3633,9 +3633,6 @@ "../browser/sync_file_system/sync_file_system_test_util.h", "../browser/sync_file_system/sync_process_runner_unittest.cc", "../browser/sync_file_system/syncable_file_system_util_unittest.cc", - "../browser/web_applications/policy/web_app_policy_manager_unittest.cc", - "../browser/web_applications/web_app_mac_unittest.mm", - "../browser/web_applications/web_app_unittest.cc", "../common/extensions/api/commands/commands_manifest_unittest.cc", "../common/extensions/api/common_extension_api_unittest.cc", "../common/extensions/api/extension_action/browser_action_manifest_unittest.cc", @@ -3703,6 +3700,7 @@ "../utility/image_writer/image_writer_unittest.cc", ] deps += [ + "//chrome/browser/web_applications:unit_tests", "//chrome/common/extensions/api", "//extensions:extensions_resources", "//extensions/browser:test_support",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn index 23a55479..b8fdd527 100644 --- a/chrome/test/android/BUILD.gn +++ b/chrome/test/android/BUILD.gn
@@ -74,6 +74,7 @@ "//chrome/android:chrome_java", "//chrome/android/third_party/compositor_animator:compositor_animator_java", "//components/bookmarks/common/android:bookmarks_java", + "//components/embedder_support/android:web_contents_delegate_java", "//components/invalidation/impl:java", "//components/location/android:location_java", "//components/policy/android:policy_java", @@ -81,7 +82,6 @@ "//components/signin/core/browser/android:java", "//components/signin/core/browser/android:signin_java_test_support", "//components/sync/android:sync_java", - "//components/web_contents_delegate_android:web_contents_delegate_android_java", "//content/public/android:content_java", "//content/public/test/android:content_java_test_support", "//net/android:net_java",
diff --git a/chrome/test/data/extensions/api_test/chromeos_info_private/extended/background.js b/chrome/test/data/extensions/api_test/chromeos_info_private/extended/background.js index 28951e4..50b4d40 100644 --- a/chrome/test/data/extensions/api_test/chromeos_info_private/extended/background.js +++ b/chrome/test/data/extensions/api_test/chromeos_info_private/extended/background.js
@@ -13,7 +13,8 @@ 'sessionType', 'playStoreStatus', 'managedDeviceStatus', - 'deviceType' + 'deviceType', + 'stylusStatus', ], chrome.test.callbackPass(function(values) { switch (testName) { case 'kiosk': @@ -45,6 +46,13 @@ break; case 'unknown device type': chrome.test.assertEq('chromedevice', values['deviceType']); + break; + case 'stylus unsupported': + chrome.test.assertEq('unsupported', values['stylusStatus']); + break; + case 'stylus supported': + chrome.test.assertEq('supported', values['stylusStatus']); + break; } })); });
diff --git a/chrome/test/data/extensions/platform_apps/launch_file/test.js b/chrome/test/data/extensions/platform_apps/launch_file/test.js index 90eb6de..0ca65bb 100644 --- a/chrome/test/data/extensions/platform_apps/launch_file/test.js +++ b/chrome/test/data/extensions/platform_apps/launch_file/test.js
@@ -3,11 +3,13 @@ // found in the LICENSE file. chrome.app.runtime.onLaunched.addListener(function (launchData) { - // Test that the isKioskSession field and isPublicSession are |false| and the - // id and items fields can be read in the launch data. + // Test that the session-specific fields are |false| and the id and items + // fields can be read in the launch data. chrome.test.runTests([ function testFileHandler() { chrome.test.assertFalse(!launchData, "No launchData"); + chrome.test.assertFalse(launchData.isDemoSession, + "launchData.isDemoSession incorrect"); chrome.test.assertFalse(launchData.isKioskSession, "launchData.isKioskSession incorrect"); chrome.test.assertFalse(launchData.isPublicSession,
diff --git a/chrome/test/data/extensions/platform_apps/launch_whitelisted_ext_with_file/test.js b/chrome/test/data/extensions/platform_apps/launch_whitelisted_ext_with_file/test.js index 45d7955f..c163b5d4 100644 --- a/chrome/test/data/extensions/platform_apps/launch_whitelisted_ext_with_file/test.js +++ b/chrome/test/data/extensions/platform_apps/launch_whitelisted_ext_with_file/test.js
@@ -3,8 +3,8 @@ // found in the LICENSE file. chrome.app.runtime.onLaunched.addListener(function (launchData) { - // Test that the isKioskSession field and isPublicSession fields are |false| - // and the id and items fields can be read in the launch data. + // Test that the session-specific fields are |false| and the id and items + // fields can be read in the launch data. chrome.test.runTests([ function checkNoChromeApp() { chrome.test.assertEq(undefined, chrome.app.getIsInstalled); @@ -13,6 +13,8 @@ function testFileHandler() { chrome.test.assertFalse(!launchData, "No launchData"); + chrome.test.assertFalse(launchData.isDemoSession, + "launchData.isDemoSession incorrect"); chrome.test.assertFalse(launchData.isKioskSession, "launchData.isKioskSession incorrect"); chrome.test.assertFalse(launchData.isPublicSession,
diff --git a/chrome/test/data/previews/resource_loading_hints.html b/chrome/test/data/previews/resource_loading_hints.html new file mode 100644 index 0000000..e7dc052 --- /dev/null +++ b/chrome/test/data/previews/resource_loading_hints.html
@@ -0,0 +1,14 @@ +<html> + <head> + <meta name="viewport" content="width=device-width" /> + <noscript> + <title>Page with Script Disabled</title> + <link rel="stylesheet" href="noscript_test.css"> + </noscript> + <script>document.title='Page with Script Enabled and Executed';</script> + </head> + <body> + <p>Test page for NoScript Previews.</p> + <script src="noscript_test.js"></script> + </body> +</html>
diff --git a/chrome/test/data/previews/resource_loading_hints_with_no_transform_header.html b/chrome/test/data/previews/resource_loading_hints_with_no_transform_header.html new file mode 100644 index 0000000..e7dc052 --- /dev/null +++ b/chrome/test/data/previews/resource_loading_hints_with_no_transform_header.html
@@ -0,0 +1,14 @@ +<html> + <head> + <meta name="viewport" content="width=device-width" /> + <noscript> + <title>Page with Script Disabled</title> + <link rel="stylesheet" href="noscript_test.css"> + </noscript> + <script>document.title='Page with Script Enabled and Executed';</script> + </head> + <body> + <p>Test page for NoScript Previews.</p> + <script src="noscript_test.js"></script> + </body> +</html>
diff --git a/chrome/test/data/previews/resource_loading_hints_with_no_transform_header.html.mock-http-headers b/chrome/test/data/previews/resource_loading_hints_with_no_transform_header.html.mock-http-headers new file mode 100644 index 0000000..fd4507e5f --- /dev/null +++ b/chrome/test/data/previews/resource_loading_hints_with_no_transform_header.html.mock-http-headers
@@ -0,0 +1,2 @@ +HTTP/1.1 200 OK +Cache-Control: no-transform
diff --git a/chrome/test/data/vr/OWNERS b/chrome/test/data/vr/OWNERS new file mode 100644 index 0000000..b2cefae --- /dev/null +++ b/chrome/test/data/vr/OWNERS
@@ -0,0 +1,4 @@ +bsheedy@chromium.org + +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR
diff --git a/chrome/test/data/webui/extensions/extension_error_page_test.js b/chrome/test/data/webui/extensions/extension_error_page_test.js index 09b71adc..7f1eaef 100644 --- a/chrome/test/data/webui/extensions/extension_error_page_test.js +++ b/chrome/test/data/webui/extensions/extension_error_page_test.js
@@ -97,7 +97,7 @@ let error = errorElements[0]; expectEquals( 'message', error.querySelector('.error-message').textContent.trim()); - expectTrue(error.querySelector('iron-icon').icon == 'error'); + expectTrue(error.querySelector('iron-icon').icon == 'cr:error'); const manifestError = Object.assign( { @@ -115,7 +115,7 @@ expectEquals( 'invalid key', error.querySelector('.error-message').textContent.trim()); - expectTrue(error.querySelector('iron-icon').icon == 'warning'); + expectTrue(error.querySelector('iron-icon').icon == 'cr:warning'); mockDelegate.testClickingCalls( error.querySelector('.icon-delete-gray button'), 'deleteErrors',
diff --git a/chrome/test/data/webui/extensions/extension_item_test.js b/chrome/test/data/webui/extensions/extension_item_test.js index 42f0f5f..fa27d23 100644 --- a/chrome/test/data/webui/extensions/extension_item_test.js +++ b/chrome/test/data/webui/extensions/extension_item_test.js
@@ -288,20 +288,20 @@ item.set('data.location', 'THIRD_PARTY'); Polymer.dom.flush(); expectTrue(extension_test_util.isVisible(item, '#source-indicator')); - expectEquals('input', icon.icon); + expectEquals('extensions-icons:input', icon.icon); extension_test_util.testIcons(item); item.set('data.location', 'UNKNOWN'); Polymer.dom.flush(); expectTrue(extension_test_util.isVisible(item, '#source-indicator')); - expectEquals('input', icon.icon); + expectEquals('extensions-icons:input', icon.icon); extension_test_util.testIcons(item); item.set('data.location', 'FROM_STORE'); item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'}); Polymer.dom.flush(); expectTrue(extension_test_util.isVisible(item, '#source-indicator')); - expectEquals('communication:business', icon.icon); + expectEquals('extensions-icons:business', icon.icon); extension_test_util.testIcons(item); item.set('data.controlledInfo', null);
diff --git a/chrome/test/data/webui/settings/about_page_tests.js b/chrome/test/data/webui/settings/about_page_tests.js index acfefa1c..b59e933 100644 --- a/chrome/test/data/webui/settings/about_page_tests.js +++ b/chrome/test/data/webui/settings/about_page_tests.js
@@ -287,7 +287,7 @@ fireStatusChanged(UpdateStatus.FAILED); assertEquals(null, icon.src); - assertEquals('settings:error', icon.icon); + assertEquals('cr:error', icon.icon); assertEquals(0, statusMessageEl.textContent.trim().length); fireStatusChanged(UpdateStatus.DISABLED); @@ -372,19 +372,19 @@ fireStatusChanged(UpdateStatus.CHECKING); assertEquals(null, icon.src); - assertEquals('settings:error', icon.icon); + assertEquals('cr:error', icon.icon); assertFalse(page.$.deprecationWarning.hidden); assertTrue(page.$.updateStatusMessage.hidden); fireStatusChanged(UpdateStatus.FAILED); assertEquals(null, icon.src); - assertEquals('settings:error', icon.icon); + assertEquals('cr:error', icon.icon); assertFalse(page.$.deprecationWarning.hidden); assertTrue(page.$.updateStatusMessage.hidden); fireStatusChanged(UpdateStatus.UPDATED); assertEquals(null, icon.src); - assertEquals('settings:error', icon.icon); + assertEquals('cr:error', icon.icon); assertFalse(page.$.deprecationWarning.hidden); assertTrue(page.$.updateStatusMessage.hidden); });
diff --git a/chrome/test/data/webui/settings/chrome_cleanup_page_test.js b/chrome/test/data/webui/settings/chrome_cleanup_page_test.js index 3927bcb..0393044 100644 --- a/chrome/test/data/webui/settings/chrome_cleanup_page_test.js +++ b/chrome/test/data/webui/settings/chrome_cleanup_page_test.js
@@ -78,10 +78,23 @@ const exactSizeRegistryKeysList = ['key 1', 'key 2', 'key 3', 'key 4']; const longRegistryKeysList = ['key 1', 'key 2', 'key 3', 'key 4', 'key 5', 'key 6']; +const shortExtensionList = ['ext 1', 'ext 2']; +const exactSizeExtensionList = ['ext 1', 'ext 2', 'ext 3', 'ext 4']; +const longExtensionList = + ['ext 1', 'ext 2', 'ext 3', 'ext 4', 'ext 5', 'ext 6']; + +const fileLists = [[], shortFileList, exactSizeFileList, longFileList]; +const registryKeysLists = [ + [], shortRegistryKeysList, exactSizeRegistryKeysList, longRegistryKeysList +]; +const extensionLists = + [[], shortExtensionList, exactSizeExtensionList, longExtensionList]; +const descriptors = ['No', 'Few', 'ExactSize', 'Many']; const defaultScannerResults = { 'files': shortFileList, 'registryKeys': shortRegistryKeysList, + 'extensions': shortExtensionList, }; /** @@ -113,11 +126,16 @@ } /** - * @param {!Array} files The list of files to be cleaned - * @param {!Array} registryKeys The list of registry entires to be cleaned. + * @param {!Array} files The list of files to be cleaned. + * @param {!Array} registryKeys The list of registry entries to be cleaned. + * @param {!Array} extensions The list of extensions to be cleaned. */ -function startCleanupFromInfected(files, registryKeys) { - const scannerResults = {'files': files, 'registryKeys': registryKeys}; +function startCleanupFromInfected(files, registryKeys, extensions) { + const scannerResults = { + 'files': files, + 'registryKeys': registryKeys, + 'extensions': extensions + }; cr.webUIListenerCallback('chrome-cleanup-upload-permission-change', false); cr.webUIListenerCallback( @@ -143,6 +161,16 @@ assertTrue(registryKeysListContainer.hidden); } + const extensionsListContainer = chromeCleanupPage.$$('#extensions-list'); + assertTrue(!!extensionsListContainer); + if (extensions.length > 0) { + assertFalse(extensionsListContainer.hidden); + assertTrue(!!extensionsListContainer); + validateVisibleItemsList(extensions, extensionsListContainer); + } else { + assertTrue(extensionsListContainer.hidden); + } + const actionButton = chromeCleanupPage.$$('#action-button'); assertTrue(!!actionButton); actionButton.click(); @@ -353,56 +381,26 @@ assertFalse(!!actionButton); }); - test('startCleanupFromInfected_FewFilesNoRegistryKeys', function() { - return startCleanupFromInfected(shortFileList, []); - }); + // Test all combinations of item list sizes. + for (let file_index = 0; file_index < fileLists.length; file_index++) { + for (let registry_index = 0; registry_index < registryKeysLists.length; + registry_index++) { + for (let extension_index = 0; extension_index < extensionLists.length; + extension_index++) { + const testName = 'startCleanupFromInfected_' + descriptors[file_index] + + 'Files' + descriptors[registry_index] + 'RegistryKeys' + + descriptors[extension_index] + 'Extensions'; + const fileList = fileLists[file_index]; + const registryKeysList = registryKeysLists[registry_index]; + const extensionList = extensionLists[extension_index]; - test('startCleanupFromInfected_FewFilesFewRegistryKeys', function() { - return startCleanupFromInfected(shortFileList, shortRegistryKeysList); - }); - - test('startCleanupFromInfected_FewFilesExactSizeRegistryKeys', function() { - return startCleanupFromInfected(shortFileList, exactSizeRegistryKeysList); - }); - - test('startCleanupFromInfected_FewFilesManyRegistryKeys', function() { - return startCleanupFromInfected(shortFileList, longRegistryKeysList); - }); - - test('startCleanupFromInfected_ExactSizeFilesNoRegistryKeys', function() { - return startCleanupFromInfected(exactSizeFileList, []); - }); - - test('startCleanupFromInfected_ExactSizeFilesFewRegistryKeys', function() { - return startCleanupFromInfected(exactSizeFileList, shortRegistryKeysList); - }); - - test( - 'startCleanupFromInfected_ExactSizeFilesExactSizeRegistryKeys', - function() { - return startCleanupFromInfected( - exactSizeFileList, exactSizeRegistryKeysList); - }); - - test('startCleanupFromInfected_ExactSizeFilesManyRegistryKeys', function() { - return startCleanupFromInfected(exactSizeFileList, longRegistryKeysList); - }); - - test('startCleanupFromInfected_ManyFilesNoRegistryKeys', function() { - return startCleanupFromInfected(longFileList, []); - }); - - test('startCleanupFromInfected_ManyFilesFewRegistryKeys', function() { - return startCleanupFromInfected(longFileList, shortRegistryKeysList); - }); - - test('startCleanupFromInfected_ManyFilesExactSizeRegistryKeys', function() { - return startCleanupFromInfected(longFileList, exactSizeRegistryKeysList); - }); - - test('startCleanupFromInfected_ManyFilesManyRegistryKeys', function() { - return startCleanupFromInfected(longFileList, longRegistryKeysList); - }); + test(testName, function() { + return startCleanupFromInfected( + fileList, registryKeysList, extensionList); + }); + } + } + } test('rebootFromRebootRequired', function() { cr.webUIListenerCallback('chrome-cleanup-on-reboot-required');
diff --git a/chrome/test/vr/OWNERS b/chrome/test/vr/OWNERS index 7e64ddb..56462b4 100644 --- a/chrome/test/vr/OWNERS +++ b/chrome/test/vr/OWNERS
@@ -2,4 +2,5 @@ cjgrant@chromium.org mthiesse@chromium.org -# COMPONENT: Internals>VR +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR>VR
diff --git a/chromecast/browser/extensions/cast_extensions_browser_client.cc b/chromecast/browser/extensions/cast_extensions_browser_client.cc index 8b1a02d1..71be0cb5 100644 --- a/chromecast/browser/extensions/cast_extensions_browser_client.cc +++ b/chromecast/browser/extensions/cast_extensions_browser_client.cc
@@ -172,10 +172,18 @@ void CastExtensionsBrowserClient::PermitExternalProtocolHandler() {} +bool CastExtensionsBrowserClient::IsInDemoMode() { + return false; +} + bool CastExtensionsBrowserClient::IsRunningInForcedAppMode() { return false; } +bool CastExtensionsBrowserClient::IsAppModeForcedForApp(const ExtensionId& id) { + return false; +} + bool CastExtensionsBrowserClient::IsLoggedInAsPublicAccount() { return false; } @@ -279,8 +287,4 @@ return "en-US"; } -bool CastExtensionsBrowserClient::IsAppModeForcedForApp(const ExtensionId& id) { - return false; -} - } // namespace extensions
diff --git a/chromecast/browser/extensions/cast_extensions_browser_client.h b/chromecast/browser/extensions/cast_extensions_browser_client.h index 2044b5f..984abf0 100644 --- a/chromecast/browser/extensions/cast_extensions_browser_client.h +++ b/chromecast/browser/extensions/cast_extensions_browser_client.h
@@ -83,7 +83,9 @@ std::unique_ptr<ExtensionHostDelegate> CreateExtensionHostDelegate() override; bool DidVersionUpdate(content::BrowserContext* context) override; void PermitExternalProtocolHandler() override; + bool IsInDemoMode() override; bool IsRunningInForcedAppMode() override; + bool IsAppModeForcedForApp(const ExtensionId& id) override; bool IsLoggedInAsPublicAccount() override; ExtensionSystemProvider* GetExtensionSystemFactory() override; void RegisterExtensionFunctions( @@ -111,7 +113,6 @@ KioskDelegate* GetKioskDelegate() override; bool IsLockScreenContext(content::BrowserContext* context) override; std::string GetApplicationLocale() override; - bool IsAppModeForcedForApp(const ExtensionId& id) override; // Sets the API client. void SetAPIClientForTest(ExtensionsAPIClient* api_client);
diff --git a/chromecast/device/bluetooth/le/gatt_client_manager_impl.cc b/chromecast/device/bluetooth/le/gatt_client_manager_impl.cc index 78ca0b77..8508594 100644 --- a/chromecast/device/bluetooth/le/gatt_client_manager_impl.cc +++ b/chromecast/device/bluetooth/le/gatt_client_manager_impl.cc
@@ -117,7 +117,11 @@ bool connected) { MAKE_SURE_IO_THREAD(OnConnectChanged, addr, status, connected); auto it = addr_to_device_.find(addr); - CHECK_DEVICE_EXISTS_IT(it); + + // Silently ignore devices we aren't keeping track of. + if (it == addr_to_device_.end()) { + return; + } it->second->SetConnected(connected); if (connected) {
diff --git a/chromeos/chromeos_features.cc b/chromeos/chromeos_features.cc index 7e58282..c4a0d5b 100644 --- a/chromeos/chromeos_features.cc +++ b/chromeos/chromeos_features.cc
@@ -12,6 +12,10 @@ const base::Feature kAndroidMessagesIntegration{ "AndroidMessagesIntegration", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables or disables native ChromeVox support for Arc. +const base::Feature kChromeVoxArcSupport{"ChromeVoxArcSupport", + base::FEATURE_DISABLED_BY_DEFAULT}; + // If enabled, DriveFS will be used for Drive sync. const base::Feature kDriveFs{"DriveFS", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromeos/chromeos_features.h b/chromeos/chromeos_features.h index f594ce4..743cc1f 100644 --- a/chromeos/chromeos_features.h +++ b/chromeos/chromeos_features.h
@@ -16,6 +16,7 @@ // alongside the definition of their values in the .cc file. CHROMEOS_EXPORT extern const base::Feature kAndroidMessagesIntegration; +CHROMEOS_EXPORT extern const base::Feature kChromeVoxArcSupport; CHROMEOS_EXPORT extern const base::Feature kDriveFs; CHROMEOS_EXPORT extern const base::Feature kEnableUnifiedMultiDeviceSettings; CHROMEOS_EXPORT extern const base::Feature kEnableUnifiedMultiDeviceSetup;
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc index 23413ae..bbb98315 100644 --- a/chromeos/chromeos_switches.cc +++ b/chromeos/chromeos_switches.cc
@@ -313,9 +313,6 @@ // Enables the Cast Receiver. const char kEnableCastReceiver[] = "enable-cast-receiver"; -// Enables native ChromeVox support for Arc. -const char kEnableChromeVoxArcSupport[] = "enable-chromevox-arc-support"; - // Enables consumer kiosk mode for Chrome OS. const char kEnableConsumerKiosk[] = "enable-consumer-kiosk";
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h index 2e6c328b..f29ad3a 100644 --- a/chromeos/chromeos_switches.h +++ b/chromeos/chromeos_switches.h
@@ -92,7 +92,6 @@ CHROMEOS_EXPORT extern const char kEnableArcOobeOptinNoSkip[]; CHROMEOS_EXPORT extern const char kEnableCaptivePortalRandomUrl[]; CHROMEOS_EXPORT extern const char kEnableCastReceiver[]; -CHROMEOS_EXPORT extern const char kEnableChromeVoxArcSupport[]; CHROMEOS_EXPORT extern const char kEnableConsumerKiosk[]; CHROMEOS_EXPORT extern const char kEnableDataSaverPrompt[]; CHROMEOS_EXPORT extern const char kEnableDemoMode[];
diff --git a/chromeos/services/multidevice_setup/BUILD.gn b/chromeos/services/multidevice_setup/BUILD.gn index 03fc0fd..6b8a48d 100644 --- a/chromeos/services/multidevice_setup/BUILD.gn +++ b/chromeos/services/multidevice_setup/BUILD.gn
@@ -29,10 +29,6 @@ "host_verifier.h", "host_verifier_impl.cc", "host_verifier_impl.h", - "host_verifier_operation.cc", - "host_verifier_operation.h", - "host_verifier_operation_impl.cc", - "host_verifier_operation_impl.h", "multidevice_setup_base.cc", "multidevice_setup_base.h", "multidevice_setup_impl.cc", @@ -84,8 +80,6 @@ "fake_host_status_provider.h", "fake_host_verifier.cc", "fake_host_verifier.h", - "fake_host_verifier_operation.cc", - "fake_host_verifier_operation.h", "fake_setup_flow_completion_recorder.cc", "fake_setup_flow_completion_recorder.h", ] @@ -109,7 +103,6 @@ "host_backend_delegate_impl_unittest.cc", "host_status_provider_impl_unittest.cc", "host_verifier_impl_unittest.cc", - "host_verifier_operation_impl_unittest.cc", "multidevice_setup_impl_unittest.cc", "multidevice_setup_service_unittest.cc", "setup_flow_completion_recorder_impl_unittest.cc",
diff --git a/chromeos/services/multidevice_setup/fake_host_verifier_operation.cc b/chromeos/services/multidevice_setup/fake_host_verifier_operation.cc deleted file mode 100644 index 2116708d..0000000 --- a/chromeos/services/multidevice_setup/fake_host_verifier_operation.cc +++ /dev/null
@@ -1,32 +0,0 @@ -// 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. - -#include "chromeos/services/multidevice_setup/fake_host_verifier_operation.h" - -namespace chromeos { - -namespace multidevice_setup { - -FakeHostVerifierOperation::FakeHostVerifierOperation(Delegate* delegate) - : HostVerifierOperation(delegate) {} - -FakeHostVerifierOperation::~FakeHostVerifierOperation() = default; - -void FakeHostVerifierOperation::PerformCancelOperation() {} - -FakeHostVerifierOperationDelegate::FakeHostVerifierOperationDelegate() = - default; - -FakeHostVerifierOperationDelegate::~FakeHostVerifierOperationDelegate() = - default; - -void FakeHostVerifierOperationDelegate::OnOperationFinished( - HostVerifierOperation::Result result) { - DCHECK(!result_); - result_ = result; -} - -} // namespace multidevice_setup - -} // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/fake_host_verifier_operation.h b/chromeos/services/multidevice_setup/fake_host_verifier_operation.h deleted file mode 100644 index af81906..0000000 --- a/chromeos/services/multidevice_setup/fake_host_verifier_operation.h +++ /dev/null
@@ -1,55 +0,0 @@ -// 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. - -#ifndef CHROMEOS_SERVICES_MULTIDEVICE_SETUP_FAKE_HOST_VERIFIER_OPERATION_H_ -#define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_FAKE_HOST_VERIFIER_OPERATION_H_ - -#include "base/macros.h" -#include "base/optional.h" -#include "chromeos/services/multidevice_setup/host_verifier_operation.h" - -namespace chromeos { - -namespace multidevice_setup { - -// Test HostVerifierOperation implementation. -class FakeHostVerifierOperation : public HostVerifierOperation { - public: - FakeHostVerifierOperation(Delegate* delegate); - ~FakeHostVerifierOperation() override; - - using HostVerifierOperation::NotifyOperationFinished; - - private: - // HostVerifierOperation: - void PerformCancelOperation() override; - - DISALLOW_COPY_AND_ASSIGN(FakeHostVerifierOperation); -}; - -// Test HostVerifierOperation::Delegate implementation. -class FakeHostVerifierOperationDelegate - : public HostVerifierOperation::Delegate { - public: - FakeHostVerifierOperationDelegate(); - ~FakeHostVerifierOperationDelegate() override; - - const base::Optional<HostVerifierOperation::Result>& result() const { - return result_; - } - - private: - // HostVerifierOperation::Delegate: - void OnOperationFinished(HostVerifierOperation::Result result) override; - - base::Optional<HostVerifierOperation::Result> result_; - - DISALLOW_COPY_AND_ASSIGN(FakeHostVerifierOperationDelegate); -}; - -} // namespace multidevice_setup - -} // namespace chromeos - -#endif // CHROMEOS_SERVICES_MULTIDEVICE_SETUP_FAKE_HOST_VERIFIER_OPERATION_H_
diff --git a/chromeos/services/multidevice_setup/host_verifier_operation.cc b/chromeos/services/multidevice_setup/host_verifier_operation.cc deleted file mode 100644 index eaaa7b7..0000000 --- a/chromeos/services/multidevice_setup/host_verifier_operation.cc +++ /dev/null
@@ -1,84 +0,0 @@ -// 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. - -#include "chromeos/services/multidevice_setup/host_verifier_operation.h" - -#include "chromeos/components/proximity_auth/logging/logging.h" - -namespace chromeos { - -namespace multidevice_setup { - -HostVerifierOperation::HostVerifierOperation(Delegate* delegate) - : delegate_(delegate) {} - -HostVerifierOperation::~HostVerifierOperation() = default; - -void HostVerifierOperation::CancelOperation() { - if (result_) { - PA_LOG(ERROR) << "HostVerifierOperation::CancelOperation(): Tried to " - << "cancel operation, but it was already finished. Result: " - << *result_; - NOTREACHED(); - } - - PerformCancelOperation(); - NotifyOperationFinished(Result::kCanceled); -} - -void HostVerifierOperation::NotifyOperationFinished(Result result) { - if (result_) { - PA_LOG(ERROR) << "HostVerifierOperation::NotifyOperationFinished(): Tried " - << "to finish operation, but it was already finished. " - << "Result: " << *result_; - } - result_ = result; - - delegate_->OnOperationFinished(*result_); -} - -std::ostream& operator<<(std::ostream& stream, - const HostVerifierOperation::Result& result) { - switch (result) { - case HostVerifierOperation::Result::kTimeoutFindingEligibleDevices: - stream << "[timeout calling FindEligibleDevices()]"; - break; - case HostVerifierOperation::Result::kErrorCallingFindEligibleDevices: - stream << "[error calling FindEligibleDevices()]"; - break; - case HostVerifierOperation::Result::kDeviceToVerifyIsNotEligible: - stream << "[device to verify was not included in FindEligibleDevices() " - << "response];"; - break; - case HostVerifierOperation::Result::kTimeoutFindingConnection: - stream << "[timeout finding connection]"; - break; - case HostVerifierOperation::Result::kConnectionAttemptFailed: - stream << "[connection attempt failed]"; - break; - case HostVerifierOperation::Result::kConnectionDisconnectedUnexpectedly: - stream << "[connection disconnected unexpectedly]"; - break; - case HostVerifierOperation::Result::kTimeoutReceivingResponse: - stream << "[timeout receiving EnableBetterTogetherResponse]"; - break; - case HostVerifierOperation::Result::kReceivedInvalidResponse: - stream << "[received invalid EnableBetterTogetherResponse message]"; - break; - case HostVerifierOperation::Result::kReceivedErrorResponse: - stream << "[received EnableBetterTogetherResponse with error]"; - break; - case HostVerifierOperation::Result::kCanceled: - stream << "[request canceled]"; - break; - case HostVerifierOperation::Result::kSuccess: - stream << "[success]"; - break; - } - return stream; -} - -} // namespace multidevice_setup - -} // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/host_verifier_operation.h b/chromeos/services/multidevice_setup/host_verifier_operation.h deleted file mode 100644 index ed0fbdf..0000000 --- a/chromeos/services/multidevice_setup/host_verifier_operation.h +++ /dev/null
@@ -1,79 +0,0 @@ -// 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. - -#ifndef CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_VERIFIER_OPERATION_H_ -#define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_VERIFIER_OPERATION_H_ - -#include <ostream> - -#include "base/macros.h" -#include "base/optional.h" - -namespace chromeos { - -namespace multidevice_setup { - -// Operation for completing the verification step for the current host device. -// A HostVerifierOperation instance is meant to be used for a single -// verification attempt; if verification needs to be retried, a new instance -// should be created for the next attempt. -class HostVerifierOperation { - public: - enum class Result { - kTimeoutFindingEligibleDevices, - kErrorCallingFindEligibleDevices, - kDeviceToVerifyIsNotEligible, - kTimeoutFindingConnection, - kConnectionAttemptFailed, - kConnectionDisconnectedUnexpectedly, - kTimeoutReceivingResponse, - kReceivedInvalidResponse, - kReceivedErrorResponse, - kCanceled, - kSuccess - }; - - class Delegate { - public: - virtual ~Delegate() = default; - virtual void OnOperationFinished(Result result) = 0; - }; - - virtual ~HostVerifierOperation(); - - // Cancels the operation, triggering a delegate callback with the kCanceled - // result. - // - // It is invalid to call this function after the operation has already - // completed. - void CancelOperation(); - - // Returns the result of the operation. If the operation has not yet finished, - // null is returned. - const base::Optional<Result>& result() const { return result_; } - - protected: - HostVerifierOperation(Delegate* delegate); - - // Derived types should use this function to cancel the operation, but they - // should not call NotifyOperationFinished() during cancellation. - virtual void PerformCancelOperation() = 0; - - void NotifyOperationFinished(Result result); - - private: - Delegate* delegate_; - base::Optional<Result> result_; - - DISALLOW_COPY_AND_ASSIGN(HostVerifierOperation); -}; - -std::ostream& operator<<(std::ostream& stream, - const HostVerifierOperation::Result& result); - -} // namespace multidevice_setup - -} // namespace chromeos - -#endif // CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_VERIFIER_OPERATION_H_
diff --git a/chromeos/services/multidevice_setup/host_verifier_operation_impl.cc b/chromeos/services/multidevice_setup/host_verifier_operation_impl.cc deleted file mode 100644 index 8a71466..0000000 --- a/chromeos/services/multidevice_setup/host_verifier_operation_impl.cc +++ /dev/null
@@ -1,333 +0,0 @@ -// 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. - -#include "chromeos/services/multidevice_setup/host_verifier_operation_impl.h" - -#include <sstream> - -#include "base/bind.h" -#include "base/memory/ptr_util.h" -#include "base/no_destructor.h" -#include "base/stl_util.h" -#include "base/time/time.h" -#include "chromeos/components/proximity_auth/logging/logging.h" -#include "chromeos/services/device_sync/public/cpp/device_sync_client.h" -#include "chromeos/services/secure_channel/public/cpp/client/secure_channel_client.h" - -namespace chromeos { - -namespace multidevice_setup { - -namespace { - -const char kFeature[] = "better_together_setup"; - -const int kNumMinutesForTimeout = 1; - -const char kEligibleDeviceIdsLogString[] = "Eligible device IDs"; -const char kIneligibleDeviceIdsLogString[] = "Ineligible device IDs"; - -void LogDeviceIds(const cryptauth::RemoteDeviceRefList& device_list, - const std::string& device_type_name, - std::stringstream* ss) { - *ss << device_type_name << ": ["; - if (!device_list.empty()) { - for (const auto& device : device_list) - *ss << "\"" << device.GetTruncatedDeviceIdForLogs() << "\", "; - ss->seekp(-2, ss->cur); // Remove last ", " from the stream. - } - *ss << "]"; -} - -std::string CreateLogString( - const cryptauth::RemoteDeviceRefList& eligible_devices, - const cryptauth::RemoteDeviceRefList& ineligible_devices) { - std::stringstream ss; - LogDeviceIds(eligible_devices, kEligibleDeviceIdsLogString, &ss); - ss << ", "; - LogDeviceIds(ineligible_devices, kIneligibleDeviceIdsLogString, &ss); - return ss.str(); -} - -base::Optional<EnableBetterTogetherResponse> DeserializePossibleResponse( - const std::string& payload) { - BetterTogetherSetupMessageWrapper wrapper; - - // If |payload| does not correspond to a BetterTogetherSetupMessageWrapper, - // return null. - if (!wrapper.ParseFromString(payload)) - return base::nullopt; - - // If |wrapper|'s type indicates that it does not contain a - // EnableBetterTogetherResponse, return null. - if (!wrapper.has_type() || - wrapper.type() != MessageType::ENABLE_BETTER_TOGETHER_RESPONSE) { - return base::nullopt; - } - - EnableBetterTogetherResponse response; - - // If |wrapper|'s payload does not represent an EnableBetterTogetherResponse, - // return null. - if (!wrapper.has_payload() || !response.ParseFromString(wrapper.payload())) - return base::nullopt; - - return response; -} - -} // namespace - -// static -HostVerifierOperationImpl::Factory* - HostVerifierOperationImpl::Factory::test_factory_ = nullptr; - -// static -HostVerifierOperationImpl::Factory* HostVerifierOperationImpl::Factory::Get() { - if (test_factory_) - return test_factory_; - - static base::NoDestructor<Factory> factory; - return factory.get(); -} - -// static -void HostVerifierOperationImpl::Factory::SetFactoryForTesting( - Factory* test_factory) { - test_factory_ = test_factory; -} - -HostVerifierOperationImpl::Factory::~Factory() = default; - -std::unique_ptr<HostVerifierOperation> -HostVerifierOperationImpl::Factory::BuildInstance( - HostVerifierOperation::Delegate* delegate, - cryptauth::RemoteDeviceRef device_to_connect, - cryptauth::RemoteDeviceRef local_device, - device_sync::DeviceSyncClient* device_sync_client, - secure_channel::SecureChannelClient* secure_channel_client, - std::unique_ptr<base::OneShotTimer> timer) { - return base::WrapUnique(new HostVerifierOperationImpl( - delegate, device_to_connect, local_device, device_sync_client, - secure_channel_client, std::move(timer))); -} - -// static -BetterTogetherSetupMessageWrapper -HostVerifierOperationImpl::CreateWrappedEnableBetterTogetherRequest() { - BetterTogetherSetupMessageWrapper wrapper; - wrapper.set_type(MessageType::ENABLE_BETTER_TOGETHER_REQUEST); - - EnableBetterTogetherRequest request; - wrapper.set_payload(request.SerializeAsString()); - - return wrapper; -} - -HostVerifierOperationImpl::HostVerifierOperationImpl( - HostVerifierOperation::Delegate* delegate, - cryptauth::RemoteDeviceRef device_to_connect, - cryptauth::RemoteDeviceRef local_device, - device_sync::DeviceSyncClient* device_sync_client, - secure_channel::SecureChannelClient* secure_channel_client, - std::unique_ptr<base::OneShotTimer> timer) - : HostVerifierOperation(delegate), - device_to_connect_(device_to_connect), - local_device_(local_device), - device_sync_client_(device_sync_client), - secure_channel_client_(secure_channel_client), - timer_(std::move(timer)), - weak_ptr_factory_(this) { - timer_->Start(FROM_HERE, base::TimeDelta::FromMinutes(kNumMinutesForTimeout), - base::Bind(&HostVerifierOperationImpl::OnTimeout, - base::Unretained(this))); - device_sync_client_->FindEligibleDevices( - cryptauth::SoftwareFeature::BETTER_TOGETHER_HOST, - base::BindOnce(&HostVerifierOperationImpl::OnFindEligibleDevicesResponse, - weak_ptr_factory_.GetWeakPtr())); -} - -HostVerifierOperationImpl::~HostVerifierOperationImpl() = default; - -void HostVerifierOperationImpl::PerformCancelOperation() { - FinishOperation(status_, Result::kCanceled); -} - -void HostVerifierOperationImpl::OnConnectionAttemptFailure( - secure_channel::mojom::ConnectionAttemptFailureReason reason) { - PA_LOG(WARNING) << "HostVerifierOperationImpl::OnConnectionAttemptFailure(): " - << "Failed to establish connection to device with ID \"" - << device_to_connect_.GetTruncatedDeviceIdForLogs() << "\". " - << "Reason: " << reason; - FinishOperation(Status::kWaitingForConnection, - Result::kConnectionAttemptFailed); -} - -void HostVerifierOperationImpl::OnConnection( - std::unique_ptr<secure_channel::ClientChannel> channel) { - client_channel_ = std::move(channel); - client_channel_->AddObserver(this); - - TransitionStatus(Status::kWaitingForConnection, Status::kWaitingForResponse); - client_channel_->SendMessage( - CreateWrappedEnableBetterTogetherRequest().SerializeAsString(), - base::DoNothing() /* on_sent_callback */); -} - -void HostVerifierOperationImpl::OnDisconnected() { - // Disconnections may occur after the operation is finished. - if (status_ == Status::kFinished) - return; - - PA_LOG(WARNING) << "HostVerifierOperationImpl::OnDisconnected(): " - << "Channel disconnected unexpectedly; could not complete " - << "verification of device with ID \"" - << device_to_connect_.GetTruncatedDeviceIdForLogs() << "\". "; - FinishOperation(Status::kWaitingForResponse, - Result::kConnectionDisconnectedUnexpectedly); -} - -void HostVerifierOperationImpl::OnMessageReceived(const std::string& payload) { - base::Optional<EnableBetterTogetherResponse> possible_response = - DeserializePossibleResponse(payload); - - // The message could have been unrelated; continue waiting. - if (!possible_response) - return; - - // If the received message is malformed, fail the operation. - if (!possible_response->has_result_code() || - !EnableBetterTogetherResponse::ResultCode_IsValid( - possible_response->result_code())) { - FinishOperation(Status::kWaitingForResponse, - Result::kReceivedInvalidResponse); - return; - } - - // If the received message includes an error, fail the operation. - if (possible_response->result_code() == EnableBetterTogetherResponse::ERROR) { - FinishOperation(Status::kWaitingForResponse, - Result::kReceivedErrorResponse); - return; - } - - FinishOperation(Status::kWaitingForResponse, Result::kSuccess); -} - -void HostVerifierOperationImpl::OnTimeout() { - switch (status_) { - case Status::kWaitingForFindEligibleDevicesResponse: - FinishOperation(status_, Result::kTimeoutFindingEligibleDevices); - break; - case Status::kWaitingForConnection: - FinishOperation(status_, Result::kTimeoutFindingConnection); - break; - case Status::kWaitingForResponse: - FinishOperation(status_, Result::kTimeoutReceivingResponse); - break; - case Status::kFinished: - PA_LOG(ERROR) << "HostVerifierOperationImpl::OnTimeout(): Timeout " - << "occurred, but the operation had already finished."; - NOTREACHED(); - break; - } -} - -void HostVerifierOperationImpl::OnFindEligibleDevicesResponse( - const base::Optional<std::string>& error_code, - cryptauth::RemoteDeviceRefList eligible_devices, - cryptauth::RemoteDeviceRefList ineligible_devices) { - // A response may be received after the operation is finished. - if (status_ == Status::kFinished) - return; - - if (error_code) { - PA_LOG(WARNING) << "HostVerifierOperationImpl::" - << "OnFindEligibleDevicesResponse(): Failed to complete " - << "FindEligibleDevices() call. Error code: " - << *error_code; - FinishOperation(Status::kWaitingForFindEligibleDevicesResponse, - Result::kErrorCallingFindEligibleDevices); - return; - } - - PA_LOG(INFO) << "HostVerifierOperationImpl::OnFindEligibleDevicesResponse(): " - << "Received FindEligibleDevices() response. " - << CreateLogString(eligible_devices, ineligible_devices); - - if (!base::ContainsValue(eligible_devices, device_to_connect_)) { - PA_LOG(WARNING) << "HostVerifierOperationImpl::" - << "OnFindEligibleDevicesResponse(): FindEligibleDevices() " - << "response does not include the device to connect. ID: " - << device_to_connect_.GetTruncatedDeviceIdForLogs(); - FinishOperation(Status::kWaitingForFindEligibleDevicesResponse, - Result::kDeviceToVerifyIsNotEligible); - return; - } - - TransitionStatus(Status::kWaitingForFindEligibleDevicesResponse, - Status::kWaitingForConnection); - - connection_attempt_ = secure_channel_client_->ListenForConnectionFromDevice( - device_to_connect_, local_device_, kFeature, - secure_channel::ConnectionPriority::kHigh); - connection_attempt_->SetDelegate(this); -} - -void HostVerifierOperationImpl::FinishOperation(Status expected_current_status, - Result result) { - TransitionStatus(expected_current_status, Status::kFinished); - - if (client_channel_) { - client_channel_->RemoveObserver(this); - client_channel_.reset(); - } - - connection_attempt_.reset(); - timer_->Stop(); - - if (result == Result::kCanceled) - return; - - NotifyOperationFinished(result); -} - -void HostVerifierOperationImpl::TransitionStatus(Status expected_current_status, - Status new_status) { - if (status_ != expected_current_status) { - PA_LOG(ERROR) << "HostVerifierOperationImpl::VerifyCurrentStatus(): " - << "Current status is unexpected. Current: " << status_ - << ", Expected: " << expected_current_status - << ", Attempted new status: " << new_status; - NOTREACHED(); - } - - PA_LOG(INFO) << "HostVerifierOperationImpl::TransitionStatus(): " - << "Transitioning from " << status_ << " to " << new_status - << "."; - status_ = new_status; -} - -std::ostream& operator<<(std::ostream& stream, - const HostVerifierOperationImpl::Status& status) { - switch (status) { - case HostVerifierOperationImpl::Status:: - kWaitingForFindEligibleDevicesResponse: - stream << "[waiting for FindEligibleDevices() response]"; - break; - case HostVerifierOperationImpl::Status::kWaitingForConnection: - stream << "[waiting for connection]"; - break; - case HostVerifierOperationImpl::Status::kWaitingForResponse: - stream << "[waiting for response]"; - break; - case HostVerifierOperationImpl::Status::kFinished: - stream << "[finished]"; - break; - } - return stream; -} - -} // namespace multidevice_setup - -} // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/host_verifier_operation_impl.h b/chromeos/services/multidevice_setup/host_verifier_operation_impl.h deleted file mode 100644 index 5fadde8..0000000 --- a/chromeos/services/multidevice_setup/host_verifier_operation_impl.h +++ /dev/null
@@ -1,133 +0,0 @@ -// 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. - -#ifndef CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_VERIFIER_OPERATION_IMPL_H_ -#define CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_VERIFIER_OPERATION_IMPL_H_ - -#include <memory> -#include <ostream> -#include <string> - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/optional.h" -#include "base/timer/timer.h" -#include "chromeos/services/multidevice_setup/host_verifier_operation.h" -#include "chromeos/services/multidevice_setup/proto/multidevice_setup.pb.h" -#include "chromeos/services/secure_channel/public/cpp/client/client_channel.h" -#include "chromeos/services/secure_channel/public/cpp/client/connection_attempt.h" -#include "chromeos/services/secure_channel/public/mojom/secure_channel.mojom.h" -#include "components/cryptauth/remote_device_ref.h" - -namespace chromeos { - -namespace device_sync { -class DeviceSyncClient; -} // namespace device_sync - -namespace secure_channel { -class SecureChannelClient; -} // namespace secure_channel - -namespace multidevice_setup { - -// Concrete HostVerifierOperation implementation. To verify the host, this class -// performs the following steps: -// (1) Call FindEligibleDevices(). This step sends a message to the host device, -// which in turn enables background advertising. -// (2) Creates a connection to the device using the BLE listener role. -// (3) Sends an EnableBetterTogetherRequest message to the host device. -// (4) Waits for an EnableBetterTogetherResponse messages to be returned by the -// host device. -class HostVerifierOperationImpl - : public HostVerifierOperation, - public secure_channel::ConnectionAttempt::Delegate, - public secure_channel::ClientChannel::Observer { - public: - class Factory { - public: - static Factory* Get(); - static void SetFactoryForTesting(Factory* test_factory); - virtual ~Factory(); - virtual std::unique_ptr<HostVerifierOperation> BuildInstance( - HostVerifierOperation::Delegate* delegate, - cryptauth::RemoteDeviceRef device_to_connect, - cryptauth::RemoteDeviceRef local_device, - device_sync::DeviceSyncClient* device_sync_client, - secure_channel::SecureChannelClient* secure_channel_client, - std::unique_ptr<base::OneShotTimer> timer = - std::make_unique<base::OneShotTimer>()); - - private: - static Factory* test_factory_; - }; - - ~HostVerifierOperationImpl() override; - - private: - friend class MultiDeviceSetupHostVerifierOperationImplTest; - - enum class Status { - kWaitingForFindEligibleDevicesResponse, - kWaitingForConnection, - kWaitingForResponse, - kFinished - }; - friend std::ostream& operator<<(std::ostream& stream, const Status& status); - - HostVerifierOperationImpl( - HostVerifierOperation::Delegate* delegate, - cryptauth::RemoteDeviceRef device_to_connect, - cryptauth::RemoteDeviceRef local_device, - device_sync::DeviceSyncClient* device_sync_client, - secure_channel::SecureChannelClient* secure_channel_client, - std::unique_ptr<base::OneShotTimer> timer); - - static BetterTogetherSetupMessageWrapper - CreateWrappedEnableBetterTogetherRequest(); - - // HostVerifierOperation: - void PerformCancelOperation() override; - - // secure_channel::ConnectionAttempt::Delegate: - void OnConnectionAttemptFailure( - secure_channel::mojom::ConnectionAttemptFailureReason reason) override; - void OnConnection( - std::unique_ptr<secure_channel::ClientChannel> channel) override; - - // secure_channel::ClientChannel::Observer: - void OnDisconnected() override; - void OnMessageReceived(const std::string& payload) override; - - void OnTimeout(); - void OnFindEligibleDevicesResponse( - const base::Optional<std::string>& error_code, - cryptauth::RemoteDeviceRefList eligible_devices, - cryptauth::RemoteDeviceRefList ineligible_devices); - void FinishOperation(Status expected_current_status, Result result); - void TransitionStatus(Status expected_current_status, Status new_status); - - cryptauth::RemoteDeviceRef device_to_connect_; - cryptauth::RemoteDeviceRef local_device_; - device_sync::DeviceSyncClient* device_sync_client_; - secure_channel::SecureChannelClient* secure_channel_client_; - std::unique_ptr<base::OneShotTimer> timer_; - - Status status_ = Status::kWaitingForFindEligibleDevicesResponse; - std::unique_ptr<secure_channel::ConnectionAttempt> connection_attempt_; - std::unique_ptr<secure_channel::ClientChannel> client_channel_; - - base::WeakPtrFactory<HostVerifierOperationImpl> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(HostVerifierOperationImpl); -}; - -std::ostream& operator<<(std::ostream& stream, - const HostVerifierOperationImpl::Status& status); - -} // namespace multidevice_setup - -} // namespace chromeos - -#endif // CHROMEOS_SERVICES_MULTIDEVICE_SETUP_HOST_VERIFIER_OPERATION_IMPL_H_
diff --git a/chromeos/services/multidevice_setup/host_verifier_operation_impl_unittest.cc b/chromeos/services/multidevice_setup/host_verifier_operation_impl_unittest.cc deleted file mode 100644 index d8cffd1..0000000 --- a/chromeos/services/multidevice_setup/host_verifier_operation_impl_unittest.cc +++ /dev/null
@@ -1,324 +0,0 @@ -// 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. - -#include "chromeos/services/multidevice_setup/host_verifier_operation_impl.h" - -#include <memory> - -#include "base/macros.h" -#include "base/timer/mock_timer.h" -#include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h" -#include "chromeos/services/multidevice_setup/fake_host_verifier_operation.h" -#include "chromeos/services/secure_channel/public/cpp/client/fake_client_channel.h" -#include "chromeos/services/secure_channel/public/cpp/client/fake_connection_attempt.h" -#include "chromeos/services/secure_channel/public/cpp/client/fake_secure_channel_client.h" -#include "components/cryptauth/remote_device_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace chromeos { - -namespace multidevice_setup { - -namespace { - -const size_t kNumTestDevices = 5; - -enum class ResponseType { - kUnrelated, - kNoResultCode, - kErrorResultCode, - kSuccess -}; - -std::string CreatePayloadForResponseType(ResponseType response_type) { - BetterTogetherSetupMessageWrapper wrapper; - wrapper.set_type(MessageType::ENABLE_BETTER_TOGETHER_RESPONSE); - - switch (response_type) { - case ResponseType::kUnrelated: { - return "unrelated"; - } - - case ResponseType::kNoResultCode: { - EnableBetterTogetherResponse response; - wrapper.set_payload(response.SerializeAsString()); - return wrapper.SerializeAsString(); - } - - case ResponseType::kErrorResultCode: { - EnableBetterTogetherResponse response; - response.set_result_code(EnableBetterTogetherResponse::ERROR); - wrapper.set_payload(response.SerializeAsString()); - return wrapper.SerializeAsString(); - } - - case ResponseType::kSuccess: { - EnableBetterTogetherResponse response; - response.set_result_code(EnableBetterTogetherResponse::NORMAL); - wrapper.set_payload(response.SerializeAsString()); - return wrapper.SerializeAsString(); - } - } -} - -} // namespace - -class MultiDeviceSetupHostVerifierOperationImplTest : public testing::Test { - protected: - MultiDeviceSetupHostVerifierOperationImplTest() - : test_devices_( - cryptauth::CreateRemoteDeviceRefListForTest(kNumTestDevices)) {} - ~MultiDeviceSetupHostVerifierOperationImplTest() override = default; - - // testing::Test: - void SetUp() override { - fake_delegate_ = std::make_unique<FakeHostVerifierOperationDelegate>(); - fake_device_sync_client_ = - std::make_unique<device_sync::FakeDeviceSyncClient>(); - fake_secure_channel_client_ = - std::make_unique<secure_channel::FakeSecureChannelClient>(); - auto mock_timer = std::make_unique<base::MockOneShotTimer>(); - mock_timer_ = mock_timer.get(); - - operation_ = HostVerifierOperationImpl::Factory::Get()->BuildInstance( - fake_delegate_.get(), remote_device(), local_device(), - fake_device_sync_client_.get(), fake_secure_channel_client_.get(), - std::move(mock_timer)); - - // The operation should have started its timer immediately. - EXPECT_TRUE(mock_timer_->IsRunning()); - } - - void Timeout() { mock_timer_->Fire(); } - - void CancelAndVerifyResult() { - operation_->CancelOperation(); - EXPECT_EQ(HostVerifierOperation::Result::kCanceled, GetOperationResult()); - } - - // Note: If |error_code| is set, then |should_remote_device_be_eligible| is - // ignored. The eligible/ineligible device lists are only provided if there - // was no error. - void CompletePendingFindEligibleDevicesResponse( - const base::Optional<std::string>& error_code = base::nullopt, - bool should_remote_device_be_eligible = true) { - cryptauth::RemoteDeviceRefList eligible_devices; - cryptauth::RemoteDeviceRefList ineligible_devices; - - if (!error_code) { - // Always make device 2 eligible. - eligible_devices.push_back(test_devices_[2]); - - if (should_remote_device_be_eligible) - eligible_devices.push_back(remote_device()); - else - ineligible_devices.push_back(remote_device()); - - // Always make the local device as well as devices 3 and 4 ineligible. - ineligible_devices.push_back(local_device()); - ineligible_devices.push_back(test_devices_[3]); - ineligible_devices.push_back(test_devices_[4]); - - if (should_remote_device_be_eligible) { - auto fake_connection_attempt = - std::make_unique<secure_channel::FakeConnectionAttempt>(); - fake_connection_attempt_ = fake_connection_attempt.get(); - fake_secure_channel_client_->set_next_listen_connection_attempt( - remote_device(), local_device(), - std::move(fake_connection_attempt)); - } - } - - EXPECT_FALSE(GetOperationResult()); - fake_device_sync_client_->InvokePendingFindEligibleDevicesCallback( - error_code, eligible_devices, ineligible_devices); - - if (error_code) { - EXPECT_EQ(HostVerifierOperation::Result::kErrorCallingFindEligibleDevices, - GetOperationResult()); - } else if (!should_remote_device_be_eligible) { - EXPECT_EQ(HostVerifierOperation::Result::kDeviceToVerifyIsNotEligible, - GetOperationResult()); - } else { - EXPECT_FALSE(GetOperationResult()); - } - } - - void FailToCreateConnectionAndVerifyState( - secure_channel::mojom::ConnectionAttemptFailureReason failure_reason) { - EXPECT_FALSE(GetOperationResult()); - fake_connection_attempt_->NotifyConnectionAttemptFailure(failure_reason); - EXPECT_EQ(HostVerifierOperation::Result::kConnectionAttemptFailed, - GetOperationResult()); - } - - void CreateConnectionSuccessfully() { - EXPECT_FALSE(GetOperationResult()); - auto fake_client_channel = - std::make_unique<secure_channel::FakeClientChannel>(); - fake_client_channel_ = fake_client_channel.get(); - fake_connection_attempt_->NotifyConnection(std::move(fake_client_channel)); - - EXPECT_EQ(1u, fake_client_channel_->sent_messages().size()); - EXPECT_EQ( - HostVerifierOperationImpl::CreateWrappedEnableBetterTogetherRequest() - .SerializeAsString(), - fake_client_channel_->sent_messages()[0].first); - } - - void ReceiveResponseAndVerifyState(ResponseType response_type) { - fake_client_channel_->NotifyMessageReceived( - CreatePayloadForResponseType(response_type)); - - switch (response_type) { - case ResponseType::kUnrelated: - EXPECT_FALSE(GetOperationResult()); - break; - case ResponseType::kNoResultCode: - EXPECT_EQ(HostVerifierOperation::Result::kReceivedInvalidResponse, - GetOperationResult()); - break; - case ResponseType::kErrorResultCode: - EXPECT_EQ(HostVerifierOperation::Result::kReceivedErrorResponse, - GetOperationResult()); - break; - case ResponseType::kSuccess: - EXPECT_EQ(HostVerifierOperation::Result::kSuccess, - GetOperationResult()); - break; - } - } - - base::Optional<HostVerifierOperation::Result> GetOperationResult() { - // Both |operation_| and |fake_delegate_| should have identical result - // values. - EXPECT_EQ(operation_->result(), fake_delegate_->result()); - return operation_->result(); - } - - secure_channel::FakeClientChannel* fake_client_channel() { - return fake_client_channel_; - } - - const cryptauth::RemoteDeviceRef& local_device() { return test_devices_[0]; } - const cryptauth::RemoteDeviceRef& remote_device() { return test_devices_[1]; } - - private: - const cryptauth::RemoteDeviceRefList test_devices_; - - std::unique_ptr<FakeHostVerifierOperationDelegate> fake_delegate_; - std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_; - std::unique_ptr<secure_channel::FakeSecureChannelClient> - fake_secure_channel_client_; - base::MockOneShotTimer* mock_timer_ = nullptr; - - secure_channel::FakeConnectionAttempt* fake_connection_attempt_ = nullptr; - secure_channel::FakeClientChannel* fake_client_channel_ = nullptr; - - std::unique_ptr<HostVerifierOperation> operation_; - - DISALLOW_COPY_AND_ASSIGN(MultiDeviceSetupHostVerifierOperationImplTest); -}; - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - TimeoutFindingEligibleDevices) { - Timeout(); - EXPECT_EQ(HostVerifierOperation::Result::kTimeoutFindingEligibleDevices, - GetOperationResult()); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - CancelWhileFindingEligibleDevices) { - CancelAndVerifyResult(); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - ErrorCallingFindEligibleDevices) { - CompletePendingFindEligibleDevicesResponse("errorCode"); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - DeviceToVerifyIsNotEligible) { - CompletePendingFindEligibleDevicesResponse( - base::nullopt /* error_code */, - false /* should_remote_device_be_eligible */); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - TimeoutFindingConnection) { - CompletePendingFindEligibleDevicesResponse(); - Timeout(); - EXPECT_EQ(HostVerifierOperation::Result::kTimeoutFindingConnection, - GetOperationResult()); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - CancelWhileFindingConnection) { - CompletePendingFindEligibleDevicesResponse(); - CancelAndVerifyResult(); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, ConnectionAttemptFailed) { - CompletePendingFindEligibleDevicesResponse(); - FailToCreateConnectionAndVerifyState( - secure_channel::mojom::ConnectionAttemptFailureReason:: - AUTHENTICATION_ERROR); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - ConnectionDisconnectedUnexpectedly) { - CompletePendingFindEligibleDevicesResponse(); - CreateConnectionSuccessfully(); - fake_client_channel()->NotifyDisconnected(); - EXPECT_EQ(HostVerifierOperation::Result::kConnectionDisconnectedUnexpectedly, - GetOperationResult()); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - TimeoutReceivingResponse) { - CompletePendingFindEligibleDevicesResponse(); - CreateConnectionSuccessfully(); - Timeout(); - EXPECT_EQ(HostVerifierOperation::Result::kTimeoutReceivingResponse, - GetOperationResult()); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - CancelWhileWaitingForResponse) { - CompletePendingFindEligibleDevicesResponse(); - CreateConnectionSuccessfully(); - CancelAndVerifyResult(); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - ReceivedInvalidResponse_NoResultCode) { - CompletePendingFindEligibleDevicesResponse(); - CreateConnectionSuccessfully(); - ReceiveResponseAndVerifyState(ResponseType::kNoResultCode); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - ReceivedInvalidResponse_ErrorResultCode) { - CompletePendingFindEligibleDevicesResponse(); - CreateConnectionSuccessfully(); - ReceiveResponseAndVerifyState(ResponseType::kErrorResultCode); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, Success) { - CompletePendingFindEligibleDevicesResponse(); - CreateConnectionSuccessfully(); - ReceiveResponseAndVerifyState(ResponseType::kSuccess); -} - -TEST_F(MultiDeviceSetupHostVerifierOperationImplTest, - ReceiveUnrelatedMessageThenSuccess) { - CompletePendingFindEligibleDevicesResponse(); - CreateConnectionSuccessfully(); - ReceiveResponseAndVerifyState(ResponseType::kUnrelated); - ReceiveResponseAndVerifyState(ResponseType::kSuccess); -} - -} // namespace multidevice_setup - -} // namespace chromeos
diff --git a/components/OWNERS b/components/OWNERS index 5bbb5625..f3ef29a 100644 --- a/components/OWNERS +++ b/components/OWNERS
@@ -30,7 +30,7 @@ per-file translate_strings.grdp=file://components/translate/OWNERS per-file undo_strings.grdp=file://components/undo/OWNERS per-file version_ui_strings.grdp=file://components/version_ui/OWNERS -per-file web_contents_delegate_android_strings.grdp=file://components/web_contents_delegate_android/OWNERS +per-file web_contents_delegate_android_strings.grdp=file://components/embedder_support/android/delegate/OWNERS # These are for the common case of adding or removing tests. If you're making # structural changes, please get a review from one of the overall components
diff --git a/components/arc/power/arc_power_bridge.cc b/components/arc/power/arc_power_bridge.cc index be74d85..7e7a2db 100644 --- a/components/arc/power/arc_power_bridge.cc +++ b/components/arc/power/arc_power_bridge.cc
@@ -139,7 +139,7 @@ bool ArcPowerBridge::TriggerNotifyBrightnessTimerForTesting() { if (!notify_brightness_timer_.IsRunning()) return false; - notify_brightness_timer_.user_task().Run(); + notify_brightness_timer_.FireNow(); return true; }
diff --git a/components/data_reduction_proxy/DEPS b/components/data_reduction_proxy/DEPS index d2649794..23dc156 100644 --- a/components/data_reduction_proxy/DEPS +++ b/components/data_reduction_proxy/DEPS
@@ -7,6 +7,7 @@ "+crypto", "+google_apis", "+net", + "+services/network/public/cpp", # Data Reduction Proxy is a layered component; subdirectories must explicitly # introduce the ability to use the content layer as appropriate.
diff --git a/components/data_reduction_proxy/core/common/BUILD.gn b/components/data_reduction_proxy/core/common/BUILD.gn index 97bc64a9cb..5fa1ee6 100644 --- a/components/data_reduction_proxy/core/common/BUILD.gn +++ b/components/data_reduction_proxy/core/common/BUILD.gn
@@ -45,6 +45,7 @@ "//components/data_reduction_proxy/proto:data_reduction_proxy_proto", "//components/variations", "//google_apis", + "//services/network/public/cpp", ] defines = [ "USE_GOOGLE_API_KEYS" ]
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc index 03bd90a..aeb892b 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -24,6 +24,7 @@ #include "net/http/http_status_code.h" #include "net/http/http_util.h" #include "net/url_request/url_request.h" +#include "services/network/public/cpp/resource_response.h" namespace { @@ -484,4 +485,20 @@ return -1; } +double EstimateCompressionRatioFromHeaders( + const network::ResourceResponseHead* response_head) { + if (!response_head->network_accessed || !response_head->headers || + response_head->headers->GetContentLength() <= 0) { + return 1.0; // No compression + } + + int64_t original_content_length = + GetDataReductionProxyOFCL(response_head->headers.get()); + if (original_content_length > 0) { + return static_cast<double>(original_content_length) / + static_cast<double>(response_head->headers->GetContentLength()); + } + return 1.0; // No compression +} + } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h index c895cf4..c97170e 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
@@ -21,6 +21,10 @@ class HttpResponseHeaders; } // namespace net +namespace network { +struct ResourceResponseHead; +} // namespace network + namespace data_reduction_proxy { // Transform directives that may be parsed out of http headers. @@ -176,9 +180,19 @@ base::StringPiece action_prefix, base::TimeDelta* bypass_duration); -// Returns the OFCL value in the Chrome-Proxy header. Returns -1 in case of -// of error or if OFCL does not exist. |headers| must be non-null. +// Returns the Original-Full-Content-Length(OFCL) value in the Chrome-Proxy +// header. Returns -1 in case of of error or if OFCL does not exist. |headers| +// must be non-null. int64_t GetDataReductionProxyOFCL(const net::HttpResponseHeaders* headers); +// Returns an estimate of the compression ratio from the Content-Length and +// Chrome-Proxy Original-Full-Content-Length(OFCL) response headers. These may +// not be populated for responses which are streamed from the origin which will +// be treated as a no compression case. Notably, only the response body size is +// used to compute the ratio, and headers are excluded, since this is only an +// estimate for response that is beginning to arrive. +double EstimateCompressionRatioFromHeaders( + const network::ResourceResponseHead* response_head); + } // namespace data_reduction_proxy #endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_HEADERS_H_
diff --git a/components/download/internal/common/download_task_runner.cc b/components/download/internal/common/download_task_runner.cc index 55db38f..7d688dc 100644 --- a/components/download/internal/common/download_task_runner.cc +++ b/components/download/internal/common/download_task_runner.cc
@@ -45,20 +45,13 @@ void SetIOTaskRunner( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { - base::AutoLock auto_lock(GetIOTaskRunnerLock()); - static int count = 0; - if (task_runner) { - DCHECK(!g_io_task_runner.Get() || - task_runner.get() == g_io_task_runner.Get().get()); - count++; - g_io_task_runner.Get() = task_runner; - return; - } + DCHECK(task_runner); - count--; - DCHECK_GE(count, 0); - if (count == 0) - g_io_task_runner.Get() = nullptr; + base::AutoLock auto_lock(GetIOTaskRunnerLock()); + if (g_io_task_runner.Get()) + return; + + g_io_task_runner.Get() = task_runner; } scoped_refptr<base::SingleThreadTaskRunner> GetIOTaskRunner() {
diff --git a/components/embedder_support/android/BUILD.gn b/components/embedder_support/android/BUILD.gn index 3e993b0..f6665ae4 100644 --- a/components/embedder_support/android/BUILD.gn +++ b/components/embedder_support/android/BUILD.gn
@@ -54,3 +54,112 @@ ] jni_package = "view" } + +java_strings_grd("web_contents_delegate_strings_grd") { + grd_file = "java/strings/web_contents_delegate_android_strings.grd" + outputs = [ + "values-am/web_contents_delegate_android_strings.xml", + "values-ar/web_contents_delegate_android_strings.xml", + "values-bg/web_contents_delegate_android_strings.xml", + "values-ca/web_contents_delegate_android_strings.xml", + "values-cs/web_contents_delegate_android_strings.xml", + "values-da/web_contents_delegate_android_strings.xml", + "values-de/web_contents_delegate_android_strings.xml", + "values-el/web_contents_delegate_android_strings.xml", + "values/web_contents_delegate_android_strings.xml", + "values-en-rGB/web_contents_delegate_android_strings.xml", + "values-es/web_contents_delegate_android_strings.xml", + "values-es-rUS/web_contents_delegate_android_strings.xml", + "values-fa/web_contents_delegate_android_strings.xml", + "values-fi/web_contents_delegate_android_strings.xml", + "values-tl/web_contents_delegate_android_strings.xml", + "values-fr/web_contents_delegate_android_strings.xml", + "values-hi/web_contents_delegate_android_strings.xml", + "values-hr/web_contents_delegate_android_strings.xml", + "values-hu/web_contents_delegate_android_strings.xml", + "values-in/web_contents_delegate_android_strings.xml", + "values-it/web_contents_delegate_android_strings.xml", + "values-iw/web_contents_delegate_android_strings.xml", + "values-ja/web_contents_delegate_android_strings.xml", + "values-ko/web_contents_delegate_android_strings.xml", + "values-lt/web_contents_delegate_android_strings.xml", + "values-lv/web_contents_delegate_android_strings.xml", + "values-nl/web_contents_delegate_android_strings.xml", + "values-nb/web_contents_delegate_android_strings.xml", + "values-pl/web_contents_delegate_android_strings.xml", + "values-pt-rBR/web_contents_delegate_android_strings.xml", + "values-pt-rPT/web_contents_delegate_android_strings.xml", + "values-ro/web_contents_delegate_android_strings.xml", + "values-ru/web_contents_delegate_android_strings.xml", + "values-sk/web_contents_delegate_android_strings.xml", + "values-sl/web_contents_delegate_android_strings.xml", + "values-sr/web_contents_delegate_android_strings.xml", + "values-sv/web_contents_delegate_android_strings.xml", + "values-sw/web_contents_delegate_android_strings.xml", + "values-th/web_contents_delegate_android_strings.xml", + "values-tr/web_contents_delegate_android_strings.xml", + "values-uk/web_contents_delegate_android_strings.xml", + "values-vi/web_contents_delegate_android_strings.xml", + "values-zh-rCN/web_contents_delegate_android_strings.xml", + "values-zh-rTW/web_contents_delegate_android_strings.xml", + ] +} + +static_library("web_contents_delegate") { + sources = [ + "delegate/color_chooser_android.cc", + "delegate/color_chooser_android.h", + "delegate/web_contents_delegate_android.cc", + "delegate/web_contents_delegate_android.h", + ] + + deps = [ + ":web_contents_delegate_jni_headers", + "//base", + "//content/public/browser", + "//content/public/common", + "//net", + "//skia", + "//ui/android", + "//ui/base", + "//ui/gfx", + "//ui/gfx/geometry", + ] +} + +android_resources("web_contents_delegate_java_resources") { + custom_package = "org.chromium.components.embedder_support.delegate" + resource_dirs = [ "java/res" ] + deps = [ + ":web_contents_delegate_strings_grd", + ] +} + +android_library("web_contents_delegate_java") { + deps = [ + ":web_contents_delegate_java_resources", + "//base:base_java", + "//content/public/android:content_java", + "//ui/android:ui_java", + ] + java_files = [ + "java/src/org/chromium/components/embedder_support/delegate/ColorChooserAndroid.java", + "java/src/org/chromium/components/embedder_support/delegate/ColorPickerAdvanced.java", + "java/src/org/chromium/components/embedder_support/delegate/ColorPickerAdvancedComponent.java", + "java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialog.java", + "java/src/org/chromium/components/embedder_support/delegate/ColorPickerMoreButton.java", + "java/src/org/chromium/components/embedder_support/delegate/ColorPickerSimple.java", + "java/src/org/chromium/components/embedder_support/delegate/ColorSuggestion.java", + "java/src/org/chromium/components/embedder_support/delegate/ColorSuggestionListAdapter.java", + "java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java", + "java/src/org/chromium/components/embedder_support/delegate/OnColorChangedListener.java", + ] +} + +generate_jni("web_contents_delegate_jni_headers") { + sources = [ + "java/src/org/chromium/components/embedder_support/delegate/ColorChooserAndroid.java", + "java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java", + ] + jni_package = "web_contents_delegate_android" +}
diff --git a/components/web_contents_delegate_android/DEPS b/components/embedder_support/android/delegate/DEPS similarity index 100% rename from components/web_contents_delegate_android/DEPS rename to components/embedder_support/android/delegate/DEPS
diff --git a/components/embedder_support/android/delegate/OWNERS b/components/embedder_support/android/delegate/OWNERS new file mode 100644 index 0000000..9fd8a62 --- /dev/null +++ b/components/embedder_support/android/delegate/OWNERS
@@ -0,0 +1,2 @@ +boliu@chromium.org +tedchoc@chromium.org \ No newline at end of file
diff --git a/components/web_contents_delegate_android/color_chooser_android.cc b/components/embedder_support/android/delegate/color_chooser_android.cc similarity index 94% rename from components/web_contents_delegate_android/color_chooser_android.cc rename to components/embedder_support/android/delegate/color_chooser_android.cc index 8e89372..c6cf78d4 100644 --- a/components/web_contents_delegate_android/color_chooser_android.cc +++ b/components/embedder_support/android/delegate/color_chooser_android.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 "components/web_contents_delegate_android/color_chooser_android.h" +#include "components/embedder_support/android/delegate/color_chooser_android.h" #include <stddef.h> @@ -50,8 +50,7 @@ OnColorChosen(env, j_color_chooser_, initial_color); } -ColorChooserAndroid::~ColorChooserAndroid() { -} +ColorChooserAndroid::~ColorChooserAndroid() {} void ColorChooserAndroid::End() { if (!j_color_chooser_.is_null()) {
diff --git a/components/web_contents_delegate_android/color_chooser_android.h b/components/embedder_support/android/delegate/color_chooser_android.h similarity index 86% rename from components/web_contents_delegate_android/color_chooser_android.h rename to components/embedder_support/android/delegate/color_chooser_android.h index c835916..d05421b 100644 --- a/components/web_contents_delegate_android/color_chooser_android.h +++ b/components/embedder_support/android/delegate/color_chooser_android.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 COMPONENTS_WEB_CONTENTS_DELEGATE_ANDROID_COLOR_CHOOSER_ANDROID_H_ -#define COMPONENTS_WEB_CONTENTS_DELEGATE_ANDROID_COLOR_CHOOSER_ANDROID_H_ +#ifndef COMPONENTS_EMBEDDER_SUPPORT_ANDROID_DELEGATE_COLOR_CHOOSER_ANDROID_H_ +#define COMPONENTS_EMBEDDER_SUPPORT_ANDROID_DELEGATE_COLOR_CHOOSER_ANDROID_H_ #include <vector> @@ -52,4 +52,4 @@ } // namespace web_contents_delegate_android -#endif // COMPONENTS_WEB_CONTENTS_DELEGATE_ANDROID_COLOR_CHOOSER_ANDROID_H_ +#endif // COMPONENTS_EMBEDDER_SUPPORT_ANDROID_DELEGATE_COLOR_CHOOSER_ANDROID_H_
diff --git a/components/web_contents_delegate_android/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc similarity index 95% rename from components/web_contents_delegate_android/web_contents_delegate_android.cc rename to components/embedder_support/android/delegate/web_contents_delegate_android.cc index 70edaf6..bd4ee2d 100644 --- a/components/web_contents_delegate_android/web_contents_delegate_android.cc +++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/web_contents_delegate_android/web_contents_delegate_android.h" +#include "components/embedder_support/android/delegate/web_contents_delegate_android.h" #include <android/keycodes.h> #include "base/android/jni_android.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" -#include "components/web_contents_delegate_android/color_chooser_android.h" +#include "components/embedder_support/android/delegate/color_chooser_android.h" #include "content/public/browser/color_chooser.h" #include "content/public/browser/global_request_id.h" #include "content/public/browser/invalidate_type.h" @@ -38,14 +38,12 @@ namespace web_contents_delegate_android { WebContentsDelegateAndroid::WebContentsDelegateAndroid(JNIEnv* env, jobject obj) - : weak_java_delegate_(env, obj) { -} + : weak_java_delegate_(env, obj) {} -WebContentsDelegateAndroid::~WebContentsDelegateAndroid() { -} +WebContentsDelegateAndroid::~WebContentsDelegateAndroid() {} -ScopedJavaLocalRef<jobject> -WebContentsDelegateAndroid::GetJavaDelegate(JNIEnv* env) const { +ScopedJavaLocalRef<jobject> WebContentsDelegateAndroid::GetJavaDelegate( + JNIEnv* env) const { return weak_java_delegate_.get(env); } @@ -89,7 +87,7 @@ ScopedJavaLocalRef<jstring> java_url = ConvertUTF8ToJavaString(env, url.spec()); ScopedJavaLocalRef<jstring> extra_headers = - ConvertUTF8ToJavaString(env, params.extra_headers); + ConvertUTF8ToJavaString(env, params.extra_headers); ScopedJavaLocalRef<jobject> post_data; if (params.uses_post && params.post_data) { post_data = content::ConvertResourceRequestBodyToJavaObject( @@ -124,7 +122,8 @@ } void WebContentsDelegateAndroid::NavigationStateChanged( - WebContents* source, content::InvalidateTypes changed_flags) { + WebContents* source, + content::InvalidateTypes changed_flags) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env); if (obj.is_null()) @@ -150,7 +149,8 @@ Java_WebContentsDelegateAndroid_activateContents(env, obj); } -void WebContentsDelegateAndroid::LoadingStateChanged(WebContents* source, +void WebContentsDelegateAndroid::LoadingStateChanged( + WebContents* source, bool to_different_document) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env); @@ -350,7 +350,8 @@ if (obj.is_null()) return false; ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec()); - return Java_WebContentsDelegateAndroid_shouldBlockMediaRequest(env, obj, j_url); + return Java_WebContentsDelegateAndroid_shouldBlockMediaRequest(env, obj, + j_url); } void WebContentsDelegateAndroid::EnterFullscreenModeForTab( @@ -384,8 +385,7 @@ } void WebContentsDelegateAndroid::RequestAppBannerFromDevTools( - content::WebContents* web_contents) { -} + content::WebContents* web_contents) {} void WebContentsDelegateAndroid::OnDidBlockFramebust( content::WebContents* web_contents,
diff --git a/components/web_contents_delegate_android/web_contents_delegate_android.h b/components/embedder_support/android/delegate/web_contents_delegate_android.h similarity index 93% rename from components/web_contents_delegate_android/web_contents_delegate_android.h rename to components/embedder_support/android/delegate/web_contents_delegate_android.h index db514ed..e7dd15a 100644 --- a/components/web_contents_delegate_android/web_contents_delegate_android.h +++ b/components/embedder_support/android/delegate/web_contents_delegate_android.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 COMPONENTS_WEB_CONTENTS_DELEGATE_ANDROID_WEB_CONTENTS_DELEGATE_ANDROID_H_ -#define COMPONENTS_WEB_CONTENTS_DELEGATE_ANDROID_WEB_CONTENTS_DELEGATE_ANDROID_H_ +#ifndef COMPONENTS_EMBEDDER_SUPPORT_ANDROID_DELEGATE_WEB_CONTENTS_DELEGATE_ANDROID_H_ +#define COMPONENTS_EMBEDDER_SUPPORT_ANDROID_DELEGATE_WEB_CONTENTS_DELEGATE_ANDROID_H_ #include <stdint.h> @@ -21,7 +21,7 @@ class WebContentsDelegate; struct NativeWebKeyboardEvent; struct OpenURLParams; -} +} // namespace content namespace web_contents_delegate_android { @@ -36,7 +36,6 @@ WEB_CONTENTS_DELEGATE_LOG_LEVEL_ERROR = 3, }; - // Native underpinnings of WebContentsDelegateAndroid.java. Provides a default // delegate for WebContents to forward calls to the java peer. The embedding // application may subclass and override methods on either the C++ or Java side @@ -103,8 +102,8 @@ const content::NativeWebKeyboardEvent& event) override; bool TakeFocus(content::WebContents* source, bool reverse) override; void ShowRepostFormWarningDialog(content::WebContents* source) override; - base::android::ScopedJavaLocalRef<jobject> - GetContentVideoViewEmbedder() override; + base::android::ScopedJavaLocalRef<jobject> GetContentVideoViewEmbedder() + override; bool ShouldBlockMediaRequest(const GURL& url) override; void EnterFullscreenModeForTab( content::WebContents* web_contents, @@ -133,4 +132,4 @@ } // namespace web_contents_delegate_android -#endif // COMPONENTS_WEB_CONTENTS_DELEGATE_ANDROID_WEB_CONTENTS_DELEGATE_ANDROID_H_ +#endif // COMPONENTS_EMBEDDER_SUPPORT_ANDROID_DELEGATE_WEB_CONTENTS_DELEGATE_ANDROID_H_
diff --git a/components/web_contents_delegate_android/java/res/drawable-hdpi/color_picker_advanced_select_handle.png b/components/embedder_support/android/java/res/drawable-hdpi/color_picker_advanced_select_handle.png similarity index 100% rename from components/web_contents_delegate_android/java/res/drawable-hdpi/color_picker_advanced_select_handle.png rename to components/embedder_support/android/java/res/drawable-hdpi/color_picker_advanced_select_handle.png Binary files differ
diff --git a/components/web_contents_delegate_android/java/res/drawable-mdpi/color_picker_advanced_select_handle.png b/components/embedder_support/android/java/res/drawable-mdpi/color_picker_advanced_select_handle.png similarity index 100% rename from components/web_contents_delegate_android/java/res/drawable-mdpi/color_picker_advanced_select_handle.png rename to components/embedder_support/android/java/res/drawable-mdpi/color_picker_advanced_select_handle.png Binary files differ
diff --git a/components/web_contents_delegate_android/java/res/drawable-xhdpi/color_picker_advanced_select_handle.png b/components/embedder_support/android/java/res/drawable-xhdpi/color_picker_advanced_select_handle.png similarity index 100% rename from components/web_contents_delegate_android/java/res/drawable-xhdpi/color_picker_advanced_select_handle.png rename to components/embedder_support/android/java/res/drawable-xhdpi/color_picker_advanced_select_handle.png Binary files differ
diff --git a/components/web_contents_delegate_android/java/res/drawable/color_button_background.xml b/components/embedder_support/android/java/res/drawable/color_button_background.xml similarity index 100% rename from components/web_contents_delegate_android/java/res/drawable/color_button_background.xml rename to components/embedder_support/android/java/res/drawable/color_button_background.xml
diff --git a/components/web_contents_delegate_android/java/res/drawable/color_picker_border.xml b/components/embedder_support/android/java/res/drawable/color_picker_border.xml similarity index 100% rename from components/web_contents_delegate_android/java/res/drawable/color_picker_border.xml rename to components/embedder_support/android/java/res/drawable/color_picker_border.xml
diff --git a/components/web_contents_delegate_android/java/res/layout/color_picker_advanced_component.xml b/components/embedder_support/android/java/res/layout/color_picker_advanced_component.xml similarity index 100% rename from components/web_contents_delegate_android/java/res/layout/color_picker_advanced_component.xml rename to components/embedder_support/android/java/res/layout/color_picker_advanced_component.xml
diff --git a/components/web_contents_delegate_android/java/res/layout/color_picker_dialog_content.xml b/components/embedder_support/android/java/res/layout/color_picker_dialog_content.xml similarity index 87% rename from components/web_contents_delegate_android/java/res/layout/color_picker_dialog_content.xml rename to components/embedder_support/android/java/res/layout/color_picker_dialog_content.xml index 552b27c6..85111fd 100644 --- a/components/web_contents_delegate_android/java/res/layout/color_picker_dialog_content.xml +++ b/components/embedder_support/android/java/res/layout/color_picker_dialog_content.xml
@@ -15,13 +15,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - <org.chromium.components.web_contents_delegate_android.ColorPickerAdvanced + <org.chromium.components.embedder_support.delegate.ColorPickerAdvanced android:id="@+id/color_picker_advanced" android:layout_width="match_parent" android:layout_height="wrap_content" /> </ScrollView> - <org.chromium.components.web_contents_delegate_android.ColorPickerSimple + <org.chromium.components.embedder_support.delegate.ColorPickerSimple android:id="@+id/color_picker_simple" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -39,7 +39,7 @@ android:background="@drawable/color_picker_border" android:padding="1px"> - <org.chromium.components.web_contents_delegate_android.ColorPickerMoreButton + <org.chromium.components.embedder_support.delegate.ColorPickerMoreButton android:id="@+id/more_colors_button" style="?android:attr/buttonBarButtonStyle" android:layout_width="match_parent"
diff --git a/components/web_contents_delegate_android/java/res/layout/color_picker_dialog_title.xml b/components/embedder_support/android/java/res/layout/color_picker_dialog_title.xml similarity index 100% rename from components/web_contents_delegate_android/java/res/layout/color_picker_dialog_title.xml rename to components/embedder_support/android/java/res/layout/color_picker_dialog_title.xml
diff --git a/components/web_contents_delegate_android/java/res/values/colors.xml b/components/embedder_support/android/java/res/values/colors.xml similarity index 100% rename from components/web_contents_delegate_android/java/res/values/colors.xml rename to components/embedder_support/android/java/res/values/colors.xml
diff --git a/components/web_contents_delegate_android/java/res/values/dimens.xml b/components/embedder_support/android/java/res/values/dimens.xml similarity index 100% rename from components/web_contents_delegate_android/java/res/values/dimens.xml rename to components/embedder_support/android/java/res/values/dimens.xml
diff --git a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorChooserAndroid.java similarity index 97% rename from components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorChooserAndroid.java index f50e57f..4ef31f4 100644 --- a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorChooserAndroid.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.components.web_contents_delegate_android; +package org.chromium.components.embedder_support.delegate; import android.content.Context;
diff --git a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvanced.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerAdvanced.java similarity index 98% rename from components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvanced.java rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerAdvanced.java index 4310b3d..e871fcb3 100644 --- a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvanced.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerAdvanced.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.components.web_contents_delegate_android; +package org.chromium.components.embedder_support.delegate; import android.content.Context; import android.graphics.Color;
diff --git a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvancedComponent.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerAdvancedComponent.java similarity index 97% rename from components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvancedComponent.java rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerAdvancedComponent.java index 3e42672..80360f0 100644 --- a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvancedComponent.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerAdvancedComponent.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.components.web_contents_delegate_android; +package org.chromium.components.embedder_support.delegate; import android.content.Context; import android.graphics.drawable.GradientDrawable;
diff --git a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerDialog.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialog.java similarity index 98% rename from components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerDialog.java rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialog.java index cc8f0b81..dca3c3c 100644 --- a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerDialog.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialog.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.components.web_contents_delegate_android; +package org.chromium.components.embedder_support.delegate; import android.app.AlertDialog; import android.app.Dialog;
diff --git a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerMoreButton.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerMoreButton.java similarity index 95% rename from components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerMoreButton.java rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerMoreButton.java index d692f4f..52bd67e2 100644 --- a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerMoreButton.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerMoreButton.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.components.web_contents_delegate_android; +package org.chromium.components.embedder_support.delegate; import android.content.Context; import android.graphics.Canvas;
diff --git a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerSimple.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerSimple.java similarity index 93% rename from components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerSimple.java rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerSimple.java index d9c20ab..b7ec055 100644 --- a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorPickerSimple.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerSimple.java
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.components.web_contents_delegate_android; +package org.chromium.components.embedder_support.delegate; import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.widget.ListView; -import org.chromium.components.web_contents_delegate_android.ColorSuggestionListAdapter.OnColorSuggestionClickListener; +import org.chromium.components.embedder_support.delegate.ColorSuggestionListAdapter.OnColorSuggestionClickListener; /** * Draws a grid of (predefined) colors and allows the user to choose one of
diff --git a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestion.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorSuggestion.java similarity index 90% rename from components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestion.java rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorSuggestion.java index c1ac714..d4d43c50 100644 --- a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestion.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorSuggestion.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.components.web_contents_delegate_android; +package org.chromium.components.embedder_support.delegate; /** * Color suggestion container used to store information for each color button that will be shown in
diff --git a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestionListAdapter.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorSuggestionListAdapter.java similarity index 98% rename from components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestionListAdapter.java rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorSuggestionListAdapter.java index ceaefad..fdc4c85 100644 --- a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestionListAdapter.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorSuggestionListAdapter.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.components.web_contents_delegate_android; +package org.chromium.components.embedder_support.delegate; import android.content.Context; import android.graphics.Color;
diff --git a/components/web_contents_delegate_android/java/DEPS b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/DEPS similarity index 100% rename from components/web_contents_delegate_android/java/DEPS rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/DEPS
diff --git a/components/web_contents_delegate_android/OWNERS b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/OWNERS similarity index 100% rename from components/web_contents_delegate_android/OWNERS rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/OWNERS
diff --git a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/OnColorChangedListener.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/OnColorChangedListener.java similarity index 86% rename from components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/OnColorChangedListener.java rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/OnColorChangedListener.java index 95630adb..fa6d3ce0 100644 --- a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/OnColorChangedListener.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/OnColorChangedListener.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.components.web_contents_delegate_android; +package org.chromium.components.embedder_support.delegate; /** * The callback used to indicate the user changed the color. @@ -14,4 +14,4 @@ * @param color The color that was set. */ void onColorChanged(int color); -} \ No newline at end of file +}
diff --git a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java similarity index 98% rename from components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java rename to components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java index bc6694b4..a11cf96b 100644 --- a/components/web_contents_delegate_android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java +++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.components.web_contents_delegate_android; +package org.chromium.components.embedder_support.delegate; import android.view.KeyEvent;
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_am.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_am.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_am.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_am.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ar.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ar.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ar.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ar.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_bg.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_bg.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_bg.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_bg.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ca.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ca.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ca.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ca.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_cs.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_cs.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_cs.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_cs.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_da.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_da.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_da.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_da.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_de.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_de.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_de.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_de.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_el.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_el.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_el.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_el.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_en-GB.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_en-GB.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_en-GB.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_en-GB.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es-419.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_es-419.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es-419.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_es-419.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_es.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_es.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_es.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fa.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_fa.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fa.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_fa.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fi.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_fi.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fi.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_fi.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fil.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_fil.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fil.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_fil.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fr.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_fr.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_fr.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_fr.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hi.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_hi.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hi.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_hi.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hr.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_hr.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hr.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_hr.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hu.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_hu.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_hu.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_hu.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_id.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_id.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_id.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_id.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_it.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_it.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_it.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_it.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_iw.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_iw.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_iw.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_iw.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ja.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ja.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ja.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ja.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ko.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ko.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ko.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ko.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lt.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_lt.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lt.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_lt.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lv.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_lv.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_lv.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_lv.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_nl.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_nl.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_nl.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_nl.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_no.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_no.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_no.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_no.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pl.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_pl.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pl.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_pl.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-BR.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_pt-BR.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-BR.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_pt-BR.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-PT.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_pt-PT.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_pt-PT.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_pt-PT.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ro.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ro.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ro.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ro.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ru.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ru.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_ru.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_ru.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sk.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_sk.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sk.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_sk.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sl.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_sl.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sl.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_sl.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sr.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_sr.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sr.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_sr.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sv.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_sv.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sv.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_sv.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sw.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_sw.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_sw.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_sw.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_th.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_th.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_th.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_th.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_tr.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_tr.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_tr.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_tr.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_uk.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_uk.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_uk.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_uk.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_vi.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_vi.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_vi.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_vi.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-CN.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_zh-CN.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-CN.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_zh-CN.xtb
diff --git a/components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-TW.xtb b/components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_zh-TW.xtb similarity index 100% rename from components/web_contents_delegate_android/java/strings/translations/web_contents_delegate_android_strings_zh-TW.xtb rename to components/embedder_support/android/java/strings/translations/web_contents_delegate_android_strings_zh-TW.xtb
diff --git a/components/web_contents_delegate_android/java/strings/web_contents_delegate_android_strings.grd b/components/embedder_support/android/java/strings/web_contents_delegate_android_strings.grd similarity index 100% rename from components/web_contents_delegate_android/java/strings/web_contents_delegate_android_strings.grd rename to components/embedder_support/android/java/strings/web_contents_delegate_android_strings.grd
diff --git a/components/gcm_driver/fake_gcm_client.cc b/components/gcm_driver/fake_gcm_client.cc index e969cd4a..adbb8f9 100644 --- a/components/gcm_driver/fake_gcm_client.cc +++ b/components/gcm_driver/fake_gcm_client.cc
@@ -77,6 +77,7 @@ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter, + const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory, std::unique_ptr<Encryptor> encryptor, Delegate* delegate) { product_category_for_subtypes_ =
diff --git a/components/gcm_driver/fake_gcm_client.h b/components/gcm_driver/fake_gcm_client.h index d08e4e0..e1500d0 100644 --- a/components/gcm_driver/fake_gcm_client.h +++ b/components/gcm_driver/fake_gcm_client.h
@@ -48,6 +48,7 @@ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter, + const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory, std::unique_ptr<Encryptor> encryptor, Delegate* delegate) override; void Start(StartMode start_mode) override;
diff --git a/components/gcm_driver/gcm_client.h b/components/gcm_driver/gcm_client.h index 1dca141..79a7789 100644 --- a/components/gcm_driver/gcm_client.h +++ b/components/gcm_driver/gcm_client.h
@@ -30,6 +30,10 @@ class URLRequestContextGetter; } +namespace network { +class SharedURLLoaderFactory; +} + namespace gcm { struct AccountMapping; @@ -241,6 +245,7 @@ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter, + const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory, std::unique_ptr<Encryptor> encryptor, Delegate* delegate) = 0;
diff --git a/components/gcm_driver/gcm_client_impl.cc b/components/gcm_driver/gcm_client_impl.cc index 881cb82..be04384 100644 --- a/components/gcm_driver/gcm_client_impl.cc +++ b/components/gcm_driver/gcm_client_impl.cc
@@ -42,6 +42,7 @@ #include "google_apis/gcm/protocol/checkin.pb.h" #include "google_apis/gcm/protocol/mcs.pb.h" #include "net/url_request/url_request_context.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" #include "url/gurl.h" namespace gcm { @@ -331,6 +332,7 @@ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter, + const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory, std::unique_ptr<Encryptor> encryptor, GCMClient::Delegate* delegate) { DCHECK_EQ(UNINITIALIZED, state_); @@ -338,6 +340,7 @@ DCHECK(delegate); url_request_context_getter_ = url_request_context_getter; + url_loader_factory_ = url_loader_factory; chrome_build_info_ = chrome_build_info; gcm_store_.reset( @@ -974,7 +977,7 @@ std::move(request_handler), GetGCMBackoffPolicy(), base::Bind(&GCMClientImpl::OnRegisterCompleted, weak_ptr_factory_.GetWeakPtr(), registration_info), - kMaxRegistrationRetries, url_request_context_getter_, &recorder_, + kMaxRegistrationRetries, url_loader_factory_, &recorder_, source_to_record)); registration_request->Start(); pending_registration_requests_.insert(
diff --git a/components/gcm_driver/gcm_client_impl.h b/components/gcm_driver/gcm_client_impl.h index 3061f27..d2c730a3 100644 --- a/components/gcm_driver/gcm_client_impl.h +++ b/components/gcm_driver/gcm_client_impl.h
@@ -46,6 +46,10 @@ class URLRequestContext; } // namespace net +namespace network { +class SharedURLLoaderFactory; +} // namespace network + namespace gcm { class CheckinRequest; @@ -110,6 +114,7 @@ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner, const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter, + const scoped_refptr<network::SharedURLLoaderFactory>& url_loader_factory, std::unique_ptr<Encryptor> encryptor, GCMClient::Delegate* delegate) override; void Start(StartMode start_mode) override; @@ -365,6 +370,7 @@ std::unique_ptr<ConnectionFactory> connection_factory_; scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; // Controls receiving and sending of packets and reliable message queueing. // Must be destroyed before |network_session_|.
diff --git a/components/gcm_driver/gcm_client_impl_unittest.cc b/components/gcm_driver/gcm_client_impl_unittest.cc index df7f5e4..b9a3411 100644 --- a/components/gcm_driver/gcm_client_impl_unittest.cc +++ b/components/gcm_driver/gcm_client_impl_unittest.cc
@@ -21,7 +21,6 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_mock_time_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" #include "base/time/clock.h" #include "base/timer/timer.h" #include "components/gcm_driver/features.h" @@ -40,6 +39,9 @@ #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_fetcher_delegate.h" #include "net/url_request/url_request_test_util.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" +#include "services/network/test/test_utils.h" #include "testing/gtest/include/gtest/gtest-spi.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/leveldatabase/leveldb_chrome.h" @@ -81,6 +83,8 @@ const char kGroupName[] = "Enabled"; const char kInvalidateTokenTrialName[] = "InvalidateTokenTrial"; +const char kRegisterUrl[] = "https://android.clients.google.com/c2dm/register3"; + // Helper for building arbitrary data messages. MCSMessage BuildDownstreamMessage( const std::string& project_id, @@ -301,7 +305,6 @@ net::HttpStatusCode response_code); void CompleteRegistration(const std::string& registration_id); void CompleteUnregistration(const std::string& app_id); - void VerifyPendingRequestFetcherDeleted(); bool ExistsRegistration(const std::string& app_id) const; void AddRegistration(const std::string& app_id, @@ -402,6 +405,9 @@ net::TestURLFetcherFactory* url_fetcher_factory() { return &url_fetcher_factory_; } + network::TestURLLoaderFactory* url_loader_factory() { + return &test_url_loader_factory_; + } base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); } @@ -427,10 +433,10 @@ net::TestURLFetcherFactory url_fetcher_factory_; scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; - base::ThreadTaskRunnerHandle task_runner_handle_; // Injected to GCM client. scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_; + network::TestURLLoaderFactory test_url_loader_factory_; base::test::ScopedFeatureList scoped_feature_list_; base::FieldTrialList field_trial_list_; std::map<std::string, base::FieldTrial*> trials_; @@ -439,8 +445,8 @@ GCMClientImplTest::GCMClientImplTest() : last_event_(NONE), last_result_(GCMClient::UNKNOWN_ERROR), - task_runner_(new base::TestMockTimeTaskRunner), - task_runner_handle_(task_runner_), + task_runner_(new base::TestMockTimeTaskRunner( + base::TestMockTimeTaskRunner::Type::kBoundToThread)), url_request_context_getter_( new net::TestURLRequestContextGetter(task_runner_)), field_trial_list_(nullptr) {} @@ -573,11 +579,11 @@ const std::string& registration_id) { std::string response(kRegistrationResponsePrefix); response.append(registration_id); - net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0); - ASSERT_TRUE(fetcher); - fetcher->set_response_code(net::HTTP_OK); - fetcher->SetResponseString(response); - fetcher->delegate()->OnURLFetchComplete(fetcher); + + EXPECT_TRUE(url_loader_factory()->SimulateResponseForPendingRequest( + GURL(kRegisterUrl), network::URLLoaderCompletionStatus(net::OK), + network::CreateResourceResponseHead(net::HTTP_OK), response)); + // Give a chance for GCMStoreImpl::Backend to finish persisting data. PumpLoopUntilIdle(); } @@ -595,11 +601,6 @@ PumpLoopUntilIdle(); } -void GCMClientImplTest::VerifyPendingRequestFetcherDeleted() { - net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0); - EXPECT_FALSE(fetcher); -} - bool GCMClientImplTest::ExistsRegistration(const std::string& app_id) const { return ExistsGCMRegistrationInMap(gcm_client_->registrations_, app_id); } @@ -621,9 +622,12 @@ GCMClient::ChromeBuildInfo chrome_build_info; chrome_build_info.version = kChromeVersion; chrome_build_info.product_category_for_subtypes = kProductCategoryForSubtypes; - gcm_client_->Initialize(chrome_build_info, gcm_store_path(), task_runner_, - url_request_context_getter_, - base::WrapUnique<Encryptor>(new FakeEncryptor), this); + gcm_client_->Initialize( + chrome_build_info, gcm_store_path(), task_runner_, + url_request_context_getter_, + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_), + base::WrapUnique<Encryptor>(new FakeEncryptor), this); } void GCMClientImplTest::StartGCMClient() { @@ -1044,7 +1048,7 @@ gcm_client()->Stop(); PumpLoopUntilIdle(); - VerifyPendingRequestFetcherDeleted(); + EXPECT_EQ(0, url_loader_factory()->NumPending()); } TEST_F(GCMClientImplTest, DispatchDownstreamMessage) {
diff --git a/components/gcm_driver/gcm_driver_desktop.cc b/components/gcm_driver/gcm_driver_desktop.cc index f131e15..c8f6908a 100644 --- a/components/gcm_driver/gcm_driver_desktop.cc +++ b/components/gcm_driver/gcm_driver_desktop.cc
@@ -74,6 +74,7 @@ const GCMClient::ChromeBuildInfo& chrome_build_info, const base::FilePath& store_path, const scoped_refptr<net::URLRequestContextGetter>& request_context, + std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info, const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner); void Start(GCMClient::StartMode start_mode, const base::WeakPtr<GCMDriverDesktop>& service); @@ -145,14 +146,18 @@ const GCMClient::ChromeBuildInfo& chrome_build_info, const base::FilePath& store_path, const scoped_refptr<net::URLRequestContextGetter>& request_context, + std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info, const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) { DCHECK(io_thread_->RunsTasksInCurrentSequence()); gcm_client_ = gcm_client_factory->BuildInstance(); + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_for_io = + network::SharedURLLoaderFactory::Create(std::move(loader_factory_info)); + gcm_client_->Initialize(chrome_build_info, store_path, blocking_task_runner, - request_context, std::make_unique<SystemEncryptor>(), - this); + request_context, url_loader_factory_for_io, + std::make_unique<SystemEncryptor>(), this); } void GCMDriverDesktop::IOWorker::OnRegisterFinished( @@ -523,7 +528,7 @@ PrefService* prefs, const base::FilePath& store_path, const scoped_refptr<net::URLRequestContextGetter>& request_context, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_for_ui, const scoped_refptr<base::SequencedTaskRunner>& ui_thread, const scoped_refptr<base::SequencedTaskRunner>& io_thread, const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner) @@ -533,7 +538,7 @@ prefs, channel_status_request_url, user_agent, - url_loader_factory)), + url_loader_factory_for_ui)), signed_in_(false), gcm_started_(false), gcm_enabled_(true), @@ -557,7 +562,10 @@ base::BindOnce(&GCMDriverDesktop::IOWorker::Initialize, base::Unretained(io_worker_.get()), std::move(gcm_client_factory), chrome_build_info, - store_path, request_context, blocking_task_runner)); + store_path, request_context, + // ->Clone() permits creation of an equivalent + // SharedURLLoaderFactory on IO thread. + url_loader_factory_for_ui->Clone(), blocking_task_runner)); } GCMDriverDesktop::~GCMDriverDesktop() {
diff --git a/components/gcm_driver/gcm_driver_desktop.h b/components/gcm_driver/gcm_driver_desktop.h index fcca6a2..c2713e12 100644 --- a/components/gcm_driver/gcm_driver_desktop.h +++ b/components/gcm_driver/gcm_driver_desktop.h
@@ -58,7 +58,7 @@ PrefService* prefs, const base::FilePath& store_path, const scoped_refptr<net::URLRequestContextGetter>& request_context, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_for_ui, const scoped_refptr<base::SequencedTaskRunner>& ui_thread, const scoped_refptr<base::SequencedTaskRunner>& io_thread, const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner);
diff --git a/components/gcm_driver/gcm_driver_desktop_unittest.cc b/components/gcm_driver/gcm_driver_desktop_unittest.cc index 306d97f..3b90067 100644 --- a/components/gcm_driver/gcm_driver_desktop_unittest.cc +++ b/components/gcm_driver/gcm_driver_desktop_unittest.cc
@@ -34,6 +34,8 @@ #include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_test_util.h" #include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" namespace gcm { @@ -166,6 +168,8 @@ TestingPrefServiceSimple prefs_; base::MessageLoopForUI message_loop_; base::Thread io_thread_; + network::TestURLLoaderFactory test_url_loader_factory_; + std::unique_ptr<GCMDriverDesktop> driver_; std::unique_ptr<FakeGCMAppHandler> gcm_app_handler_; std::unique_ptr<FakeGCMConnectionObserver> gcm_connection_observer_; @@ -187,8 +191,7 @@ : io_thread_("IOThread"), registration_result_(GCMClient::UNKNOWN_ERROR), send_result_(GCMClient::UNKNOWN_ERROR), - unregistration_result_(GCMClient::UNKNOWN_ERROR) { -} + unregistration_result_(GCMClient::UNKNOWN_ERROR) {} GCMDriverTest::~GCMDriverTest() { } @@ -244,7 +247,9 @@ std::unique_ptr<GCMClientFactory>(new FakeGCMClientFactory( base::ThreadTaskRunnerHandle::Get(), io_thread_.task_runner())), chrome_build_info, kTestChannelStatusRequestURL, "user-agent-string", - &prefs_, temp_dir_.GetPath(), request_context, nullptr, + &prefs_, temp_dir_.GetPath(), request_context, + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_), base::ThreadTaskRunnerHandle::Get(), io_thread_.task_runner(), message_loop_.task_runner()));
diff --git a/components/mirroring/service/BUILD.gn b/components/mirroring/service/BUILD.gn index 7a3cfe4..1f9d28b 100644 --- a/components/mirroring/service/BUILD.gn +++ b/components/mirroring/service/BUILD.gn
@@ -18,6 +18,7 @@ "//media/capture/mojom:video_capture", "//media/cast:common", "//media/mojo/interfaces", + "//media/mojo/interfaces:remoting", "//net", "//services/network/public/mojom", ]
diff --git a/components/mirroring/service/interface.h b/components/mirroring/service/interface.h index eb44559..222b342 100644 --- a/components/mirroring/service/interface.h +++ b/components/mirroring/service/interface.h
@@ -11,6 +11,7 @@ #include "media/capture/mojom/video_capture.mojom.h" #include "media/mojo/interfaces/audio_data_pipe.mojom.h" #include "media/mojo/interfaces/audio_input_stream.mojom.h" +#include "media/mojo/interfaces/remoting.mojom.h" #include "net/base/ip_address.h" #include "services/network/public/mojom/network_service.mojom.h" @@ -100,11 +101,18 @@ virtual void GetVideoCaptureHost( media::mojom::VideoCaptureHostRequest request) = 0; + virtual void GetNetworkContext( network::mojom::NetworkContextRequest request) = 0; + virtual void CreateAudioStream(AudioStreamCreatorClient* client, const media::AudioParameters& params, uint32_t total_segments) = 0; + + virtual void ConnectToRemotingSource( + media::mojom::RemoterPtr remoter, + media::mojom::RemotingSourceRequest request) = 0; + // TODO(xjz): Add interface for HW encoder profiles query and VEA create // support. };
diff --git a/components/mirroring/service/message_dispatcher.cc b/components/mirroring/service/message_dispatcher.cc index aa5ad4a4..95cf380 100644 --- a/components/mirroring/service/message_dispatcher.cc +++ b/components/mirroring/service/message_dispatcher.cc
@@ -17,10 +17,7 @@ public: RequestHolder() {} - ~RequestHolder() { - if (!response_callback_.is_null()) - std::move(response_callback_).Run(ReceiverResponse()); - } + ~RequestHolder() {} void Start(const base::TimeDelta& timeout, int32_t sequence_number, @@ -134,6 +131,8 @@ OnceResponseCallback callback) { DCHECK(!callback.is_null()); DCHECK(timeout > base::TimeDelta()); + + Unsubscribe(response_type); // Cancel the old request if there is any. RequestHolder* const request_holder = new RequestHolder(); request_holder->Start( timeout, sequence_number,
diff --git a/components/mirroring/service/message_dispatcher.h b/components/mirroring/service/message_dispatcher.h index 7b2ee9b..7fbd3c5 100644 --- a/components/mirroring/service/message_dispatcher.h +++ b/components/mirroring/service/message_dispatcher.h
@@ -38,6 +38,8 @@ // delivered to the supplied callback if the sequence number of the response // matches |sequence_number|. If the timeout period elapses, the callback will // be run once with an unknown type of |response|. + // Note: Calling RequestReply() before a previous reply was made will cancel + // the previous request and not run its response callback. void RequestReply(const CastMessage& message, ResponseType response_type, int32_t sequence_number,
diff --git a/components/mirroring/service/message_dispatcher_unittest.cc b/components/mirroring/service/message_dispatcher_unittest.cc index 32cb732..184227de 100644 --- a/components/mirroring/service/message_dispatcher_unittest.cc +++ b/components/mirroring/service/message_dispatcher_unittest.cc
@@ -286,14 +286,11 @@ EXPECT_FALSE(last_answer_response_); EXPECT_FALSE(last_status_response_); - // Destroy the dispatcher. Expect to receive an unknown type response. + // Destroy the dispatcher. message_dispatcher_.reset(); scoped_task_environment_.RunUntilIdle(); - ASSERT_TRUE(last_answer_response_); + ASSERT_FALSE(last_answer_response_); EXPECT_FALSE(last_status_response_); - EXPECT_TRUE(last_error_message_.empty()); - EXPECT_EQ(ResponseType::UNKNOWN, last_answer_response_->type); - EXPECT_EQ(-1, last_answer_response_->sequence_number); } } // namespace mirroring
diff --git a/components/mirroring/service/session.cc b/components/mirroring/service/session.cc index 73fa22fc..f99169a 100644 --- a/components/mirroring/service/session.cc +++ b/components/mirroring/service/session.cc
@@ -46,6 +46,8 @@ using media::cast::PacketEvent; using media::cast::OperationalStatus; using media::cast::Packet; +using media::mojom::RemotingSinkAudioCapability; +using media::mojom::RemotingSinkVideoCapability; namespace mirroring { @@ -60,6 +62,11 @@ constexpr base::TimeDelta kOfferAnswerExchangeTimeout = base::TimeDelta::FromSeconds(15); +// Amount of time to wait before assuming the Cast Receiver does not support +// querying for capabilities via GET_CAPABILITIES. +constexpr base::TimeDelta kGetCapabilitiesTimeout = + base::TimeDelta::FromSeconds(30); + // Used for OFFER/ANSWER message exchange. Some receivers will error out on // payloadType values other than the ones hard-coded here. constexpr int kAudioPayloadType = 127; @@ -225,6 +232,87 @@ stream_list->emplace_back(std::move(stream)); } +// Checks whether receiver's build version is less than "1.|base_version|.xxxx". +// Returns false if given version doesn't have the format of "1.xx.xxxx". +bool NeedsWorkaroundForOlder1DotXVersions( + const std::string& receiver_build_version, + int base_version) { + if (!base::StartsWith(receiver_build_version, "1.", + base::CompareCase::SENSITIVE)) + return false; + const size_t end_pos = receiver_build_version.find_first_of('.', 2); + if (end_pos == std::string::npos) + return false; + int version = 0; + return (base::StringToInt(receiver_build_version.substr(2, end_pos - 2), + &version) && + version < base_version); +} + +// Convert the sink capabilities to media::mojom::RemotingSinkMetadata. +media::mojom::RemotingSinkMetadata ToRemotingSinkMetadata( + const std::vector<std::string>& capabilities, + const CastSinkInfo& sink_info, + const std::string& receiver_build_version) { + media::mojom::RemotingSinkMetadata sink_metadata; + sink_metadata.friendly_name = sink_info.friendly_name; + + for (const auto& capability : capabilities) { + if (capability == "audio") { + sink_metadata.audio_capabilities.push_back( + RemotingSinkAudioCapability::CODEC_BASELINE_SET); + } else if (capability == "aac") { + sink_metadata.audio_capabilities.push_back( + RemotingSinkAudioCapability::CODEC_AAC); + } else if (capability == "opus") { + sink_metadata.audio_capabilities.push_back( + RemotingSinkAudioCapability::CODEC_OPUS); + } else if (capability == "video") { + sink_metadata.video_capabilities.push_back( + RemotingSinkVideoCapability::CODEC_BASELINE_SET); + } else if (capability == "4k") { + sink_metadata.video_capabilities.push_back( + RemotingSinkVideoCapability::SUPPORT_4K); + } else if (capability == "h264") { + sink_metadata.video_capabilities.push_back( + RemotingSinkVideoCapability::CODEC_H264); + } else if (capability == "vp8") { + sink_metadata.video_capabilities.push_back( + RemotingSinkVideoCapability::CODEC_VP8); + } else if (capability == "vp9") { + // Before 1.27 Earth receivers report "vp9" even though they don't support + // remoting the VP9 encoded video. + if (!NeedsWorkaroundForOlder1DotXVersions(receiver_build_version, 27) || + base::StartsWith(sink_info.model_name, "Chromecast Ultra", + base::CompareCase::SENSITIVE)) { + sink_metadata.video_capabilities.push_back( + RemotingSinkVideoCapability::CODEC_VP9); + } + } else if (capability == "hevc") { + // Before 1.27 Earth receivers report "hevc" even though they don't + // support remoting the HEVC encoded video. + if (!NeedsWorkaroundForOlder1DotXVersions(receiver_build_version, 27) || + base::StartsWith(sink_info.model_name, "Chromecast Ultra", + base::CompareCase::SENSITIVE)) { + sink_metadata.video_capabilities.push_back( + RemotingSinkVideoCapability::CODEC_HEVC); + } + } else { + DVLOG(1) << "Unknown mediaCap name: " << capability; + } + } + + // Enable remoting 1080p 30fps or higher resolution/fps content for Chromecast + // Ultra receivers only. + // TODO(xjz): Receiver should report this capability. + if (sink_info.model_name == "Chromecast Ultra") { + sink_metadata.video_capabilities.push_back( + RemotingSinkVideoCapability::SUPPORT_4K); + } + + return sink_metadata; +} + } // namespace class Session::AudioCapturingCallback final @@ -283,6 +371,7 @@ CastMessageChannel* outbound_channel) : session_id_(session_id), sink_info_(sink_info), + state_(MIRRORING), observer_(observer), resource_provider_(resource_provider), message_dispatcher_(outbound_channel, @@ -294,8 +383,6 @@ max_resolution.height()); resource_provider_->GetNetworkContext(mojo::MakeRequest(&network_context_)); - auto wifi_status_monitor = - std::make_unique<WifiStatusMonitor>(session_id_, &message_dispatcher_); network::mojom::URLLoaderFactoryParamsPtr params = network::mojom::URLLoaderFactoryParams::New(); params->process_id = network::mojom::kBrowserProcessId; @@ -314,9 +401,9 @@ session_tags.SetKey("receiverProductName", base::Value(sink_info_.model_name)); - session_monitor_.emplace( - kMaxCrashReportBytes, sink_info_.ip_address, std::move(session_tags), - std::move(url_loader_factory), std::move(wifi_status_monitor)); + session_monitor_.emplace(kMaxCrashReportBytes, sink_info_.ip_address, + std::move(session_tags), + std::move(url_loader_factory)); CreateAndSendOffer(); } @@ -328,31 +415,48 @@ void Session::ReportError(SessionError error) { if (session_monitor_.has_value()) session_monitor_->OnStreamingError(error); + if (state_ == REMOTING) { + media_remoter_->OnRemotingFailed(); // Try to fallback on mirroring. + return; + } + + // Report the error and stop this session. if (observer_) observer_->OnError(error); StopSession(); } -void Session::StopSession() { - DVLOG(1) << __func__; - if (!resource_provider_) +void Session::StopStreaming() { + DVLOG(2) << __func__ << " state=" << state_; + if (!cast_environment_) return; session_monitor_->StopStreamingSession(); - session_monitor_.reset(); - weak_factory_.InvalidateWeakPtrs(); if (audio_input_device_) { audio_input_device_->Stop(); audio_input_device_ = nullptr; } audio_capturing_callback_.reset(); - audio_encode_thread_ = nullptr; - video_encode_thread_ = nullptr; - video_capture_client_.reset(); audio_stream_.reset(); video_stream_.reset(); cast_transport_.reset(); cast_environment_ = nullptr; +} + +void Session::StopSession() { + DVLOG(1) << __func__; + if (state_ == STOPPED) + return; + + state_ = STOPPED; + StopStreaming(); + + session_monitor_.reset(); + weak_factory_.InvalidateWeakPtrs(); + audio_encode_thread_ = nullptr; + video_encode_thread_ = nullptr; + video_capture_client_.reset(); + media_remoter_.reset(); resource_provider_ = nullptr; if (observer_) { observer_->DidStop(); @@ -448,10 +552,12 @@ std::move(packet_events)); } -void Session::OnAnswer(const std::string& cast_mode, - const std::vector<FrameSenderConfig>& audio_configs, +void Session::OnAnswer(const std::vector<FrameSenderConfig>& audio_configs, const std::vector<FrameSenderConfig>& video_configs, const ReceiverResponse& response) { + if (state_ == STOPPED) + return; + if (!response.answer || response.type == ResponseType::UNKNOWN) { ReportError(ANSWER_TIME_OUT); return; @@ -465,6 +571,8 @@ } const Answer& answer = *response.answer; + const std::string cast_mode = + (state_ == MIRRORING ? "mirroring" : "remoting"); if (answer.cast_mode != cast_mode) { ReportError(ANSWER_MISMATCHED_CAST_MODE); return; @@ -515,23 +623,19 @@ return; } - if ((has_audio && - audio_config.rtp_payload_type == RtpPayloadType::REMOTE_AUDIO) || - (has_video && - video_config.rtp_payload_type == RtpPayloadType::REMOTE_VIDEO)) { - NOTIMPLEMENTED(); // TODO(xjz): Add support for media remoting. - return; - } - // Start streaming. - audio_encode_thread_ = base::CreateSingleThreadTaskRunnerWithTraits( - {base::TaskPriority::USER_BLOCKING, - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, - base::SingleThreadTaskRunnerThreadMode::DEDICATED); - video_encode_thread_ = base::CreateSingleThreadTaskRunnerWithTraits( - {base::TaskPriority::USER_BLOCKING, - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, - base::SingleThreadTaskRunnerThreadMode::DEDICATED); + const bool initially_starting_session = + !audio_encode_thread_ && !video_encode_thread_; + if (initially_starting_session) { + audio_encode_thread_ = base::CreateSingleThreadTaskRunnerWithTraits( + {base::TaskPriority::USER_BLOCKING, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, + base::SingleThreadTaskRunnerThreadMode::DEDICATED); + video_encode_thread_ = base::CreateSingleThreadTaskRunnerWithTraits( + {base::TaskPriority::USER_BLOCKING, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, + base::SingleThreadTaskRunnerThreadMode::DEDICATED); + } cast_environment_ = new media::cast::CastEnvironment( base::DefaultTickClock::GetInstance(), base::ThreadTaskRunnerHandle::Get(), audio_encode_thread_, @@ -546,65 +650,98 @@ std::make_unique<TransportClient>(this), std::move(udp_client), base::ThreadTaskRunnerHandle::Get()); - if (has_audio) { - auto audio_sender = std::make_unique<media::cast::AudioSender>( - cast_environment_, audio_config, - base::BindRepeating(&Session::OnEncoderStatusChange, - weak_factory_.GetWeakPtr()), - cast_transport_.get()); - audio_stream_ = std::make_unique<AudioRtpStream>( - std::move(audio_sender), weak_factory_.GetWeakPtr()); - DCHECK(!audio_capturing_callback_); - // TODO(xjz): Elliminate the thread hops. The audio data is thread-hopped - // from the audio thread, and later thread-hopped again to the encoding - // thread. - audio_capturing_callback_ = std::make_unique<AudioCapturingCallback>( - media::BindToCurrentLoop(base::BindRepeating( - &AudioRtpStream::InsertAudio, audio_stream_->AsWeakPtr())), - base::BindOnce(&Session::ReportError, weak_factory_.GetWeakPtr(), - SessionError::AUDIO_CAPTURE_ERROR)); - audio_input_device_ = new media::AudioInputDevice( - std::make_unique<CapturedAudioInput>(base::BindRepeating( - &Session::CreateAudioStream, base::Unretained(this))), - base::ThreadPriority::NORMAL); - audio_input_device_->Initialize(mirror_settings_.GetAudioCaptureParams(), - audio_capturing_callback_.get()); - audio_input_device_->Start(); + if (state_ == REMOTING) { + DCHECK(media_remoter_); + DCHECK(audio_config.rtp_payload_type == RtpPayloadType::REMOTE_AUDIO || + video_config.rtp_payload_type == RtpPayloadType::REMOTE_VIDEO); + media_remoter_->StartRpcMessaging(cast_environment_, cast_transport_.get(), + audio_config, video_config); + } else /* MIRRORING */ { + if (has_audio) { + auto audio_sender = std::make_unique<media::cast::AudioSender>( + cast_environment_, audio_config, + base::BindRepeating(&Session::OnEncoderStatusChange, + weak_factory_.GetWeakPtr()), + cast_transport_.get()); + audio_stream_ = std::make_unique<AudioRtpStream>( + std::move(audio_sender), weak_factory_.GetWeakPtr()); + DCHECK(!audio_capturing_callback_); + // TODO(xjz): Elliminate the thread hops. The audio data is thread-hopped + // from the audio thread, and later thread-hopped again to the encoding + // thread. + audio_capturing_callback_ = std::make_unique<AudioCapturingCallback>( + media::BindToCurrentLoop(base::BindRepeating( + &AudioRtpStream::InsertAudio, audio_stream_->AsWeakPtr())), + base::BindOnce(&Session::ReportError, weak_factory_.GetWeakPtr(), + SessionError::AUDIO_CAPTURE_ERROR)); + audio_input_device_ = new media::AudioInputDevice( + std::make_unique<CapturedAudioInput>(base::BindRepeating( + &Session::CreateAudioStream, base::Unretained(this))), + base::ThreadPriority::NORMAL); + audio_input_device_->Initialize(mirror_settings_.GetAudioCaptureParams(), + audio_capturing_callback_.get()); + audio_input_device_->Start(); + } + + if (has_video) { + auto video_sender = std::make_unique<media::cast::VideoSender>( + cast_environment_, video_config, + base::BindRepeating(&Session::OnEncoderStatusChange, + weak_factory_.GetWeakPtr()), + base::BindRepeating(&Session::CreateVideoEncodeAccelerator, + weak_factory_.GetWeakPtr()), + base::BindRepeating(&Session::CreateVideoEncodeMemory, + weak_factory_.GetWeakPtr()), + cast_transport_.get(), + base::BindRepeating(&Session::SetTargetPlayoutDelay, + weak_factory_.GetWeakPtr())); + video_stream_ = std::make_unique<VideoRtpStream>( + std::move(video_sender), weak_factory_.GetWeakPtr()); + if (!video_capture_client_) { + media::mojom::VideoCaptureHostPtr video_host; + resource_provider_->GetVideoCaptureHost(mojo::MakeRequest(&video_host)); + video_capture_client_ = std::make_unique<VideoCaptureClient>( + mirror_settings_.GetVideoCaptureParams(), std::move(video_host)); + video_capture_client_->Start( + base::BindRepeating(&VideoRtpStream::InsertVideoFrame, + video_stream_->AsWeakPtr()), + base::BindOnce(&Session::ReportError, weak_factory_.GetWeakPtr(), + SessionError::VIDEO_CAPTURE_ERROR)); + } else { + video_capture_client_->Resume(base::BindRepeating( + &VideoRtpStream::InsertVideoFrame, video_stream_->AsWeakPtr())); + } + } + if (media_remoter_) + media_remoter_->OnMirroringResumed(); } - if (has_video) { - auto video_sender = std::make_unique<media::cast::VideoSender>( - cast_environment_, video_config, - base::BindRepeating(&Session::OnEncoderStatusChange, - weak_factory_.GetWeakPtr()), - base::BindRepeating(&Session::CreateVideoEncodeAccelerator, - weak_factory_.GetWeakPtr()), - base::BindRepeating(&Session::CreateVideoEncodeMemory, - weak_factory_.GetWeakPtr()), - cast_transport_.get(), - base::BindRepeating(&Session::SetTargetPlayoutDelay, - weak_factory_.GetWeakPtr())); - video_stream_ = std::make_unique<VideoRtpStream>( - std::move(video_sender), weak_factory_.GetWeakPtr()); - media::mojom::VideoCaptureHostPtr video_host; - resource_provider_->GetVideoCaptureHost(mojo::MakeRequest(&video_host)); - video_capture_client_ = std::make_unique<VideoCaptureClient>( - mirror_settings_.GetVideoCaptureParams(), std::move(video_host)); - video_capture_client_->Start( - base::BindRepeating(&VideoRtpStream::InsertVideoFrame, - video_stream_->AsWeakPtr()), - base::BindOnce(&Session::ReportError, weak_factory_.GetWeakPtr(), - SessionError::VIDEO_CAPTURE_ERROR)); - } - + DCHECK(session_monitor_.has_value()); const SessionMonitor::SessionType session_type = (has_audio && has_video) ? SessionMonitor::AUDIO_AND_VIDEO : has_audio ? SessionMonitor::AUDIO_ONLY : SessionMonitor::VIDEO_ONLY; - session_monitor_->StartStreamingSession(cast_environment_, session_type, - false /* is_remoting */); + std::unique_ptr<WifiStatusMonitor> wifi_status_monitor; + if (answer.supports_get_status) { + wifi_status_monitor = + std::make_unique<WifiStatusMonitor>(session_id_, &message_dispatcher_); + // Before 1.28 Android TV Chromecast receivers respond to GET_CAPABILITIES + // even though they don't support remoting. + if (initially_starting_session && + (!NeedsWorkaroundForOlder1DotXVersions( + session_monitor_->GetReceiverBuildVersion(), 28) || + base::StartsWith(sink_info_.model_name, "Chromecast", + base::CompareCase::SENSITIVE) || + base::StartsWith(sink_info_.model_name, "Eureka Dongle", + base::CompareCase::SENSITIVE))) { + QueryCapabilitiesForRemoting(); + } + } + session_monitor_->StartStreamingSession(cast_environment_, + std::move(wifi_status_monitor), + session_type, state_ == REMOTING); - if (observer_) + if (initially_starting_session && observer_) observer_->DidStart(); } @@ -626,6 +763,8 @@ } void Session::CreateAndSendOffer() { + DCHECK(state_ != STOPPED); + // The random AES key and initialization vector pair used by all streams in // this session. const std::string aes_key = MakeRandomString(16); // AES-128. @@ -637,46 +776,62 @@ base::Value::ListStorage stream_list; int stream_index = 0; if (sink_info_.capability != DeviceCapability::VIDEO_ONLY) { - FrameSenderConfig config = MirrorSettings::GetDefaultAudioConfig( - RtpPayloadType::AUDIO_OPUS, Codec::CODEC_AUDIO_OPUS); - AddSenderConfig(base::RandInt(kAudioSsrcMin, kAudioSsrcMax), config, - aes_key, aes_iv, &audio_configs); - AddStreamObject(stream_index++, "OPUS", audio_configs.back(), - mirror_settings_, &stream_list); + const int32_t audio_ssrc = base::RandInt(kAudioSsrcMin, kAudioSsrcMax); + if (state_ == MIRRORING) { + FrameSenderConfig config = MirrorSettings::GetDefaultAudioConfig( + RtpPayloadType::AUDIO_OPUS, Codec::CODEC_AUDIO_OPUS); + AddSenderConfig(audio_ssrc, config, aes_key, aes_iv, &audio_configs); + AddStreamObject(stream_index++, "OPUS", audio_configs.back(), + mirror_settings_, &stream_list); + } else /* REMOTING */ { + FrameSenderConfig config = MirrorSettings::GetDefaultAudioConfig( + RtpPayloadType::REMOTE_AUDIO, Codec::CODEC_AUDIO_REMOTE); + AddSenderConfig(audio_ssrc, config, aes_key, aes_iv, &audio_configs); + AddStreamObject(stream_index++, "REMOTE_AUDIO", audio_configs.back(), + mirror_settings_, &stream_list); + } } if (sink_info_.capability != DeviceCapability::AUDIO_ONLY) { const int32_t video_ssrc = base::RandInt(kVideoSsrcMin, kVideoSsrcMax); - if (IsHardwareVP8EncodingSupported(GetSupportedVeaProfiles())) { + if (state_ == MIRRORING) { + if (IsHardwareVP8EncodingSupported(GetSupportedVeaProfiles())) { + FrameSenderConfig config = MirrorSettings::GetDefaultVideoConfig( + RtpPayloadType::VIDEO_VP8, Codec::CODEC_VIDEO_VP8); + config.use_external_encoder = true; + AddSenderConfig(video_ssrc, config, aes_key, aes_iv, &video_configs); + AddStreamObject(stream_index++, "VP8", video_configs.back(), + mirror_settings_, &stream_list); + } + if (IsHardwareH264EncodingSupported(GetSupportedVeaProfiles())) { + FrameSenderConfig config = MirrorSettings::GetDefaultVideoConfig( + RtpPayloadType::VIDEO_H264, Codec::CODEC_VIDEO_H264); + config.use_external_encoder = true; + AddSenderConfig(video_ssrc, config, aes_key, aes_iv, &video_configs); + AddStreamObject(stream_index++, "H264", video_configs.back(), + mirror_settings_, &stream_list); + } + if (video_configs.empty()) { + FrameSenderConfig config = MirrorSettings::GetDefaultVideoConfig( + RtpPayloadType::VIDEO_VP8, Codec::CODEC_VIDEO_VP8); + AddSenderConfig(video_ssrc, config, aes_key, aes_iv, &video_configs); + AddStreamObject(stream_index++, "VP8", video_configs.back(), + mirror_settings_, &stream_list); + } + } else /* REMOTING */ { FrameSenderConfig config = MirrorSettings::GetDefaultVideoConfig( - RtpPayloadType::VIDEO_VP8, Codec::CODEC_VIDEO_VP8); - config.use_external_encoder = true; + RtpPayloadType::REMOTE_VIDEO, Codec::CODEC_VIDEO_REMOTE); AddSenderConfig(video_ssrc, config, aes_key, aes_iv, &video_configs); - AddStreamObject(stream_index++, "VP8", video_configs.back(), - mirror_settings_, &stream_list); - } - if (IsHardwareH264EncodingSupported(GetSupportedVeaProfiles())) { - FrameSenderConfig config = MirrorSettings::GetDefaultVideoConfig( - RtpPayloadType::VIDEO_H264, Codec::CODEC_VIDEO_H264); - config.use_external_encoder = true; - AddSenderConfig(video_ssrc, config, aes_key, aes_iv, &video_configs); - AddStreamObject(stream_index++, "H264", video_configs.back(), - mirror_settings_, &stream_list); - } - if (video_configs.empty()) { - FrameSenderConfig config = MirrorSettings::GetDefaultVideoConfig( - RtpPayloadType::VIDEO_VP8, Codec::CODEC_VIDEO_VP8); - AddSenderConfig(video_ssrc, config, aes_key, aes_iv, &video_configs); - AddStreamObject(stream_index++, "VP8", video_configs.back(), + AddStreamObject(stream_index++, "REMOTE_VIDEO", video_configs.back(), mirror_settings_, &stream_list); } } DCHECK(!audio_configs.empty() || !video_configs.empty()); // Assemble the OFFER message. - const std::string cast_mode = "mirroring"; base::Value offer(base::Value::Type::DICTIONARY); - offer.SetKey("castMode", base::Value(cast_mode)); - offer.SetKey("receiverGetStatus", base::Value("true")); + offer.SetKey("castMode", + base::Value(state_ == MIRRORING ? "mirroring" : "remoting")); + offer.SetKey("receiverGetStatus", base::Value(true)); offer.SetKey("supportedStreams", base::Value(stream_list)); const int32_t sequence_number = message_dispatcher_.GetNextSeqNumber(); @@ -695,8 +850,75 @@ message_dispatcher_.RequestReply( message_to_receiver, ResponseType::ANSWER, sequence_number, kOfferAnswerExchangeTimeout, - base::BindOnce(&Session::OnAnswer, base::Unretained(this), cast_mode, - audio_configs, video_configs)); + base::BindOnce(&Session::OnAnswer, base::Unretained(this), audio_configs, + video_configs)); +} + +void Session::ConnectToRemotingSource( + media::mojom::RemoterPtr remoter, + media::mojom::RemotingSourceRequest request) { + resource_provider_->ConnectToRemotingSource(std::move(remoter), + std::move(request)); +} + +void Session::RequestRemotingStreaming() { + DCHECK(media_remoter_); + DCHECK_EQ(MIRRORING, state_); + if (video_capture_client_) + video_capture_client_->Pause(); + StopStreaming(); + state_ = REMOTING; + CreateAndSendOffer(); +} + +void Session::RestartMirroringStreaming() { + if (state_ != REMOTING) + return; + StopStreaming(); + state_ = MIRRORING; + CreateAndSendOffer(); +} + +void Session::QueryCapabilitiesForRemoting() { + DCHECK(!media_remoter_); + const int32_t sequence_number = message_dispatcher_.GetNextSeqNumber(); + base::Value query(base::Value::Type::DICTIONARY); + query.SetKey("type", base::Value("GET_CAPABILITIES")); + query.SetKey("sessionId", base::Value(session_id_)); + query.SetKey("seqNum", base::Value(sequence_number)); + + CastMessage query_message; + query_message.message_namespace = kWebRtcNamespace; + const bool did_serialize_query = + base::JSONWriter::Write(query, &query_message.json_format_data); + DCHECK(did_serialize_query); + message_dispatcher_.RequestReply( + query_message, ResponseType::CAPABILITIES_RESPONSE, sequence_number, + kGetCapabilitiesTimeout, + base::BindOnce(&Session::OnCapabilitiesResponse, base::Unretained(this))); +} + +void Session::OnCapabilitiesResponse(const ReceiverResponse& response) { + if (!response.capabilities || response.type == ResponseType::UNKNOWN) { + VLOG(1) << "Receiver doens't support GET_CAPABILITIES. Remoting disabled."; + return; + } + if (response.result != "ok") { + VLOG(1) << "Bad CAPABILITIES_RESPONSE. Remoting disabled."; + if (response.error) { + VLOG(1) << "error code=" << response.error->code + << " description=" << response.error->description + << " details=" << response.error->details; + } + return; + } + const std::vector<std::string>& caps = response.capabilities->media_caps; + const std::string receiver_build_version = + session_monitor_.has_value() ? session_monitor_->GetReceiverBuildVersion() + : ""; + media_remoter_ = std::make_unique<MediaRemoter>( + this, ToRemotingSinkMetadata(caps, sink_info_, receiver_build_version), + &message_dispatcher_); } } // namespace mirroring
diff --git a/components/mirroring/service/session.h b/components/mirroring/service/session.h index b1b061a..41c21c3 100644 --- a/components/mirroring/service/session.h +++ b/components/mirroring/service/session.h
@@ -9,6 +9,7 @@ #include "base/optional.h" #include "base/single_thread_task_runner.h" #include "components/mirroring/service/interface.h" +#include "components/mirroring/service/media_remoter.h" #include "components/mirroring/service/message_dispatcher.h" #include "components/mirroring/service/mirror_settings.h" #include "components/mirroring/service/rtp_stream.h" @@ -33,13 +34,14 @@ class VideoCaptureClient; class SessionMonitor; -// Controls a mirroring session, including audio/video capturing and Cast -// Streaming. When constructed, it does OFFER/ANSWER exchange with the mirroring -// receiver. Mirroring starts when the exchange succeeds and stops when this -// class is destructed or error occurs. |observer| will get notified when status -// changes. |outbound_channel| is responsible for sending messages to the -// mirroring receiver through Cast Channel. -class Session final : public RtpStreamClient { +// Controls a mirroring session, including audio/video capturing, Cast +// Streaming, and the switching to/from media remoting. When constructed, it +// does OFFER/ANSWER exchange with the mirroring receiver. Mirroring starts when +// the exchange succeeds and stops when this class is destructed or error +// occurs. |observer| will get notified when status changes. |outbound_channel| +// is responsible for sending messages to the mirroring receiver through Cast +// Channel. +class Session final : public RtpStreamClient, public MediaRemoter::Client { public: Session(int32_t session_id, const CastSinkInfo& sink_info, @@ -72,7 +74,6 @@ // get notified with error, and session is stopped. Otherwise, capturing and // streaming are started with the selected configs. void OnAnswer( - const std::string& cast_mode, const std::vector<media::cast::FrameSenderConfig>& audio_configs, const std::vector<media::cast::FrameSenderConfig>& video_configs, const ReceiverResponse& response); @@ -87,10 +88,30 @@ const media::AudioParameters& params, uint32_t shared_memory_count); + // Callback for CAPABILITIES_RESPONSE. + void OnCapabilitiesResponse(const ReceiverResponse& response); + private: + // To allow the test code access the |message_dispatcher_|. + // TODO(xjz): Remove this after adding the inbound message channel argument. + friend class SessionTest; + class AudioCapturingCallback; - void StopSession(); + // MediaRemoter::Client implementation. + void ConnectToRemotingSource( + media::mojom::RemoterPtr remoter, + media::mojom::RemotingSourceRequest source_request) override; + void RequestRemotingStreaming() override; + void RestartMirroringStreaming() override; + + // Stops the current streaming session. If not called from StopSession(), a + // new streaming session will start later after exchanging OFFER/ANSWER + // messages with the receiver. This could happen any number of times before + // StopSession() shuts down everything permanently. + void StopStreaming(); + + void StopSession(); // Shuts down the entire mirroring session. // Notify |observer_| that error occurred and close the session. void ReportError(SessionError error); @@ -106,10 +127,23 @@ // Create and send OFFER message. void CreateAndSendOffer(); + // Send GET_CAPABILITIES message. + void QueryCapabilitiesForRemoting(); + // Provided by Cast Media Route Provider (MRP). const int32_t session_id_; const CastSinkInfo sink_info_; + // State transition: + // MIRRORING <-------> REMOTING + // | | + // .---> STOPPED <----. + enum { + MIRRORING, // A mirroring streaming session is starting or started. + REMOTING, // A remoting streaming session is starting or started. + STOPPED, // The session is stopped due to user's request or errors. + } state_; + SessionObserver* observer_ = nullptr; ResourceProvider* resource_provider_ = nullptr; MirrorSettings mirror_settings_; @@ -130,6 +164,7 @@ scoped_refptr<base::SingleThreadTaskRunner> video_encode_thread_ = nullptr; std::unique_ptr<AudioCapturingCallback> audio_capturing_callback_; scoped_refptr<media::AudioInputDevice> audio_input_device_; + std::unique_ptr<MediaRemoter> media_remoter_; base::WeakPtrFactory<Session> weak_factory_; };
diff --git a/components/mirroring/service/session_monitor.cc b/components/mirroring/service/session_monitor.cc index 94e6d774..82d05b52 100644 --- a/components/mirroring/service/session_monitor.cc +++ b/components/mirroring/service/session_monitor.cc
@@ -105,25 +105,27 @@ int max_retention_bytes, const net::IPAddress& receiver_address, base::Value session_tags, - network::mojom::URLLoaderFactoryPtr loader_factory, - std::unique_ptr<WifiStatusMonitor> wifi_status_monitor) + network::mojom::URLLoaderFactoryPtr loader_factory) : max_retention_bytes_(max_retention_bytes), receiver_address_(receiver_address), session_tags_(std::move(session_tags)), url_loader_factory_(std::move(loader_factory)), - wifi_status_monitor_(std::move(wifi_status_monitor)), stored_snapshots_bytes_(0), - weak_factory_(this) {} + weak_factory_(this) { + QueryReceiverSetupInfo(); +} SessionMonitor::~SessionMonitor() {} void SessionMonitor::StartStreamingSession( scoped_refptr<media::cast::CastEnvironment> cast_environment, + std::unique_ptr<WifiStatusMonitor> wifi_status_monitor, SessionType session_type, bool is_remoting) { DCHECK(!event_subscribers_); DCHECK(!snapshot_timer_.IsRunning()); + wifi_status_monitor_ = std::move(wifi_status_monitor); std::string session_activity = session_type == AUDIO_AND_VIDEO ? "audio+video" @@ -156,6 +158,7 @@ TakeSnapshot(); // Final snapshot of this streaming session. } event_subscribers_.reset(); + wifi_status_monitor_.reset(); } void SessionMonitor::OnStreamingError(SessionError error) { @@ -305,6 +308,12 @@ stored_snapshots_bytes_ = snapshots_bytes; } +std::string SessionMonitor::GetReceiverBuildVersion() const { + std::string build_version; + GetString(session_tags_, "receiverVersion", &build_version); + return build_version; +} + std::string SessionMonitor::GetEventLogsAndReset( bool is_audio, const std::string& extra_data) {
diff --git a/components/mirroring/service/session_monitor.h b/components/mirroring/service/session_monitor.h index ba48923..a6e27fb7 100644 --- a/components/mirroring/service/session_monitor.h +++ b/components/mirroring/service/session_monitor.h
@@ -56,8 +56,7 @@ SessionMonitor(int max_retention_bytes, const net::IPAddress& receiver_address, base::Value session_tags, - network::mojom::URLLoaderFactoryPtr loader_factory, - std::unique_ptr<WifiStatusMonitor> wifi_status_monitor); + network::mojom::URLLoaderFactoryPtr loader_factory); ~SessionMonitor(); @@ -71,6 +70,7 @@ // events/stats. void StartStreamingSession( scoped_refptr<media::cast::CastEnvironment> cast_environment, + std::unique_ptr<WifiStatusMonitor> wifi_status_monitor, SessionType session_type, bool is_remoting); void StopStreamingSession(); @@ -91,6 +91,8 @@ // Takes a snapshot of recent Cast Streaming events and statistics. void TakeSnapshot(); + std::string GetReceiverBuildVersion() const; + private: // Query the receiver for its current setup and uptime. void QueryReceiverSetupInfo(); @@ -113,7 +115,7 @@ network::mojom::URLLoaderFactoryPtr url_loader_factory_; // Monitors the WiFi status if not null. - const std::unique_ptr<WifiStatusMonitor> wifi_status_monitor_; + std::unique_ptr<WifiStatusMonitor> wifi_status_monitor_; std::unique_ptr<media::cast::RawEventSubscriberBundle> event_subscribers_;
diff --git a/components/mirroring/service/session_monitor_unittest.cc b/components/mirroring/service/session_monitor_unittest.cc index c887eaa..93792e5 100644 --- a/components/mirroring/service/session_monitor_unittest.cc +++ b/components/mirroring/service/session_monitor_unittest.cc
@@ -92,8 +92,6 @@ void CreateSessionMonitor(int max_bytes, std::string* expected_settings) { EXPECT_CALL(*this, Send(::testing::_)).Times(::testing::AtLeast(1)); - auto wifi_status_monitor = - std::make_unique<WifiStatusMonitor>(123, &message_dispatcher_); network::mojom::URLLoaderFactoryPtr url_loader_factory; auto test_url_loader_factory = std::make_unique<network::TestURLLoaderFactory>(); @@ -111,7 +109,7 @@ session_tags.SetKey("shouldCaptureVideo", base::Value(true)); session_monitor_ = std::make_unique<SessionMonitor>( max_bytes, receiver_address_, std::move(session_tags), - std::move(url_loader_factory), std::move(wifi_status_monitor)); + std::move(url_loader_factory)); } // Generates and sends |num_of_responses| WiFi status. @@ -148,9 +146,11 @@ scoped_task_environment_.GetMainThreadTaskRunner(), scoped_task_environment_.GetMainThreadTaskRunner()); EXPECT_TRUE(session_monitor_); - session_monitor_->StartStreamingSession(cast_environment_, - SessionMonitor::AUDIO_AND_VIDEO, - false /* is_remoting */); + auto wifi_status_monitor = + std::make_unique<WifiStatusMonitor>(123, &message_dispatcher_); + session_monitor_->StartStreamingSession( + cast_environment_, std::move(wifi_status_monitor), + SessionMonitor::AUDIO_AND_VIDEO, false /* is_remoting */); scoped_task_environment_.RunUntilIdle(); } @@ -220,8 +220,8 @@ TEST_F(SessionMonitorTest, ProvidesExpectedTags) { std::string expected_settings; CreateSessionMonitor(kRetentionBytes, &expected_settings); - SendWifiStatus(34, 2000, 5); StartStreamingSession(); + SendWifiStatus(34, 2000, 5); std::vector<int32_t> bundle_sizes({kRetentionBytes}); std::vector<SessionMonitor::EventsAndStats> bundles = AssembleBundleAndVerify(bundle_sizes); @@ -271,11 +271,11 @@ // 2500 is an estimate number of bytes for a snapshot that includes tags and // five WiFi status records. CreateSessionMonitor(2500, nullptr); + StartStreamingSession(); SendWifiStatus(34, 2000, 5); - StartStreamingSession(); StopStreamingSession(); - SendWifiStatus(54, 3000, 5); StartStreamingSession(); + SendWifiStatus(54, 3000, 5); StopStreamingSession(); std::vector<int32_t> bundle_sizes({kRetentionBytes}); std::vector<SessionMonitor::EventsAndStats> bundles = @@ -289,11 +289,11 @@ TEST_F(SessionMonitorTest, AssembleBundlesWithVaryingSizes) { CreateSessionMonitor(kRetentionBytes, nullptr); + StartStreamingSession(); SendWifiStatus(34, 2000, 5); - StartStreamingSession(); StopStreamingSession(); - SendWifiStatus(54, 3000, 5); StartStreamingSession(); + SendWifiStatus(54, 3000, 5); StopStreamingSession(); std::vector<int32_t> bundle_sizes({2500, kRetentionBytes}); std::vector<SessionMonitor::EventsAndStats> bundles =
diff --git a/components/mirroring/service/session_unittest.cc b/components/mirroring/service/session_unittest.cc index 8a20bdbd..7443fb6 100644 --- a/components/mirroring/service/session_unittest.cc +++ b/components/mirroring/service/session_unittest.cc
@@ -27,13 +27,46 @@ using ::testing::InvokeWithoutArgs; using ::testing::_; +using ::testing::AtLeast; +using ::testing::Mock; using media::cast::FrameSenderConfig; using media::cast::Packet; +using media::mojom::RemotingStopReason; +using media::mojom::RemotingStartFailReason; +using media::mojom::RemotingSinkMetadata; +using media::mojom::RemotingSinkMetadataPtr; namespace mirroring { +namespace { + const int kSessionId = 5; +class MockRemotingSource final : public media::mojom::RemotingSource { + public: + MockRemotingSource() : binding_(this) {} + ~MockRemotingSource() override {} + + void Bind(media::mojom::RemotingSourceRequest request) { + binding_.Bind(std::move(request)); + } + + MOCK_METHOD0(OnSinkGone, void()); + MOCK_METHOD0(OnStarted, void()); + MOCK_METHOD1(OnStartFailed, void(RemotingStartFailReason)); + MOCK_METHOD1(OnMessageFromSink, void(const std::vector<uint8_t>&)); + MOCK_METHOD1(OnStopped, void(RemotingStopReason)); + MOCK_METHOD1(OnSinkAvailable, void(const RemotingSinkMetadata&)); + void OnSinkAvailable(RemotingSinkMetadataPtr metadata) override { + OnSinkAvailable(*metadata); + } + + private: + mojo::Binding<media::mojom::RemotingSource> binding_; +}; + +} // namespace + class SessionTest : public ResourceProvider, public SessionObserver, public CastMessageChannel, @@ -49,13 +82,13 @@ MOCK_METHOD0(DidStart, void()); MOCK_METHOD0(DidStop, void()); - // ResourceProvider implemenation. MOCK_METHOD0(OnGetVideoCaptureHost, void()); MOCK_METHOD0(OnGetNetworkContext, void()); MOCK_METHOD0(OnCreateAudioStream, void()); + MOCK_METHOD0(OnConnectToRemotingSource, void()); - // Called when sends OFFER message. - MOCK_METHOD0(OnOffer, void()); + // Called when sends an outbound message. + MOCK_METHOD1(OnOutboundMessage, void(const std::string& message_type)); // CastMessageHandler implementation. For outbound messages. void Send(const CastMessage& message) { @@ -68,10 +101,13 @@ EXPECT_TRUE(GetString(*value, "type", &message_type)); if (message_type == "OFFER") { EXPECT_TRUE(GetInt(*value, "seqNum", &offer_sequence_number_)); - OnOffer(); + } else if (message_type == "GET_CAPABILITIES") { + EXPECT_TRUE(GetInt(*value, "seqNum", &capability_sequence_number_)); } + OnOutboundMessage(message_type); } + // ResourceProvider implemenation. void GetVideoCaptureHost( media::mojom::VideoCaptureHostRequest request) override { video_host_ = std::make_unique<FakeVideoCaptureHost>(std::move(request)); @@ -95,21 +131,34 @@ std::vector<FrameSenderConfig> audio_configs; std::vector<FrameSenderConfig> video_configs; if (sink_capability_ != DeviceCapability::VIDEO_ONLY) { - FrameSenderConfig audio_config = MirrorSettings::GetDefaultAudioConfig( - media::cast::RtpPayloadType::AUDIO_OPUS, - media::cast::Codec::CODEC_AUDIO_OPUS); - audio_configs.emplace_back(audio_config); + if (cast_mode_ == "remoting") { + audio_configs.emplace_back(MirrorSettings::GetDefaultAudioConfig( + media::cast::RtpPayloadType::REMOTE_AUDIO, + media::cast::Codec::CODEC_AUDIO_REMOTE)); + } else { + EXPECT_EQ("mirroring", cast_mode_); + audio_configs.emplace_back(MirrorSettings::GetDefaultAudioConfig( + media::cast::RtpPayloadType::AUDIO_OPUS, + media::cast::Codec::CODEC_AUDIO_OPUS)); + } } if (sink_capability_ != DeviceCapability::AUDIO_ONLY) { - FrameSenderConfig video_config = MirrorSettings::GetDefaultVideoConfig( - media::cast::RtpPayloadType::VIDEO_VP8, - media::cast::Codec::CODEC_VIDEO_VP8); - video_configs.emplace_back(video_config); + if (cast_mode_ == "remoting") { + video_configs.emplace_back(MirrorSettings::GetDefaultVideoConfig( + media::cast::RtpPayloadType::REMOTE_VIDEO, + media::cast::Codec::CODEC_VIDEO_REMOTE)); + } else { + EXPECT_EQ("mirroring", cast_mode_); + video_configs.emplace_back(MirrorSettings::GetDefaultVideoConfig( + media::cast::RtpPayloadType::VIDEO_VP8, + media::cast::Codec::CODEC_VIDEO_VP8)); + } } auto answer = std::make_unique<Answer>(); answer->udp_port = receiver_endpoint_.port(); - answer->cast_mode = "mirroring"; + answer->cast_mode = cast_mode_; + answer->supports_get_status = true; const int number_of_configs = audio_configs.size() + video_configs.size(); for (int i = 0; i < number_of_configs; ++i) { answer->send_indexes.push_back(i); @@ -122,28 +171,40 @@ response.sequence_number = offer_sequence_number_; response.answer = std::move(answer); - session_->OnAnswer("mirroring", audio_configs, video_configs, response); + session_->OnAnswer(audio_configs, video_configs, response); + scoped_task_environment_.RunUntilIdle(); } + void ConnectToRemotingSource( + media::mojom::RemoterPtr remoter, + media::mojom::RemotingSourceRequest request) override { + remoter_ = std::move(remoter); + remoting_source_.Bind(std::move(request)); + OnConnectToRemotingSource(); + } + + // Create a mirroring session. Expect to send OFFER message. void CreateSession(DeviceCapability sink_capability) { sink_capability_ = sink_capability; CastSinkInfo sink_info; sink_info.ip_address = receiver_endpoint_.address(); sink_info.capability = sink_capability_; - // Expect to receive OFFER message when session is created. - base::RunLoop run_loop; + sink_info.model_name = "Chromecast"; + cast_mode_ = "mirroring"; + // Expect to send OFFER message when session is created. EXPECT_CALL(*this, OnGetNetworkContext()).Times(1); EXPECT_CALL(*this, OnError(_)).Times(0); - EXPECT_CALL(*this, OnOffer()) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); + EXPECT_CALL(*this, OnOutboundMessage("OFFER")).Times(1); session_ = std::make_unique<Session>( kSessionId, sink_info, gfx::Size(1920, 1080), this, this, this); - run_loop.Run(); + scoped_task_environment_.RunUntilIdle(); + Mock::VerifyAndClear(this); } + // Starts the mirroring session. void StartSession() { + ASSERT_TRUE(cast_mode_ == "mirroring"); // Except mirroing session starts after receiving ANSWER message. - base::RunLoop run_loop; const int num_to_get_video_host = sink_capability_ == DeviceCapability::AUDIO_ONLY ? 0 : 1; const int num_to_create_audio_stream = @@ -151,79 +212,144 @@ EXPECT_CALL(*this, OnGetVideoCaptureHost()).Times(num_to_get_video_host); EXPECT_CALL(*this, OnCreateAudioStream()).Times(num_to_create_audio_stream); EXPECT_CALL(*this, OnError(_)).Times(0); - EXPECT_CALL(*this, DidStart()) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); + EXPECT_CALL(*this, OnOutboundMessage("GET_STATUS")).Times(AtLeast(1)); + EXPECT_CALL(*this, OnOutboundMessage("GET_CAPABILITIES")).Times(1); + EXPECT_CALL(*this, DidStart()).Times(1); SendAnswer(); - run_loop.Run(); scoped_task_environment_.RunUntilIdle(); + Mock::VerifyAndClear(this); } void StopSession() { - base::RunLoop run_loop; if (video_host_) EXPECT_CALL(*video_host_, OnStopped()).Times(1); - EXPECT_CALL(*this, DidStop()) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); + EXPECT_CALL(*this, DidStop()).Times(1); session_.reset(); - run_loop.Run(); scoped_task_environment_.RunUntilIdle(); + Mock::VerifyAndClear(this); } - void SendVideoFrame() { + void CaptureOneVideoFrame() { + ASSERT_TRUE(cast_mode_ == "mirroring"); ASSERT_TRUE(video_host_); - base::RunLoop run_loop; // Expect to send out some UDP packets. - EXPECT_CALL(*network_context_->udp_socket(), OnSend()) - .Times(testing::AtLeast(1)); - EXPECT_CALL(*video_host_, ReleaseBuffer(_, _, _)) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); + EXPECT_CALL(*network_context_->udp_socket(), OnSend()).Times(AtLeast(1)); + EXPECT_CALL(*video_host_, ReleaseBuffer(_, _, _)).Times(1); // Send one video frame to the consumer. video_host_->SendOneFrame(gfx::Size(64, 32), base::TimeTicks::Now()); - run_loop.Run(); scoped_task_environment_.RunUntilIdle(); + Mock::VerifyAndClear(network_context_.get()); + Mock::VerifyAndClear(video_host_.get()); } void SignalAnswerTimeout() { - base::RunLoop run_loop; - EXPECT_CALL(*this, OnGetVideoCaptureHost()).Times(0); - EXPECT_CALL(*this, OnCreateAudioStream()).Times(0); - EXPECT_CALL(*this, OnError(ANSWER_TIME_OUT)).Times(1); - EXPECT_CALL(*this, DidStop()) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); - session_->OnAnswer("mirroring", std::vector<FrameSenderConfig>(), + if (cast_mode_ == "mirroring") { + EXPECT_CALL(*this, DidStop()).Times(1); + EXPECT_CALL(*this, OnError(ANSWER_TIME_OUT)).Times(1); + } else { + EXPECT_CALL(*this, DidStop()).Times(0); + EXPECT_CALL(*this, OnError(ANSWER_TIME_OUT)).Times(0); + // Expect to send OFFER message to fallback on mirroring. + EXPECT_CALL(*this, OnOutboundMessage("OFFER")).Times(1); + // The start of remoting is expected to fail. + EXPECT_CALL(remoting_source_, + OnStartFailed(RemotingStartFailReason::SERVICE_NOT_CONNECTED)) + .Times(1); + EXPECT_CALL(remoting_source_, OnSinkGone()).Times(AtLeast(1)); + } + session_->OnAnswer(std::vector<FrameSenderConfig>(), std::vector<FrameSenderConfig>(), ReceiverResponse()); + scoped_task_environment_.RunUntilIdle(); + cast_mode_ = "mirroring"; + Mock::VerifyAndClear(this); + Mock::VerifyAndClear(&remoting_source_); + } + + void SendRemotingCapabilities() { + EXPECT_CALL(*this, OnConnectToRemotingSource()).Times(1); + EXPECT_CALL(remoting_source_, OnSinkAvailable(_)).Times(1); + ReceiverResponse response; + response.result = "ok"; + response.type = ResponseType::CAPABILITIES_RESPONSE; + response.sequence_number = capability_sequence_number_; + response.capabilities = std::make_unique<ReceiverCapability>(); + response.capabilities->media_caps = + std::vector<std::string>({"video", "audio", "vp8", "opus"}); + session_->OnCapabilitiesResponse(response); + scoped_task_environment_.RunUntilIdle(); + Mock::VerifyAndClear(this); + Mock::VerifyAndClear(&remoting_source_); + } + + void StartRemoting() { + base::RunLoop run_loop; + ASSERT_TRUE(remoter_.is_bound()); + // GET_CAPABILITIES is only sent once at the start of mirroring. + EXPECT_CALL(*this, OnOutboundMessage("GET_CAPABILITIES")).Times(0); + EXPECT_CALL(*this, OnOutboundMessage("OFFER")) + .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); + remoter_->Start(); run_loop.Run(); scoped_task_environment_.RunUntilIdle(); + cast_mode_ = "remoting"; + Mock::VerifyAndClear(this); + } + + void RemotingStarted() { + ASSERT_TRUE(cast_mode_ == "remoting"); + EXPECT_CALL(remoting_source_, OnStarted()).Times(1); + SendAnswer(); + scoped_task_environment_.RunUntilIdle(); + Mock::VerifyAndClear(this); + Mock::VerifyAndClear(&remoting_source_); + } + + void StopRemoting() { + ASSERT_TRUE(cast_mode_ == "remoting"); + const RemotingStopReason reason = RemotingStopReason::LOCAL_PLAYBACK; + // Expect to send OFFER message to fallback on mirroring. + EXPECT_CALL(*this, OnOutboundMessage("OFFER")).Times(1); + EXPECT_CALL(remoting_source_, OnStopped(reason)).Times(1); + remoter_->Stop(reason); + scoped_task_environment_.RunUntilIdle(); + cast_mode_ = "mirroring"; + Mock::VerifyAndClear(this); + Mock::VerifyAndClear(&remoting_source_); } private: base::test::ScopedTaskEnvironment scoped_task_environment_; const net::IPEndPoint receiver_endpoint_; + DeviceCapability sink_capability_ = DeviceCapability::AUDIO_AND_VIDEO; + media::mojom::RemoterPtr remoter_; + MockRemotingSource remoting_source_; + std::string cast_mode_; + int32_t offer_sequence_number_ = -1; + int32_t capability_sequence_number_ = -1; + std::unique_ptr<Session> session_; std::unique_ptr<FakeVideoCaptureHost> video_host_; std::unique_ptr<MockNetworkContext> network_context_; - DeviceCapability sink_capability_ = DeviceCapability::AUDIO_ONLY; - int32_t offer_sequence_number_ = -1; DISALLOW_COPY_AND_ASSIGN(SessionTest); }; -TEST_F(SessionTest, StartAudioOnlyMirroring) { +TEST_F(SessionTest, AudioOnlyMirroring) { CreateSession(DeviceCapability::AUDIO_ONLY); StartSession(); StopSession(); } -TEST_F(SessionTest, StartAudioAndVideoMirroring) { - CreateSession(DeviceCapability::AUDIO_AND_VIDEO); +TEST_F(SessionTest, VideoOnlyMirroring) { + CreateSession(DeviceCapability::VIDEO_ONLY); StartSession(); + CaptureOneVideoFrame(); StopSession(); } -TEST_F(SessionTest, VideoMirroring) { - CreateSession(DeviceCapability::VIDEO_ONLY); +TEST_F(SessionTest, AudioAndVideoMirroring) { + CreateSession(DeviceCapability::AUDIO_AND_VIDEO); StartSession(); - SendVideoFrame(); StopSession(); } @@ -232,4 +358,35 @@ SignalAnswerTimeout(); } +TEST_F(SessionTest, SwitchToAndFromRemoting) { + CreateSession(DeviceCapability::AUDIO_AND_VIDEO); + StartSession(); + SendRemotingCapabilities(); + StartRemoting(); + RemotingStarted(); + StopRemoting(); + StopSession(); +} + +TEST_F(SessionTest, StopSessionWhileRemoting) { + CreateSession(DeviceCapability::AUDIO_AND_VIDEO); + StartSession(); + SendRemotingCapabilities(); + StartRemoting(); + RemotingStarted(); + StopSession(); +} + +TEST_F(SessionTest, StartRemotingFailed) { + CreateSession(DeviceCapability::AUDIO_AND_VIDEO); + StartSession(); + SendRemotingCapabilities(); + StartRemoting(); + SignalAnswerTimeout(); + // Resume mirroring. + SendAnswer(); + CaptureOneVideoFrame(); + StopSession(); +} + } // namespace mirroring
diff --git a/components/optimization_guide/proto/hints.proto b/components/optimization_guide/proto/hints.proto index fbb7d0f5..a58e681 100644 --- a/components/optimization_guide/proto/hints.proto +++ b/components/optimization_guide/proto/hints.proto
@@ -9,7 +9,7 @@ enum OptimizationType { TYPE_UNSPECIFIED = 0; - // This optimization blocks Javascript on the page. + // This optimization blocks JavaScript on the page. NOSCRIPT = 1; // This optimization applies a set of ResourceLoadingHint(s) to load the // page.
diff --git a/components/optimization_guide/test_component_creator.cc b/components/optimization_guide/test_component_creator.cc index 99c0a617..cec41ff5 100644 --- a/components/optimization_guide/test_component_creator.cc +++ b/components/optimization_guide/test_component_creator.cc
@@ -24,11 +24,12 @@ } optimization_guide::ComponentInfo -TestComponentCreator::CreateComponentInfoWithNoScriptWhitelist( - std::vector<std::string> whitelisted_host_suffixes) { +TestComponentCreator::CreateComponentInfoWithWhitelist( + optimization_guide::proto::OptimizationType optimization_type, + const std::vector<std::string>& whitelisted_host_suffixes) { std::string version_string = base::IntToString(next_component_version_++); base::FilePath hints_path = GetFilePath(version_string); - WriteConfigToFile(hints_path, whitelisted_host_suffixes); + WriteConfigToFile(optimization_type, hints_path, whitelisted_host_suffixes); return optimization_guide::ComponentInfo(base::Version(version_string), hints_path); } @@ -41,18 +42,19 @@ } void TestComponentCreator::WriteConfigToFile( + optimization_guide::proto::OptimizationType optimization_type, base::FilePath file_path, - std::vector<std::string> whitelisted_noscript_host_suffixes) { + std::vector<std::string> whitelisted_host_suffixes) { base::ScopedAllowBlockingForTesting allow_blocking; optimization_guide::proto::Configuration config; - for (auto whitelisted_noscript_site : whitelisted_noscript_host_suffixes) { + for (auto whitelisted_noscript_site : whitelisted_host_suffixes) { optimization_guide::proto::Hint* hint = config.add_hints(); hint->set_key(whitelisted_noscript_site); hint->set_key_representation(optimization_guide::proto::HOST_SUFFIX); optimization_guide::proto::Optimization* optimization = hint->add_whitelisted_optimizations(); - optimization->set_optimization_type(optimization_guide::proto::NOSCRIPT); + optimization->set_optimization_type(optimization_type); } std::string serialized_config;
diff --git a/components/optimization_guide/test_component_creator.h b/components/optimization_guide/test_component_creator.h index 8daa5571..ccf056f 100644 --- a/components/optimization_guide/test_component_creator.h +++ b/components/optimization_guide/test_component_creator.h
@@ -22,10 +22,12 @@ TestComponentCreator(); ~TestComponentCreator(); - // Creates component data based on |whitelisted_host_suffixes| to a temp file + // Creates component data based on |whitelisted_host_suffixes| for + // optimization with type |optimization_type| to a temp file // and returns the ComponentInfo for it. - optimization_guide::ComponentInfo CreateComponentInfoWithNoScriptWhitelist( - std::vector<std::string> whitelisted_host_suffixes); + optimization_guide::ComponentInfo CreateComponentInfoWithWhitelist( + optimization_guide::proto::OptimizationType optimization_type, + const std::vector<std::string>& whitelisted_host_suffixes); private: // Returns the scoped temp directory path with the |file_path_suffix| that is @@ -33,11 +35,12 @@ // The file itself will not be automatically created. base::FilePath GetFilePath(std::string file_path_suffix); - // Writes a configuration of hints with the - // |whitelisted_noscript_host_suffixes| to the file path. + // Writes a configuration of hints for |optimization_type| with the + // |whitelisted_host_suffixes| to the file path. void WriteConfigToFile( + optimization_guide::proto::OptimizationType optimization_type, base::FilePath file_path, - std::vector<std::string> whitelisted_noscript_host_suffixes); + std::vector<std::string> whitelisted_host_suffixes); std::unique_ptr<base::ScopedTempDir> scoped_temp_dir_; int next_component_version_;
diff --git a/components/previews/content/previews_content_util.cc b/components/previews/content/previews_content_util.cc index 5f066f9..6872231 100644 --- a/components/previews/content/previews_content_util.cc +++ b/components/previews/content/previews_content_util.cc
@@ -34,13 +34,17 @@ previews_state |= content::RESOURCE_LOADING_HINTS_ON; } + if (previews_decider->ShouldAllowPreview(url_request, + previews::PreviewsType::OFFLINE)) { + previews_state |= content::OFFLINE_PAGE_ON; + } + // Check for client-side previews in precendence order. - // Note: this for for the beginning of navigation so we should not + // Note: this is for the beginning of navigation so we should not // check for https here (since an http request may redirect to https). if (previews_decider->ShouldAllowPreview(url_request, previews::PreviewsType::NOSCRIPT)) { previews_state |= content::NOSCRIPT_ON; - return previews_state; } if (previews::params::IsClientLoFiEnabled() && @@ -50,7 +54,6 @@ previews::params::GetBlackListedHostsForClientLoFiFieldTrial(), false)) { previews_state |= content::CLIENT_LOFI_ON; - return previews_state; } return previews_state; @@ -62,6 +65,15 @@ const previews::PreviewsDecider* previews_decider) { bool is_https = url_request.url().SchemeIs(url::kHttpsScheme); + previews::PreviewsUserData* previews_user_data = + previews::PreviewsUserData::GetData(url_request); + // Check if an offline preview was actually served. + if (previews_user_data && previews_user_data->offline_preview_used()) { + DCHECK(previews_state & content::OFFLINE_PAGE_ON); + return content::OFFLINE_PAGE_ON; + } + previews_state &= ~content::OFFLINE_PAGE_ON; + // If a server preview is set, retain only the bits determined for the server. // |previews_state| must already have been updated for server previews from // the main frame response headers (so if they are set here, then they are @@ -73,8 +85,6 @@ content::SERVER_LOFI_ON | content::CLIENT_LOFI_ON); } - previews::PreviewsUserData* previews_user_data = - previews::PreviewsUserData::GetData(url_request); if (previews_user_data && previews_user_data->cache_control_no_transform_directive()) { if (HasEnabledPreviews(previews_state)) { @@ -96,6 +106,9 @@ url_request, previews::PreviewsType::RESOURCE_LOADING_HINTS)) { return content::RESOURCE_LOADING_HINTS_ON; } + // Remove RESOURCE_LOADING_HINTS_ON from |previews_state| since we decided + // not to commit to it. + previews_state = previews_state & ~content::RESOURCE_LOADING_HINTS_ON; } if (previews_state & content::NOSCRIPT_ON) { @@ -124,6 +137,8 @@ previews::PreviewsType GetMainFramePreviewsType( content::PreviewsState previews_state) { // The order is important here. + if (previews_state & content::OFFLINE_PAGE_ON) + return previews::PreviewsType::OFFLINE; if (previews_state & content::SERVER_LITE_PAGE_ON) return previews::PreviewsType::LITE_PAGE; if (previews_state & content::SERVER_LOFI_ON)
diff --git a/components/previews/content/previews_content_util_unittest.cc b/components/previews/content/previews_content_util_unittest.cc index e6e56cc..95a4d920 100644 --- a/components/previews/content/previews_content_util_unittest.cc +++ b/components/previews/content/previews_content_util_unittest.cc
@@ -122,12 +122,12 @@ TEST_F(PreviewsContentUtilTest, DetermineEnabledClientPreviewsStateClientLoFi) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitFromCommandLine("Previews,ClientLoFi", std::string()); - EXPECT_EQ(content::CLIENT_LOFI_ON, - previews::DetermineEnabledClientPreviewsState( - *CreateHttpsRequest(), enabled_previews_decider())); - EXPECT_EQ(content::CLIENT_LOFI_ON, - previews::DetermineEnabledClientPreviewsState( - *CreateRequest(), enabled_previews_decider())); + EXPECT_TRUE(content::CLIENT_LOFI_ON & + previews::DetermineEnabledClientPreviewsState( + *CreateHttpsRequest(), enabled_previews_decider())); + EXPECT_TRUE(content::CLIENT_LOFI_ON & + previews::DetermineEnabledClientPreviewsState( + *CreateRequest(), enabled_previews_decider())); } TEST_F(PreviewsContentUtilTest, @@ -150,13 +150,13 @@ scoped_feature_list.InitFromCommandLine( "Previews,ClientLoFi,NoScriptPreviews", std::string()); - // Verify NoScript takes precendence over LoFi (for https). - EXPECT_EQ(content::NOSCRIPT_ON, - previews::DetermineEnabledClientPreviewsState( - *CreateHttpsRequest(), enabled_previews_decider())); - EXPECT_EQ(content::NOSCRIPT_ON, - previews::DetermineEnabledClientPreviewsState( - *CreateRequest(), enabled_previews_decider())); + // Verify both are enabled. + EXPECT_TRUE((content::NOSCRIPT_ON | content::CLIENT_LOFI_ON) & + previews::DetermineEnabledClientPreviewsState( + *CreateHttpsRequest(), enabled_previews_decider())); + EXPECT_TRUE((content::NOSCRIPT_ON | content::CLIENT_LOFI_ON) & + previews::DetermineEnabledClientPreviewsState( + *CreateRequest(), enabled_previews_decider())); // Verify non-HTTP[S] URL has no previews enabled. std::unique_ptr<net::URLRequest> data_url_request(
diff --git a/components/previews/content/previews_decider_impl.cc b/components/previews/content/previews_decider_impl.cc index 271f7cc..3fb0621 100644 --- a/components/previews/content/previews_decider_impl.cc +++ b/components/previews/content/previews_decider_impl.cc
@@ -408,10 +408,15 @@ const net::URLRequest& request, PreviewsType type, std::vector<PreviewsEligibilityReason>* passed_reasons) const { - if (!previews_opt_guide_) + DCHECK(type == PreviewsType::NOSCRIPT || + type == PreviewsType::RESOURCE_LOADING_HINTS); + + // For NoScript, if optimization guide is not present, assume that all URLs + // are ALLOWED. + if (!previews_opt_guide_ && type == PreviewsType::NOSCRIPT) return PreviewsEligibilityReason::ALLOWED; - // Check optmization guide whitelist. + // Check optimization guide whitelist. if (!previews_opt_guide_->IsWhitelisted(request, type)) { return PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER; }
diff --git a/components/previews/core/previews_user_data.h b/components/previews/core/previews_user_data.h index f598ca9..df90bc1 100644 --- a/components/previews/core/previews_user_data.h +++ b/components/previews/core/previews_user_data.h
@@ -85,6 +85,12 @@ return committed_previews_type_ != previews::PreviewsType::NONE; } + // Whether an offline preview is being served. + void set_offline_preview_used(bool offline_preview_used) { + offline_preview_used_ = offline_preview_used; + } + bool offline_preview_used() { return offline_preview_used_; } + private: // A session unique ID related to this navigation. const uint64_t page_id_; @@ -93,6 +99,9 @@ // Whether the origin provided a no-transform directive. bool cache_control_no_transform_directive_ = false; + // Whether an offline preview is being served. + bool offline_preview_used_ = false; + // Whether a lite page preview was prevented from being shown due to the // blacklist. bool black_listed_for_lite_page_ = false;
diff --git a/components/sync/driver/data_type_manager_impl_unittest.cc b/components/sync/driver/data_type_manager_impl_unittest.cc index e1974d8..8f5bbabe 100644 --- a/components/sync/driver/data_type_manager_impl_unittest.cc +++ b/components/sync/driver/data_type_manager_impl_unittest.cc
@@ -1443,10 +1443,7 @@ EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state()); // Simulate timeout by firing the timer. - dtm_->GetModelAssociationManagerForTesting() - ->GetTimerForTesting() - ->user_task() - .Run(); + dtm_->GetModelAssociationManagerForTesting()->GetTimerForTesting()->FireNow(); EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state()); EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
diff --git a/components/sync/driver/model_association_manager_unittest.cc b/components/sync/driver/model_association_manager_unittest.cc index 40849965..e19917a2 100644 --- a/components/sync/driver/model_association_manager_unittest.cc +++ b/components/sync/driver/model_association_manager_unittest.cc
@@ -221,7 +221,7 @@ GetController(controllers_, APPS)->FinishStart(DataTypeController::OK); EXPECT_CALL(delegate_, OnSingleDataTypeWillStop(BOOKMARKS, _)); - model_association_manager.GetTimerForTesting()->user_task().Run(); + model_association_manager.GetTimerForTesting()->FireNow(); EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(controllers_, BOOKMARKS)->state()); @@ -354,7 +354,7 @@ DataTypeController::ASSOCIATING); EXPECT_CALL(delegate_, OnSingleDataTypeWillStop(BOOKMARKS, _)); - model_association_manager.GetTimerForTesting()->user_task().Run(); + model_association_manager.GetTimerForTesting()->FireNow(); EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(controllers_, BOOKMARKS)->state());
diff --git a/components/variations/variations_request_scheduler_mobile_unittest.cc b/components/variations/variations_request_scheduler_mobile_unittest.cc index 91b2ee9..9d5f6b6 100644 --- a/components/variations/variations_request_scheduler_mobile_unittest.cc +++ b/components/variations/variations_request_scheduler_mobile_unittest.cc
@@ -69,7 +69,7 @@ // Force execution of the task on this timer to verify that the correct task // was added to the timer. - scheduler.schedule_fetch_timer_.user_task().Run(); + scheduler.schedule_fetch_timer_.FireNow(); // The task should not execute because the seed was fetched too recently. EXPECT_EQ(0, executed); @@ -95,7 +95,7 @@ // Force execution of the task on this timer to verify that the correct task // was added to the timer - this will verify that the right task is running. - scheduler.schedule_fetch_timer_.user_task().Run(); + scheduler.schedule_fetch_timer_.FireNow(); // We expect the input task to have triggered. EXPECT_EQ(1, executed); @@ -134,7 +134,7 @@ scheduler.OnAppEnterForeground(); EXPECT_TRUE(scheduler.schedule_fetch_timer_.IsRunning()); - scheduler.schedule_fetch_timer_.user_task().Run(); + scheduler.schedule_fetch_timer_.FireNow(); // This time it should execute the task. EXPECT_EQ(2, executed); }
diff --git a/components/viz/common/surfaces/parent_local_surface_id_allocator.cc b/components/viz/common/surfaces/parent_local_surface_id_allocator.cc index 2d8de94..014cd0c 100644 --- a/components/viz/common/surfaces/parent_local_surface_id_allocator.cc +++ b/components/viz/common/surfaces/parent_local_surface_id_allocator.cc
@@ -49,24 +49,25 @@ } const LocalSurfaceId& ParentLocalSurfaceIdAllocator::GenerateId() { - if (!is_allocation_suppressed_) + if (!is_allocation_suppressed_) { ++current_local_surface_id_.parent_sequence_number_; + TRACE_EVENT_WITH_FLOW2( + TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), + "LocalSurfaceId.Embed.Flow", + TRACE_ID_GLOBAL(current_local_surface_id_.embed_trace_id()), + TRACE_EVENT_FLAG_FLOW_OUT, "step", + "ParentLocalSurfaceIdAllocator::GenerateId", "local_surface_id", + current_local_surface_id_.ToString()); + TRACE_EVENT_WITH_FLOW2( + TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), + "LocalSurfaceId.Submission.Flow", + TRACE_ID_GLOBAL(current_local_surface_id_.submission_trace_id()), + TRACE_EVENT_FLAG_FLOW_OUT, "step", + "ParentLocalSurfaceIdAllocator::GenerateId", "local_surface_id", + current_local_surface_id_.ToString()); + } is_invalid_ = false; - TRACE_EVENT_WITH_FLOW2( - TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), - "LocalSurfaceId.Embed.Flow", - TRACE_ID_GLOBAL(current_local_surface_id_.embed_trace_id()), - TRACE_EVENT_FLAG_FLOW_OUT, "step", - "ParentLocalSurfaceIdAllocator::GenerateId", "local_surface_id", - current_local_surface_id_.ToString()); - TRACE_EVENT_WITH_FLOW2( - TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), - "LocalSurfaceId.Submission.Flow", - TRACE_ID_GLOBAL(current_local_surface_id_.submission_trace_id()), - TRACE_EVENT_FLAG_FLOW_OUT, "step", - "ParentLocalSurfaceIdAllocator::GenerateId", "local_surface_id", - current_local_surface_id_.ToString()); return current_local_surface_id_; }
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn index 826d73f..166f325 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn
@@ -144,6 +144,8 @@ "frame_sinks/video_capture/in_flight_frame_delivery.h", "frame_sinks/video_capture/interprocess_frame_pool.cc", "frame_sinks/video_capture/interprocess_frame_pool.h", + "frame_sinks/video_capture/video_capture_overlay.cc", + "frame_sinks/video_capture/video_capture_overlay.h", "frame_sinks/video_detector.cc", "frame_sinks/video_detector.h", "gl/gpu_service_impl.cc", @@ -319,6 +321,7 @@ "frame_sinks/surface_synchronization_unittest.cc", "frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc", "frame_sinks/video_capture/interprocess_frame_pool_unittest.cc", + "frame_sinks/video_capture/video_capture_overlay_unittest.cc", "frame_sinks/video_detector_unittest.cc", "gl/gpu_service_impl_unittest.cc", "hit_test/hit_test_aggregator_unittest.cc",
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc index bef1025..bbdf378b 100644 --- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc +++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -308,14 +308,6 @@ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", "ReceiveCompositorFrame"); - TRACE_EVENT_WITH_FLOW2( - TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), - "LocalSurfaceId.Submission.Flow", - TRACE_ID_GLOBAL(local_surface_id.submission_trace_id()), - TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", - "ReceiveCompositorFrame", "local_surface_id", - local_surface_id.ToString()); - TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"), "SubmitCompositorFrame", local_surface_id.hash()); @@ -385,6 +377,14 @@ local_surface_id == last_created_surface_id_.local_surface_id()) { current_surface = prev_surface; } else { + TRACE_EVENT_WITH_FLOW2( + TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), + "LocalSurfaceId.Submission.Flow", + TRACE_ID_GLOBAL(local_surface_id.submission_trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", + "ReceiveCompositorFrame", "local_surface_id", + local_surface_id.ToString()); + SurfaceId surface_id(frame_sink_id_, local_surface_id); SurfaceInfo surface_info(surface_id, frame.device_scale_factor(), frame.size_in_pixels());
diff --git a/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc b/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc new file mode 100644 index 0000000..75be2cb --- /dev/null +++ b/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc
@@ -0,0 +1,574 @@ +// 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. + +#include "components/viz/service/frame_sinks/video_capture/video_capture_overlay.h" + +#include <algorithm> +#include <cmath> +#include <utility> + +#include "base/bind.h" +#include "base/numerics/safe_conversions.h" +#include "base/trace_event/trace_event.h" +#include "media/base/limits.h" +#include "media/base/video_frame.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkFilterQuality.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect_conversions.h" + +using media::VideoFrame; +using media::VideoPixelFormat; + +namespace viz { + +VideoCaptureOverlay::FrameSource::~FrameSource() = default; + +VideoCaptureOverlay::VideoCaptureOverlay(FrameSource* frame_source) + : frame_source_(frame_source) { + DCHECK(frame_source_); +} + +VideoCaptureOverlay::~VideoCaptureOverlay() = default; + +void VideoCaptureOverlay::SetImageAndBounds(const SkBitmap& image, + const gfx::RectF& bounds) { + const gfx::Rect old_rect = ComputeSourceMutationRect(); + + image_ = image; + bounds_ = bounds; + + // Reset the cached sprite since the source image has been changed. + sprite_ = nullptr; + + const gfx::Rect new_rect = ComputeSourceMutationRect(); + if (!new_rect.IsEmpty() || !old_rect.IsEmpty()) { + frame_source_->InvalidateRect(old_rect); + frame_source_->InvalidateRect(new_rect); + frame_source_->RequestRefreshFrame(); + } +} + +void VideoCaptureOverlay::SetBounds(const gfx::RectF& bounds) { + if (bounds_ != bounds) { + const gfx::Rect old_rect = ComputeSourceMutationRect(); + bounds_ = bounds; + const gfx::Rect new_rect = ComputeSourceMutationRect(); + if (!new_rect.IsEmpty() || !old_rect.IsEmpty()) { + frame_source_->InvalidateRect(old_rect); + frame_source_->InvalidateRect(new_rect); + frame_source_->RequestRefreshFrame(); + } + } +} + +namespace { + +// Scales a |relative| rect having coordinates in the range [0.0,1.0) by the +// given |span|, snapping all coordinates to even numbers. +gfx::Rect ToAbsoluteBoundsForI420(const gfx::RectF& relative, + const gfx::Rect& span) { + const float absolute_left = std::fma(relative.x(), span.width(), span.x()); + const float absolute_top = std::fma(relative.y(), span.height(), span.y()); + const float absolute_right = + std::fma(relative.right(), span.width(), span.x()); + const float absolute_bottom = + std::fma(relative.bottom(), span.height(), span.y()); + + // Compute the largest I420-friendly Rect that is fully-enclosed by the + // absolute rect. Use saturated_cast<> to restrict all extreme results [and + // Inf and NaN] to a safe range of integers. + const int snapped_left = + base::saturated_cast<int16_t>(std::ceil(absolute_left / 2.0f)) * 2; + const int snapped_top = + base::saturated_cast<int16_t>(std::ceil(absolute_top / 2.0f)) * 2; + const int snapped_right = + base::saturated_cast<int16_t>(std::floor(absolute_right / 2.0f)) * 2; + const int snapped_bottom = + base::saturated_cast<int16_t>(std::floor(absolute_bottom / 2.0f)) * 2; + return gfx::Rect(snapped_left, snapped_top, + std::max(0, snapped_right - snapped_left), + std::max(0, snapped_bottom - snapped_top)); +} + +// Shrinks the given |rect| by the minimum amount necessary to align its corners +// to even-numbered coordinates. |rect| is assumed to have non-negative values +// for its coordinates. +gfx::Rect MinimallyShrinkRectForI420(const gfx::Rect& rect) { + DCHECK(gfx::Rect(0, 0, media::limits::kMaxDimension, + media::limits::kMaxDimension) + .Contains(rect)); + const int left = rect.x() + (rect.x() % 2); + const int top = rect.y() + (rect.y() % 2); + const int right = rect.right() - (rect.right() % 2); + const int bottom = rect.bottom() - (rect.bottom() % 2); + return gfx::Rect(left, top, std::max(0, right - left), + std::max(0, bottom - top)); +} + +} // namespace + +VideoCaptureOverlay::OnceRenderer VideoCaptureOverlay::MakeRenderer( + const gfx::Rect& region_in_frame, + const VideoPixelFormat frame_format, + const gfx::ColorSpace& frame_color_space) { + // If there's no image set yet, punt. + if (image_.drawsNothing()) { + return VideoCaptureOverlay::OnceRenderer(); + } + + // Determine the bounds of the sprite to be blitted onto the video frame. The + // calculations here align to the 2x2 pixel-quads, since dealing with + // fractions or partial I420 chroma plane alpha-blending would greatly + // complexify the blitting algorithm later on. This introduces a little + // inaccuracy in the size and position of the overlay in the final result, but + // should be an acceptable trade-off for all use cases. + const gfx::Rect bounds_in_frame = + ToAbsoluteBoundsForI420(bounds_, region_in_frame); + // If the sprite's size will be unreasonably large, punt. + if (bounds_in_frame.width() > media::limits::kMaxDimension || + bounds_in_frame.height() > media::limits::kMaxDimension) { + return VideoCaptureOverlay::OnceRenderer(); + } + + // Compute the blit rect: the region of the frame to be modified by future + // Sprite::Blit() calls. First, |region_in_frame| must be shrunk to have + // even-valued coordinates to ensure the final blit rect is I420-friendly. + // Then, the shrunk |region_in_frame| is used to clip |bounds_in_frame|. + gfx::Rect blit_rect = MinimallyShrinkRectForI420(region_in_frame); + blit_rect.Intersect(bounds_in_frame); + // If the two rects didn't intersect at all (i.e., everything has been + // clipped), punt. + if (blit_rect.IsEmpty()) { + return VideoCaptureOverlay::OnceRenderer(); + } + + // If the cached sprite does not match the computed scaled size, pixel format, + // and/or color space, create a new instance for this (and future) renderers. + if (!sprite_ || sprite_->size() != bounds_in_frame.size() || + sprite_->format() != frame_format || + sprite_->color_space() != frame_color_space) { + sprite_ = base::MakeRefCounted<Sprite>(image_, bounds_in_frame.size(), + frame_format, frame_color_space); + } + + return base::BindOnce(&Sprite::Blit, sprite_, bounds_in_frame.origin(), + blit_rect); +} + +// static +VideoCaptureOverlay::OnceRenderer VideoCaptureOverlay::MakeCombinedRenderer( + const std::vector<std::unique_ptr<VideoCaptureOverlay>>& overlays, + const gfx::Rect& region_in_frame, + const VideoPixelFormat frame_format, + const gfx::ColorSpace& frame_color_space) { + if (overlays.empty()) { + return VideoCaptureOverlay::OnceRenderer(); + } + + std::vector<OnceRenderer> renderers; + for (const std::unique_ptr<VideoCaptureOverlay>& overlay : overlays) { + renderers.emplace_back(overlay->MakeRenderer(region_in_frame, frame_format, + frame_color_space)); + if (renderers.back().is_null()) { + renderers.pop_back(); + } + } + + if (renderers.empty()) { + return VideoCaptureOverlay::OnceRenderer(); + } + + return base::BindOnce( + [](std::vector<OnceRenderer> renderers, VideoFrame* frame) { + for (OnceRenderer& renderer : renderers) { + std::move(renderer).Run(frame); + } + }, + std::move(renderers)); +} + +gfx::Rect VideoCaptureOverlay::ComputeSourceMutationRect() const { + if (!image_.drawsNothing() && !bounds_.IsEmpty()) { + const gfx::Size& source_size = frame_source_->GetSourceSize(); + gfx::Rect result = gfx::ToEnclosingRect( + gfx::ScaleRect(bounds_, source_size.width(), source_size.height())); + result.Intersect(gfx::Rect(source_size)); + return result; + } + return gfx::Rect(); +} + +VideoCaptureOverlay::Sprite::Sprite(const SkBitmap& image, + const gfx::Size& size, + const VideoPixelFormat format, + const gfx::ColorSpace& color_space) + : image_(image), size_(size), format_(format), color_space_(color_space) { + DCHECK(!image_.isNull()); +} + +VideoCaptureOverlay::Sprite::~Sprite() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +namespace { + +// Returns the pointer to the element at the |offset| position, given a pointer +// to the element for (0,0) in a row-major image plane. +template <typename Pointer> +Pointer PositionPointerInPlane(Pointer plane_begin, + int stride, + const gfx::Point& offset) { + return plane_begin + (offset.y() * stride) + offset.x(); +} + +// Returns the pointer to the element at the |offset| position, given a pointer +// to the element for (0,0) in a row-major bitmap with 4 elements per pixel. +template <typename Pointer> +Pointer PositionPointerARGB(Pointer pixels_begin, + int stride, + const gfx::Point& offset) { + return pixels_begin + (offset.y() * stride) + (4 * offset.x()); +} + +// Transforms the lower 8 bits of |value| from the [0,255] range to the +// normalized floating-point [0.0,1.0] range. +float From255(uint8_t value) { + return value / 255.0f; +} + +// Transforms the value from the normalized floating-point [0.0,1.0] range to an +// unsigned int in the [0,255] range, capping any out-of-range values. +uint32_t ToClamped255(float value) { + value = std::fma(value, 255.0f, 0.5f /* rounding */); + return base::saturated_cast<uint8_t>(value); +} + +} // namespace + +void VideoCaptureOverlay::Sprite::Blit(const gfx::Point& position, + const gfx::Rect& blit_rect, + VideoFrame* frame) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(frame); + DCHECK_EQ(format_, frame->format()); + DCHECK(frame->visible_rect().Contains(blit_rect)); + + TRACE_EVENT2("gpu.capture", "VideoCaptureOverlay::Sprite::Blit", "x", + position.x(), "y", position.y()); + + if (!transformed_image_) { + TransformImageOnce(); + } + + // Compute the left-most and top-most pixel to source from the transformed + // image. This is usually (0,0) unless only part of the sprite is being + // blitted (i.e., cropped at the edge(s) of the video frame). + gfx::Point src_origin = blit_rect.origin() - position.OffsetFromOrigin(); + DCHECK(gfx::Rect(size_).Contains(gfx::Rect(src_origin, blit_rect.size()))); + + // Blit the sprite (src) onto the video frame (dest). One of two algorithms is + // used, depending on the video frame's format, as the blending calculations + // and data layout/format are different. + switch (frame->format()) { + case media::PIXEL_FORMAT_I420: { + // Core assumption: All coordinates are aligned to even-numbered + // coordinates. + DCHECK_EQ(src_origin.x() % 2, 0); + DCHECK_EQ(src_origin.y() % 2, 0); + DCHECK_EQ(blit_rect.x() % 2, 0); + DCHECK_EQ(blit_rect.y() % 2, 0); + DCHECK_EQ(blit_rect.width() % 2, 0); + DCHECK_EQ(blit_rect.height() % 2, 0); + + // Helper function to execute a "SrcOver" blit from |src| to |dst|, and + // store the results back in |dst|. + const auto BlitOntoPlane = [](const gfx::Size& blit_size, int src_stride, + const float* src, const float* under_weight, + int dst_stride, uint8_t* dst) { + for (int row = 0; row < blit_size.height(); ++row, src += src_stride, + under_weight += src_stride, dst += dst_stride) { + for (int col = 0; col < blit_size.width(); ++col) { + dst[col] = ToClamped255( + std::fma(From255(dst[col]), under_weight[col], src[col])); + } + } + }; + + // Blit the Y plane: |src| points to the pre-multiplied luma values, while + // |under_weight| points to the "one minus src alpha" values. Both have + // the same stride, |src_stride|. + int src_stride = size_.width(); + const float* under_weight = PositionPointerInPlane( + transformed_image_.get(), src_stride, src_origin); + const int num_pixels = size_.GetArea(); + const float* src = under_weight + num_pixels; + // Likewise, start |dst| at the upper-left-most pixel within the video + // frame's Y plane that will be SrcOver'ed. + int dst_stride = frame->stride(VideoFrame::kYPlane); + uint8_t* dst = + PositionPointerInPlane(frame->visible_data(VideoFrame::kYPlane), + dst_stride, blit_rect.origin()); + BlitOntoPlane(blit_rect.size(), src_stride, src, under_weight, dst_stride, + dst); + + // Blit the U and V planes similarly to the Y plane, but reduce all + // coordinates by 2x2. + src_stride = size_.width() / 2; + src_origin = gfx::Point(src_origin.x() / 2, src_origin.y() / 2); + under_weight = PositionPointerInPlane( + transformed_image_.get() + 2 * num_pixels, src_stride, src_origin); + const int num_chroma_pixels = size_.GetArea() / 4; + src = under_weight + num_chroma_pixels; + dst_stride = frame->stride(VideoFrame::kUPlane); + const gfx::Rect chroma_blit_rect(blit_rect.x() / 2, blit_rect.y() / 2, + blit_rect.width() / 2, + blit_rect.height() / 2); + dst = PositionPointerInPlane(frame->visible_data(VideoFrame::kUPlane), + dst_stride, chroma_blit_rect.origin()); + BlitOntoPlane(chroma_blit_rect.size(), src_stride, src, under_weight, + dst_stride, dst); + src += num_chroma_pixels; + dst_stride = frame->stride(VideoFrame::kVPlane); + dst = PositionPointerInPlane(frame->visible_data(VideoFrame::kVPlane), + dst_stride, chroma_blit_rect.origin()); + BlitOntoPlane(chroma_blit_rect.size(), src_stride, src, under_weight, + dst_stride, dst); + + break; + } + + case media::PIXEL_FORMAT_ARGB: { + // Start |src| at the upper-left-most pixel within |transformed_image_| + // that will be blitted. + const int src_stride = size_.width() * 4; + const float* src = + PositionPointerARGB(transformed_image_.get(), src_stride, src_origin); + + // Likewise, start |dst| at the upper-left-most pixel within the video + // frame that will be SrcOver'ed. + const int dst_stride = frame->stride(VideoFrame::kARGBPlane); + DCHECK_EQ(dst_stride % sizeof(uint32_t), 0u); + uint8_t* dst = + PositionPointerARGB(frame->visible_data(VideoFrame::kARGBPlane), + dst_stride, blit_rect.origin()); + DCHECK_EQ((dst - frame->visible_data(VideoFrame::kARGBPlane)) % + sizeof(uint32_t), + 0u); + + // Blend each sprite pixel over the corresponding pixel in the video + // frame, and store the result back in the video frame. Note that the + // video frame format does NOT have color values pre-multiplied by the + // alpha. + for (int row = 0; row < blit_rect.height(); + ++row, src += src_stride, dst += dst_stride) { + uint32_t* dst_pixel = reinterpret_cast<uint32_t*>(dst); + for (int col = 0; col < blit_rect.width(); ++col) { + const int src_idx = 4 * col; + const float src_alpha = src[src_idx]; + const float dst_weight = + From255(dst_pixel[col] >> 24) * (1.0f - src_alpha); + const float out_alpha = src_alpha + dst_weight; + float out_red = std::fma(From255(dst_pixel[col] >> 16), dst_weight, + src[src_idx + 1]); + float out_green = std::fma(From255(dst_pixel[col] >> 8), dst_weight, + src[src_idx + 2]); + float out_blue = std::fma(From255(dst_pixel[col] >> 0), dst_weight, + src[src_idx + 3]); + if (out_alpha != 0.0f) { + out_red /= out_alpha; + out_green /= out_alpha; + out_blue /= out_alpha; + } + dst_pixel[col] = + ((ToClamped255(out_alpha) << 24) | (ToClamped255(out_red) << 16) | + (ToClamped255(out_green) << 8) | (ToClamped255(out_blue) << 0)); + } + } + + break; + } + + default: + NOTREACHED(); + break; + } +} + +void VideoCaptureOverlay::Sprite::TransformImageOnce() { + TRACE_EVENT2("gpu.capture", "VideoCaptureOverlay::Sprite::TransformImageOnce", + "width", size_.width(), "height", size_.height()); + + // Scale the source |image_| to match the format and size required. For the + // purposes of color space conversion, the alpha must not be pre-multiplied. + const SkImageInfo scaled_image_format = + SkImageInfo::Make(size_.width(), size_.height(), kN32_SkColorType, + kUnpremul_SkAlphaType, image_.refColorSpace()); + SkBitmap scaled_image; + if (image_.info() == scaled_image_format) { + scaled_image = image_; + } else { + if (!scaled_image.tryAllocPixels(scaled_image_format) || + !image_.pixmap().scalePixels(scaled_image.pixmap(), + kMedium_SkFilterQuality)) { + // If the allocation, format conversion and/or scaling failed, just reset + // the |scaled_image|. This will be checked below. + scaled_image.reset(); + } + } + + gfx::ColorSpace image_color_space; + if (scaled_image.colorSpace()) { + image_color_space = gfx::ColorSpace(*scaled_image.colorSpace()); + DCHECK(image_color_space.IsValid()); + } else { + // Assume a default linear color space, if no color space was provided. + DCHECK(!image_.colorSpace()); // Skia should have set it! + image_color_space = gfx::ColorSpace( + gfx::ColorSpace::PrimaryID::BT709, gfx::ColorSpace::TransferID::LINEAR, + gfx::ColorSpace::MatrixID::RGB, gfx::ColorSpace::RangeID::FULL); + } + + // The source image is no longer needed. Reset it to dereference pixel memory. + image_.reset(); + + // Populate |colors| and |alphas| from the |scaled_image|. If the image + // scaling operation failed, this sprite should draw nothing, and so fully + // transparent pixels will be generated instead. + const int num_pixels = size_.GetArea(); + std::unique_ptr<float[]> alphas(new float[num_pixels]); + std::unique_ptr<gfx::ColorTransform::TriStim[]> colors( + new gfx::ColorTransform::TriStim[num_pixels]); + if (scaled_image.drawsNothing()) { + std::fill(alphas.get(), alphas.get() + num_pixels, 0.0f); + std::fill(colors.get(), colors.get() + num_pixels, + gfx::ColorTransform::TriStim()); + } else { + int pos = 0; + for (int y = 0; y < size_.height(); ++y) { + const uint32_t* src = scaled_image.getAddr32(0, y); + for (int x = 0; x < size_.width(); ++x) { + const uint32_t pixel = src[x]; + alphas[pos] = ((pixel >> SK_A32_SHIFT) & 0xff) / 255.0f; + colors[pos].SetPoint(((pixel >> SK_R32_SHIFT) & 0xff) / 255.0f, + ((pixel >> SK_G32_SHIFT) & 0xff) / 255.0f, + ((pixel >> SK_B32_SHIFT) & 0xff) / 255.0f); + ++pos; + } + } + } + + // Transform the colors, if needed. This may perform RGB→YUV conversion. + if (image_color_space != color_space_) { + const auto color_transform = gfx::ColorTransform::NewColorTransform( + image_color_space, color_space_, + gfx::ColorTransform::Intent::INTENT_ABSOLUTE); + color_transform->Transform(colors.get(), num_pixels); + } + + switch (format_) { + case media::PIXEL_FORMAT_I420: { + // Produce 5 planes of data: The "one minus alpha" plane, the Y plane, the + // subsampled "one minus alpha" plane, the U plane, and the V plane. + // Pre-multiply the colors by the alpha to prevent extra work in multiple + // later Blit() calls. + DCHECK_EQ(size_.width() % 2, 0); + DCHECK_EQ(size_.height() % 2, 0); + const int num_chroma_pixels = size_.GetArea() / 4; + transformed_image_.reset( + new float[num_pixels * 2 + num_chroma_pixels * 3]); + + // Copy the alpha values, and pre-multiply the luma values by the alpha. + float* out_1_minus_alpha = transformed_image_.get(); + float* out_luma = out_1_minus_alpha + num_pixels; + for (int i = 0; i < num_pixels; ++i) { + const float alpha = alphas[i]; + out_1_minus_alpha[i] = 1.0f - alpha; + out_luma[i] = colors[i].x() * alpha; + } + + // Downscale the alpha, U, and V planes by 2x2, and pre-multiply the + // chroma values by the alpha. + float* out_uv_1_minus_alpha = out_luma + num_pixels; + float* out_u = out_uv_1_minus_alpha + num_chroma_pixels; + float* out_v = out_u + num_chroma_pixels; + const float* alpha_row0 = alphas.get(); + const float* const alpha_row_end = alpha_row0 + num_pixels; + const gfx::ColorTransform::TriStim* color_row0 = colors.get(); + while (alpha_row0 < alpha_row_end) { + const float* alpha_row1 = alpha_row0 + size_.width(); + const gfx::ColorTransform::TriStim* color_row1 = + color_row0 + size_.width(); + for (int col = 0; col < size_.width(); col += 2) { + // First, the downscaled alpha is the average of the four original + // alpha values: + // + // sum_of_alphas = a[r,c] + a[r,c+1] + a[r+1,c] + a[r+1,c+1]; + // average_alpha = sum_of_alphas / 4 + *(out_uv_1_minus_alpha++) = + std::fma(alpha_row0[col] + alpha_row0[col + 1] + alpha_row1[col] + + alpha_row1[col + 1], + -1.0f / 4.0f, 1.0f); + // Then, the downscaled chroma values are the weighted average of the + // four original chroma values (weighed by alpha): + // + // weighted_sum_of_chromas = + // c[r,c]*a[r,c] + c[r,c+1]*a[r,c+1] + + // c[r+1,c]*a[r+1,c] + c[r+1,c+1]*a[r+1,c+1] + // sum_of_weights = sum_of_alphas; + // average_chroma = weighted_sum_of_chromas / sum_of_weights + // + // But then, because the chroma is to be pre-multiplied by the alpha, + // the calculations simplify, as follows: + // + // premul_chroma = average_chroma * average_alpha + // = (weighted_sum_of_chromas / sum_of_alphas) * + // (sum_of_alphas / 4) + // = weighted_sum_of_chromas / 4 + // + // This also automatically solves a special case, when sum_of_alphas + // is zero: With the simplified calculations, there is no longer a + // "divide-by-zero guard" needed; and the result in this case will be + // a zero chroma, which is perfectly acceptable behavior. + *(out_u++) = ((color_row0[col].y() * alpha_row0[col]) + + (color_row0[col + 1].y() * alpha_row0[col + 1]) + + (color_row1[col].y() * alpha_row1[col]) + + (color_row1[col + 1].y() * alpha_row1[col + 1])) / + 4.0f; + *(out_v++) = ((color_row0[col].z() * alpha_row0[col]) + + (color_row0[col + 1].z() * alpha_row0[col + 1]) + + (color_row1[col].z() * alpha_row1[col]) + + (color_row1[col + 1].z() * alpha_row1[col + 1])) / + 4.0f; + } + alpha_row0 = alpha_row1 + size_.width(); + color_row0 = color_row1 + size_.width(); + } + + break; + } + + case media::PIXEL_FORMAT_ARGB: { + // Produce ARGB pixels from |colors| and |alphas|. Pre-multiply the colors + // by the alpha to prevent extra work in multiple later Blit() calls. + transformed_image_.reset(new float[num_pixels * 4]); + float* out = transformed_image_.get(); + for (int i = 0; i < num_pixels; ++i) { + const float alpha = alphas[i]; + *(out++) = alpha; + *(out++) = colors[i].x() * alpha; + *(out++) = colors[i].y() * alpha; + *(out++) = colors[i].z() * alpha; + } + break; + } + + default: + NOTREACHED(); + break; + } +} + +} // namespace viz
diff --git a/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h b/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h new file mode 100644 index 0000000..1d39a15 --- /dev/null +++ b/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h
@@ -0,0 +1,186 @@ +// 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. + +#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_VIDEO_CAPTURE_VIDEO_CAPTURE_OVERLAY_H_ +#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_VIDEO_CAPTURE_VIDEO_CAPTURE_OVERLAY_H_ + +#include <stdint.h> + +#include <memory> +#include <vector> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/sequence_checker.h" +#include "components/viz/service/viz_service_export.h" +#include "media/base/video_types.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/color_space.h" +#include "ui/gfx/color_transform.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/geometry/size.h" + +namespace media { +class VideoFrame; +} + +namespace viz { + +// An overlay image to be blitted onto video frames. A mojo client sets the +// image, position, and size of the overlay in the video frame; and then this +// VideoCaptureOverlay scales the image and maps its color space to match that +// of the video frame before the blitting. +// +// As an optimization, the client's bitmap image is transformed (scaled, color +// space converted, and pre-multiplied by alpha), and then this cached Sprite is +// re-used for blitting to all successive video frames until some change +// requires a different transformation. MakeRenderer() produces a Renderer +// callback that holds a reference to an existing Sprite, or will create a new +// one if necessary. The Renderer callback can then be run at any point in the +// future, unaffected by later image, size, or color space settings changes. +// +// The blit algorithm uses naive linear blending. Thus, the use of non-linear +// color spaces will cause loses in color accuracy. +// +// TODO(crbug.com/810133): Override the mojom::FrameSinkVideoCaptureOverlay +// interface. +class VIZ_SERVICE_EXPORT VideoCaptureOverlay { + public: + // Interface for notifying the frame source when changes to the overlay's + // state occur. + class VIZ_SERVICE_EXPORT FrameSource { + public: + // Returns the current size of the source, or empty if unknown. + virtual gfx::Size GetSourceSize() = 0; + + // Notifies the FrameSource that the given source |rect| needs to be + // re-captured soon. One or more calls to this method will be followed-up + // with a call to RequestRefreshFrame(). + virtual void InvalidateRect(const gfx::Rect& rect) = 0; + + // Notifies the FrameSource that another frame should be captured and have + // its VideoCaptureOverlay re-rendered soon to reflect an updated overlay + // image and/or position. + virtual void RequestRefreshFrame() = 0; + + protected: + virtual ~FrameSource(); + }; + + // A OnceCallback that, when run, renders the overlay on a VideoFrame. + using OnceRenderer = base::OnceCallback<void(media::VideoFrame*)>; + + // |frame_source| must outlive this instance. + explicit VideoCaptureOverlay(FrameSource* frame_source); + + ~VideoCaptureOverlay(); + + // Sets/Changes the overlay |image| and its position and size, relative to the + // source content. |bounds| consists of coordinates where the range [0.0,1.0) + // indicates the relative position+size within the bounds of the source + // content (e.g., 0.0 refers to the top or left edge; 1.0 to just after the + // bottom or right edge). Pass empty |bounds| to temporarily hide the overlay + // until a later call to SetBounds(). + void SetImageAndBounds(const SkBitmap& image, const gfx::RectF& bounds); + void SetBounds(const gfx::RectF& bounds); + + // Returns a OnceCallback that, when run, renders this VideoCaptureOverlay on + // a VideoFrame. The overlay's position and size are computed based on the + // given content |region_in_frame|, and its color space is converted to match + // the |frame_color_space|. Returns a null OnceCallback if there is nothing to + // render at this time. + OnceRenderer MakeRenderer(const gfx::Rect& region_in_frame, + const media::VideoPixelFormat frame_format, + const gfx::ColorSpace& frame_color_space); + + // Returns a OnceCallback that renders all of the given |overlays| in + // order. The remaining arguments are the same as in MakeRenderer(). This is a + // convenience that produces a single callback, so that client code need not + // deal with collections of callbacks. Returns a null OnceCallback if there is + // nothing to render at this time. + static OnceRenderer MakeCombinedRenderer( + const std::vector<std::unique_ptr<VideoCaptureOverlay>>& overlays, + const gfx::Rect& region_in_frame, + const media::VideoPixelFormat frame_format, + const gfx::ColorSpace& frame_color_space); + + private: + // Transforms the overlay SkBitmap image by scaling and converting its color + // space, and then blitting it onto a VideoFrame. The transformation is lazy: + // Meaning, a reference to the SkBitmap image is held until the first call to + // Blit(), where the transformation is then executed and the reference to the + // original SkBitmap dropped. The transformed data is then cached for re-use + // for later Blit() calls. + class Sprite : public base::RefCounted<Sprite> { + public: + Sprite(const SkBitmap& image, + const gfx::Size& size, + const media::VideoPixelFormat format, + const gfx::ColorSpace& color_space); + + const gfx::Size& size() const { return size_; } + media::VideoPixelFormat format() const { return format_; } + const gfx::ColorSpace& color_space() const { return color_space_; } + + void Blit(const gfx::Point& position, + const gfx::Rect& blit_rect, + media::VideoFrame* frame); + + private: + friend class base::RefCounted<Sprite>; + ~Sprite(); + + void TransformImageOnce(); + + // As Sprites can be long-lived and hidden from external code within + // callbacks, ensure that all Blit() calls are in-sequence. + SEQUENCE_CHECKER(sequence_checker_); + + // If not null, this is the original, unscaled overlay image. After + // TransformImageOnce() has been called, this is set to null. + SkBitmap image_; + + // The size, format, and color space of the cached transformed image. + const gfx::Size size_; + const media::VideoPixelFormat format_; + const gfx::ColorSpace color_space_; + + // The transformed source image data. For blitting to ARGB format video + // frames, the source image data will consist of 4 elements per pixel pixel + // (A, R, G, B). For blitting to the I420 format, the source image data is + // not interlaved: Instead, there are 5 planes of data (one minus alpha, Y, + // subsampled one minus alpha, U, V). For both formats, the color components + // are premultiplied for more-efficient Blit()'s. + std::unique_ptr<float[]> transformed_image_; + + DISALLOW_COPY_AND_ASSIGN(Sprite); + }; + + // Computes the region of the source that, if changed, would require + // re-rendering the overlay. + gfx::Rect ComputeSourceMutationRect() const; + + FrameSource* const frame_source_; + + // The currently-set overlay image. + SkBitmap image_; + + // If empty, the overlay is currently hidden. Otherwise, this consists of + // coordinates where the range [0.0,1.0) indicates the relative position+size + // within the bounds of the video frame's content region (e.g., 0.0 refers to + // the top or left edge; 1.0 to just after the bottom or right edge). + gfx::RectF bounds_; + + // The current Sprite. This is set to null whenever a settings change requires + // a new Sprite to be generated from the |image_|. + scoped_refptr<Sprite> sprite_; + + DISALLOW_COPY_AND_ASSIGN(VideoCaptureOverlay); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_VIDEO_CAPTURE_VIDEO_CAPTURE_OVERLAY_H_
diff --git a/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc b/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc new file mode 100644 index 0000000..2bb5112 --- /dev/null +++ b/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc
@@ -0,0 +1,554 @@ +// 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. + +#include "components/viz/service/frame_sinks/video_capture/video_capture_overlay.h" + +#include <array> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/numerics/safe_conversions.h" +#include "base/optional.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/stl_util.h" +#include "cc/test/pixel_comparator.h" +#include "cc/test/pixel_test_utils.h" +#include "components/viz/test/paths.h" +#include "media/base/video_frame.h" +#include "media/base/video_types.h" +#include "media/base/video_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "third_party/skia/include/core/SkPixmap.h" +#include "ui/gfx/color_space.h" +#include "ui/gfx/color_transform.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/geometry/size.h" + +using media::VideoFrame; +using media::VideoPixelFormat; + +using testing::_; +using testing::InvokeWithoutArgs; +using testing::NiceMock; +using testing::Return; +using testing::StrictMock; + +namespace viz { +namespace { + +class MockFrameSource : public VideoCaptureOverlay::FrameSource { + public: + MOCK_METHOD0(GetSourceSize, gfx::Size()); + MOCK_METHOD1(InvalidateRect, void(const gfx::Rect& rect)); + MOCK_METHOD0(RequestRefreshFrame, void()); +}; + +class VideoCaptureOverlayTest : public testing::Test { + public: + VideoCaptureOverlayTest() = default; + + NiceMock<MockFrameSource>* frame_source() { return &frame_source_; } + + std::unique_ptr<VideoCaptureOverlay> CreateOverlay() { + return std::make_unique<VideoCaptureOverlay>(frame_source()); + } + + void RunUntilIdle() { base::RunLoop().RunUntilIdle(); } + + // Makes a SkBitmap filled with a 50% white background color plus four rects + // of four different colors/opacities. |cycle| causes the four rects to rotate + // positions (counter-clockwise by N steps). + static SkBitmap MakeTestBitmap(int cycle) { + constexpr gfx::Size kTestImageSize = gfx::Size(24, 16); + // Test colors have been chosen to exercise different opacities, + // intensities, and color channels; to confirm all aspects of the "SrcOver" + // image blending algorithms are working properly. + constexpr SkColor kTestImageBackground = + SkColorSetARGB(0xff, 0xff, 0xff, 0xff); + constexpr SkColor kTestImageColors[4] = { + SkColorSetARGB(0xaa, 0xff, 0x00, 0x00), + SkColorSetARGB(0xbb, 0x00, 0xee, 0x00), + SkColorSetARGB(0xcc, 0x00, 0x00, 0x77), + SkColorSetARGB(0xdd, 0x66, 0x66, 0x00), + }; + constexpr SkIRect kTestImageColorRects[4] = { + SkIRect::MakeXYWH(4, 2, 4, 4), SkIRect::MakeXYWH(16, 2, 4, 4), + SkIRect::MakeXYWH(4, 10, 4, 4), SkIRect::MakeXYWH(16, 10, 4, 4), + }; + + SkBitmap result; + const SkImageInfo info = SkImageInfo::MakeN32Premul( + kTestImageSize.width(), kTestImageSize.height(), + GetLinearSRGB().ToSkColorSpace()); + CHECK(result.tryAllocPixels(info, info.minRowBytes())); + result.eraseColor(kTestImageBackground); + for (size_t i = 0; i < base::size(kTestImageColors); ++i) { + const size_t idx = (i + cycle) % base::size(kTestImageColors); + result.erase(kTestImageColors[idx], kTestImageColorRects[i]); + } + + return result; + } + + // Returns the sRGB color space, but with a linear transfer function. + static gfx::ColorSpace GetLinearSRGB() { + return gfx::ColorSpace( + gfx::ColorSpace::PrimaryID::BT709, gfx::ColorSpace::TransferID::LINEAR, + gfx::ColorSpace::MatrixID::RGB, gfx::ColorSpace::RangeID::FULL); + } + + // Returns the BT709 color space (YUV), but with a linear transfer function. + static gfx::ColorSpace GetLinearRec709() { + return gfx::ColorSpace( + gfx::ColorSpace::PrimaryID::BT709, gfx::ColorSpace::TransferID::LINEAR, + gfx::ColorSpace::MatrixID::BT709, gfx::ColorSpace::RangeID::LIMITED); + } + + static constexpr auto kARGBFormat = VideoPixelFormat::PIXEL_FORMAT_ARGB; + static constexpr auto kI420Format = VideoPixelFormat::PIXEL_FORMAT_I420; + + private: + NiceMock<MockFrameSource> frame_source_; + + DISALLOW_COPY_AND_ASSIGN(VideoCaptureOverlayTest); +}; + +// Tests that MakeRenderer() does not make a OnceRenderer until the client has +// set the image. +TEST_F(VideoCaptureOverlayTest, DoesNotRenderWithoutImage) { + constexpr gfx::Size kSize = gfx::Size(100, 75); + EXPECT_CALL(*frame_source(), GetSourceSize()).WillRepeatedly(Return(kSize)); + std::unique_ptr<VideoCaptureOverlay> overlay = CreateOverlay(); + + // The overlay does not have an image yet, so the renderer should be null. + constexpr gfx::Rect kRegionInFrame = gfx::Rect(kSize); + EXPECT_FALSE( + overlay->MakeRenderer(kRegionInFrame, kI420Format, GetLinearRec709())); + + // Once an image is set, the renderer should not be null. + overlay->SetImageAndBounds(MakeTestBitmap(1), gfx::RectF(0, 0, 1, 1)); + EXPECT_TRUE( + overlay->MakeRenderer(kRegionInFrame, kI420Format, GetLinearRec709())); +} + +// Tests that MakeRenderer() does not make a OnceRenderer if the bounds are set +// to something outside the frame's content region. +TEST_F(VideoCaptureOverlayTest, DoesNotRenderIfCompletelyOutOfBounds) { + constexpr gfx::Size kSize = gfx::Size(100, 75); + EXPECT_CALL(*frame_source(), GetSourceSize()).WillRepeatedly(Return(kSize)); + std::unique_ptr<VideoCaptureOverlay> overlay = CreateOverlay(); + + // The overlay does not have an image yet, so the renderer should be null. + constexpr gfx::Rect kRegionInFrame = gfx::Rect(kSize); + EXPECT_FALSE( + overlay->MakeRenderer(kRegionInFrame, kI420Format, GetLinearRec709())); + + // Setting an image, but out-of-bounds, should always result in a null + // renderer. + overlay->SetImageAndBounds(MakeTestBitmap(0), gfx::RectF(-1, -1, 1, 1)); + EXPECT_FALSE( + overlay->MakeRenderer(kRegionInFrame, kI420Format, GetLinearRec709())); + overlay->SetBounds(gfx::RectF(1, 1, 1, 1)); + EXPECT_FALSE( + overlay->MakeRenderer(kRegionInFrame, kI420Format, GetLinearRec709())); + overlay->SetBounds(gfx::RectF(-1, 1, 1, 1)); + EXPECT_FALSE( + overlay->MakeRenderer(kRegionInFrame, kI420Format, GetLinearRec709())); + overlay->SetBounds(gfx::RectF(1, -1, 1, 1)); + EXPECT_FALSE( + overlay->MakeRenderer(kRegionInFrame, kI420Format, GetLinearRec709())); +} + +// Tests that that MakeCombinedRenderer() only makes a OnceRenderer when one or +// more overlays are set to make visible changes to a video frame. +TEST_F(VideoCaptureOverlayTest, + DoesNotDoCombinedRenderIfNoOverlaysWouldRender) { + constexpr gfx::Size kSize = gfx::Size(100, 75); + EXPECT_CALL(*frame_source(), GetSourceSize()).WillRepeatedly(Return(kSize)); + std::vector<std::unique_ptr<VideoCaptureOverlay>> overlays; + overlays.emplace_back(CreateOverlay()); + overlays.emplace_back(CreateOverlay()); + + // Neither overlay has an image yet, so the combined renderer should be null. + constexpr gfx::Rect kRegionInFrame = gfx::Rect(kSize); + EXPECT_FALSE(VideoCaptureOverlay::MakeCombinedRenderer( + overlays, kRegionInFrame, kI420Format, GetLinearRec709())); + + // If just the first overlay renders, the combined renderer should not be + // null. + overlays[0]->SetImageAndBounds(MakeTestBitmap(0), gfx::RectF(0, 0, 1, 1)); + EXPECT_TRUE(VideoCaptureOverlay::MakeCombinedRenderer( + overlays, kRegionInFrame, kI420Format, GetLinearRec709())); + + // If both overlays render, the combined renderer should not be null. + overlays[1]->SetImageAndBounds(MakeTestBitmap(1), gfx::RectF(0, 0, 1, 1)); + EXPECT_TRUE(VideoCaptureOverlay::MakeCombinedRenderer( + overlays, kRegionInFrame, kI420Format, GetLinearRec709())); + + // If only the second overlay renders, because the first is hidden, the + // combined renderer should not be null. + overlays[0]->SetBounds(gfx::RectF()); + EXPECT_TRUE(VideoCaptureOverlay::MakeCombinedRenderer( + overlays, kRegionInFrame, kI420Format, GetLinearRec709())); + + // Both overlays are hidden, so the combined renderer should be null. + overlays[1]->SetBounds(gfx::RectF()); + EXPECT_FALSE(VideoCaptureOverlay::MakeCombinedRenderer( + overlays, kRegionInFrame, kI420Format, GetLinearRec709())); +} + +class VideoCaptureOverlayRenderTest + : public VideoCaptureOverlayTest, + public testing::WithParamInterface<VideoPixelFormat> { + public: + VideoCaptureOverlayRenderTest() + : trace_(__FILE__, __LINE__, VideoPixelFormatToString(pixel_format())) {} + + VideoPixelFormat pixel_format() const { return GetParam(); } + + bool is_argb_test() const { + return pixel_format() == media::PIXEL_FORMAT_ARGB; + } + + gfx::ColorSpace GetColorSpace() const { + // For these tests, we use linear RGB and YUV color spaces. This is because + // VideoCaptureOverlay does not account for non-linear color spaces when + // blending. See class notes. + return is_argb_test() ? GetLinearSRGB() : GetLinearRec709(); + } + + scoped_refptr<VideoFrame> CreateVideoFrame(const gfx::Size& size) const { + auto frame = VideoFrame::CreateFrame(pixel_format(), size, gfx::Rect(size), + size, base::TimeDelta()); + + // Fill the video frame with black. For ARGB tests, also set alpha channel + // to 1.0. This allows the expected results of the ARGB tests to be the same + // as those of the YUV tests, and so only one set of golden files needs to + // be used. + if (is_argb_test()) { + uint8_t* dst = frame->visible_data(VideoFrame::kARGBPlane); + const int stride = frame->stride(VideoFrame::kARGBPlane); + for (int row = 0; row < size.height(); ++row, dst += stride) { + uint32_t* const begin = reinterpret_cast<uint32_t*>(dst); + std::fill(begin, begin + size.width(), UINT32_C(0xff000000)); + } + } else /* if (!is_argb_test()) */ { + media::FillYUV(frame.get(), 0x00, 0x80, 0x80); + } + + frame->set_color_space(GetColorSpace()); + return frame; + } + + bool FrameMatchesPNG(const VideoFrame& frame, const char* golden_file) { + const gfx::ColorSpace png_color_space = GetLinearSRGB(); + // Note: Using kUnpremul_SkAlphaType since that is the semantics of + // PIXEL_FORMAT_ARGB, and converting to kPremul_SkAlphaType before producing + // the PNG would lose precision for no good reason. + const SkImageInfo canonical_format = SkImageInfo::Make( + frame.visible_rect().width(), frame.visible_rect().height(), + kN32_SkColorType, kUnpremul_SkAlphaType, + png_color_space.ToSkColorSpace()); + SkBitmap canonical_bitmap; + CHECK(canonical_bitmap.tryAllocPixels(canonical_format, 0)); + + // Populate |canonical_bitmap| with data from the frame. For I420, use + // gfx::ColorTransform to map back from YUV→RGB. + switch (frame.format()) { + case media::PIXEL_FORMAT_ARGB: { + // Map from the video frame's ARGB format to the canonical + // representation. + const SkImageInfo frame_format = SkImageInfo::Make( + frame.visible_rect().width(), frame.visible_rect().height(), + kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, + frame.ColorSpace().ToSkColorSpace()); + canonical_bitmap.writePixels( + SkPixmap(frame_format, frame.visible_data(VideoFrame::kARGBPlane), + frame.stride(VideoFrame::kARGBPlane)), + 0, 0); + break; + } + + case media::PIXEL_FORMAT_I420: { + // Map from I420 planar [0,255] (of which only [16,235] is used) values + // to interleaved [0.0,1.0] values. + const gfx::Size& size = frame.visible_rect().size(); + std::unique_ptr<gfx::ColorTransform::TriStim[]> colors( + new gfx::ColorTransform::TriStim[size.GetArea()]); + int pos = 0; + for (int row = 0; row < size.height(); ++row) { + const uint8_t* y = frame.visible_data(VideoFrame::kYPlane) + + (row * frame.stride(VideoFrame::kYPlane)); + const uint8_t* u = frame.visible_data(VideoFrame::kUPlane) + + ((row / 2) * frame.stride(VideoFrame::kUPlane)); + const uint8_t* v = frame.visible_data(VideoFrame::kVPlane) + + ((row / 2) * frame.stride(VideoFrame::kVPlane)); + for (int col = 0; col < size.width(); ++col) { + colors[pos].SetPoint(y[col] / 255.0f, u[col / 2] / 255.0f, + v[col / 2] / 255.0f); + ++pos; + } + } + + // Execute the YUV→RGB conversion. + gfx::ColorTransform::NewColorTransform( + frame.ColorSpace(), png_color_space, + gfx::ColorTransform::Intent::INTENT_ABSOLUTE) + ->Transform(colors.get(), size.GetArea()); + + // Map back from interleaved [0.0,1.0] values to intervealed ARGB, + // setting alpha=100%. + const auto ToClamped255 = [](float value) -> uint32_t { + value = (value * 255.0f) + 0.5f /* rounding */; + return base::saturated_cast<uint8_t>(value); + }; + pos = 0; + for (int row = 0; row < size.height(); ++row) { + uint32_t* out = canonical_bitmap.getAddr32(0, row); + for (int col = 0; col < size.width(); ++col) { + out[col] = ((UINT32_C(255) << SK_A32_SHIFT) | + (ToClamped255(colors[pos].x()) << SK_R32_SHIFT) | + (ToClamped255(colors[pos].y()) << SK_G32_SHIFT) | + (ToClamped255(colors[pos].z()) << SK_B32_SHIFT)); + ++pos; + } + } + + break; + } + + default: + NOTREACHED(); + return false; + } + + // Determine the full path to the golden file to compare the results. + base::FilePath golden_file_path; + base::PathService::Get(Paths::DIR_TEST_DATA, &golden_file_path); + golden_file_path = + golden_file_path.Append(FILE_PATH_LITERAL("video_capture")) + .Append(base::FilePath::FromUTF8Unsafe(golden_file)); + + // If the very-specific command-line switch is present, rewrite the golden + // file. This is only done when the ARGB test runs, for the reasons outlined + // in the comments below (regarding FuzzyPixelComparator). + if (is_argb_test() && + base::CommandLine::ForCurrentProcess()->HasSwitch( + "video-overlay-capture-test-update-golden-files")) { + LOG(INFO) << "Rewriting golden file: " << golden_file_path.AsUTF8Unsafe(); + cc::WritePNGFile(canonical_bitmap, golden_file_path, false); + } + + // FuzzyPixelComparator configuration: Allow 100% of pixels to mismatch, but + // no single pixel component should be different by more than 1/255 (64/255 + // for YUV tests), and the absolute average error must not exceed 1/255 + // (16/255 for YUV tests). The YUV tests allow for more error due to the + // expected errors introduced by both color space (dynamic range) and format + // (chroma subsampling) conversion. + cc::FuzzyPixelComparator comparator(false, 100.0f, 0.0f, + is_argb_test() ? 1.0f : 16.0f, + is_argb_test() ? 1 : 64, 0); + const bool matches_golden_file = + cc::MatchesPNGFile(canonical_bitmap, golden_file_path, comparator); + // If MatchesPNGFile() returned false, it will have LOG(ERROR)'ed the + // expected versus actual PNG data URLs. So, only do the VLOG(1)'s when + // MatchesPNGFile() returned true. + if (matches_golden_file && VLOG_IS_ON(1)) { + SkBitmap expected; + if (cc::ReadPNGFile(golden_file_path, &expected)) { + VLOG(1) << "Expected bitmap: " << cc::GetPNGDataUrl(expected); + } + VLOG(1) << "Actual bitmap: " << cc::GetPNGDataUrl(canonical_bitmap); + } + return matches_golden_file; + } + + // The size of the compositor frame sink's Surface. + static constexpr gfx::Size kSourceSize = gfx::Size(96, 40); + + private: + testing::ScopedTrace trace_; + + DISALLOW_COPY_AND_ASSIGN(VideoCaptureOverlayRenderTest); +}; + +// static +constexpr gfx::Size VideoCaptureOverlayRenderTest::kSourceSize; + +// Basic test: Render an overlay image that covers the entire video frame and is +// not scaled. +TEST_P(VideoCaptureOverlayRenderTest, FullCover_NoScaling) { + StrictMock<MockFrameSource> frame_source; + VideoCaptureOverlay overlay(&frame_source); + + EXPECT_CALL(frame_source, GetSourceSize()) + .WillRepeatedly(Return(kSourceSize)); + EXPECT_CALL(frame_source, InvalidateRect(gfx::Rect())).RetiresOnSaturation(); + EXPECT_CALL(frame_source, InvalidateRect(gfx::Rect(kSourceSize))) + .RetiresOnSaturation(); + EXPECT_CALL(frame_source, RequestRefreshFrame()); + + const SkBitmap test_bitmap = MakeTestBitmap(0); + overlay.SetImageAndBounds(test_bitmap, gfx::RectF(0, 0, 1, 1)); + const gfx::Size output_size(test_bitmap.width(), test_bitmap.height()); + VideoCaptureOverlay::OnceRenderer renderer = overlay.MakeRenderer( + gfx::Rect(output_size), pixel_format(), GetColorSpace()); + ASSERT_TRUE(renderer); + auto frame = CreateVideoFrame(output_size); + std::move(renderer).Run(frame.get()); + EXPECT_TRUE(FrameMatchesPNG(*frame, "overlay_full_cover.png")); +} + +// Basic test: Render an overlay image that covers the entire video frame and is +// scaled. +TEST_P(VideoCaptureOverlayRenderTest, FullCover_WithScaling) { + StrictMock<MockFrameSource> frame_source; + VideoCaptureOverlay overlay(&frame_source); + + EXPECT_CALL(frame_source, GetSourceSize()) + .WillRepeatedly(Return(kSourceSize)); + EXPECT_CALL(frame_source, InvalidateRect(gfx::Rect())).RetiresOnSaturation(); + EXPECT_CALL(frame_source, InvalidateRect(gfx::Rect(kSourceSize))) + .RetiresOnSaturation(); + EXPECT_CALL(frame_source, RequestRefreshFrame()); + + const SkBitmap test_bitmap = MakeTestBitmap(0); + overlay.SetImageAndBounds(test_bitmap, gfx::RectF(0, 0, 1, 1)); + const gfx::Size output_size(test_bitmap.width() * 4, + test_bitmap.height() * 4); + VideoCaptureOverlay::OnceRenderer renderer = overlay.MakeRenderer( + gfx::Rect(output_size), pixel_format(), GetColorSpace()); + ASSERT_TRUE(renderer); + auto frame = CreateVideoFrame(output_size); + std::move(renderer).Run(frame.get()); + EXPECT_TRUE(FrameMatchesPNG(*frame, "overlay_full_cover_scaled.png")); +} + +// Tests that changing the position of the overlay results in it being rendered +// at different locations in the video frame. +TEST_P(VideoCaptureOverlayRenderTest, MovesAround) { + NiceMock<MockFrameSource> frame_source; + EXPECT_CALL(frame_source, GetSourceSize()) + .WillRepeatedly(Return(kSourceSize)); + VideoCaptureOverlay overlay(&frame_source); + + const SkBitmap test_bitmap = MakeTestBitmap(0); + const gfx::Size frame_size(test_bitmap.width() * 4, test_bitmap.height() * 4); + + const gfx::RectF relative_image_bounds[6] = { + gfx::RectF(0.0f, 0.0f, 0.5f, 0.5f), + gfx::RectF(1.0f / frame_size.width(), 0.0f, 0.5f, 0.5f), + gfx::RectF(2.0f / frame_size.width(), 0.0f, 0.5f, 0.5f), + gfx::RectF(2.0f / frame_size.width(), 1.0f / frame_size.height(), 0.5f, + 0.5f), + gfx::RectF(2.0f / frame_size.width(), 2.0f / frame_size.height(), 0.5f, + 0.5f), + gfx::RectF(0.5f, 0.5f, 0.5f, 0.5f), + }; + + VideoCaptureOverlay::OnceRenderer renderers[6]; + for (int i = 0; i < 6; ++i) { + if (i == 0) { + overlay.SetImageAndBounds(test_bitmap, relative_image_bounds[i]); + } else { + overlay.SetBounds(relative_image_bounds[i]); + } + renderers[i] = overlay.MakeRenderer(gfx::Rect(frame_size), pixel_format(), + GetColorSpace()); + } + + constexpr std::array<const char*, 6> kGoldenFiles = { + "overlay_moves_0_0.png", "overlay_moves_1_0.png", "overlay_moves_2_0.png", + "overlay_moves_2_1.png", "overlay_moves_2_2.png", "overlay_moves_lr.png", + }; + + for (int i = 0; i < 6; ++i) { + SCOPED_TRACE(testing::Message() << "relative_image_bounds=" + << relative_image_bounds[i].ToString() + << ", frame_size=" << frame_size.ToString() + << ", golden_file=" << kGoldenFiles[i]); + auto frame = CreateVideoFrame(frame_size); + std::move(renderers[i]).Run(frame.get()); + EXPECT_TRUE(FrameMatchesPNG(*frame, kGoldenFiles[i])); + } +} + +// Tests that the overlay will be partially rendered (clipped) when any part of +// it extends outside the video frame's content region. +// +// For this test, the content region is a rectangle, centered within the frame +// (e.g., the content is being letterboxed), and the test attempts to locate the +// overlay such that part of it should be clipped. The test succeeds if the +// overlay is clipped to the content region in the center. For example: +// +// +-------------------------------+ +// | | +// | ...... | +// | ..****//////////// | **** the drawn part of the overlay +// | ..****CONTENT///// | +// | /////REGION///// | .... the clipped part of the overlay +// | //////////////// | (i.e., not drawn) +// | | +// | | +// +-------------------------------+ +TEST_P(VideoCaptureOverlayRenderTest, ClipsToContentBounds) { + NiceMock<MockFrameSource> frame_source; + EXPECT_CALL(frame_source, GetSourceSize()) + .WillRepeatedly(Return(kSourceSize)); + VideoCaptureOverlay overlay(&frame_source); + + const SkBitmap test_bitmap = MakeTestBitmap(0); + const gfx::Size frame_size(test_bitmap.width() * 4, test_bitmap.height() * 4); + const gfx::Rect region_in_frame(test_bitmap.width(), test_bitmap.height(), + test_bitmap.width() * 2, + test_bitmap.height() * 2); + + const gfx::RectF relative_image_bounds[4] = { + gfx::RectF(-0.25f, -0.25f, 0.5f, 0.5f), + gfx::RectF(0.75f, -0.25f, 0.5f, 0.5f), + gfx::RectF(0.75f, 0.75f, 0.5f, 0.5f), + gfx::RectF(-0.25f, 0.75f, 0.5f, 0.5f), + }; + + VideoCaptureOverlay::OnceRenderer renderers[4]; + for (int i = 0; i < 4; ++i) { + if (i == 0) { + overlay.SetImageAndBounds(test_bitmap, relative_image_bounds[i]); + } else { + overlay.SetBounds(relative_image_bounds[i]); + } + renderers[i] = + overlay.MakeRenderer(region_in_frame, pixel_format(), GetColorSpace()); + } + + constexpr std::array<const char*, 4> kGoldenFiles = { + "overlay_clips_ul.png", "overlay_clips_ur.png", "overlay_clips_lr.png", + "overlay_clips_ll.png", + }; + + for (int i = 0; i < 4; ++i) { + auto frame = CreateVideoFrame(frame_size); + std::move(renderers[i]).Run(frame.get()); + EXPECT_TRUE(FrameMatchesPNG(*frame, kGoldenFiles[i])); + } +} + +INSTANTIATE_TEST_CASE_P( + , + VideoCaptureOverlayRenderTest, + testing::Values(VideoCaptureOverlayRenderTest::kARGBFormat, + VideoCaptureOverlayRenderTest::kI420Format)); + +} // namespace +} // namespace viz
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc index b74efab..dc9c682 100644 --- a/components/viz/service/surfaces/surface.cc +++ b/components/viz/service/surfaces/surface.cc
@@ -408,6 +408,14 @@ if (!track_dependencies) continue; + TRACE_EVENT_WITH_FLOW2( + TRACE_DISABLED_BY_DEFAULT("viz.surface_id_flow"), + "LocalSurfaceId.Embed.Flow", + TRACE_ID_GLOBAL(surface_id.local_surface_id().embed_trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", + "AddedActivationDependency", "child_surface_id", + surface_id.ToString()); + // Record the latest |parent_sequence_number| this surface is interested // in observing for the provided FrameSinkId. uint32_t& parent_sequence_number =
diff --git a/components/viz/test/data/video_capture/overlay_clips_ll.png b/components/viz/test/data/video_capture/overlay_clips_ll.png new file mode 100644 index 0000000..7faf623c --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_clips_ll.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_clips_lr.png b/components/viz/test/data/video_capture/overlay_clips_lr.png new file mode 100644 index 0000000..1eaf92c --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_clips_lr.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_clips_ul.png b/components/viz/test/data/video_capture/overlay_clips_ul.png new file mode 100644 index 0000000..f89dc43 --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_clips_ul.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_clips_ur.png b/components/viz/test/data/video_capture/overlay_clips_ur.png new file mode 100644 index 0000000..416b1c59 --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_clips_ur.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_full_cover.png b/components/viz/test/data/video_capture/overlay_full_cover.png new file mode 100644 index 0000000..b2aacf7c --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_full_cover.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_full_cover_scaled.png b/components/viz/test/data/video_capture/overlay_full_cover_scaled.png new file mode 100644 index 0000000..2485016 --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_full_cover_scaled.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_moves_0_0.png b/components/viz/test/data/video_capture/overlay_moves_0_0.png new file mode 100644 index 0000000..f2efc15 --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_moves_0_0.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_moves_1_0.png b/components/viz/test/data/video_capture/overlay_moves_1_0.png new file mode 100644 index 0000000..0bf0a55 --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_moves_1_0.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_moves_2_0.png b/components/viz/test/data/video_capture/overlay_moves_2_0.png new file mode 100644 index 0000000..62668ce --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_moves_2_0.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_moves_2_1.png b/components/viz/test/data/video_capture/overlay_moves_2_1.png new file mode 100644 index 0000000..aa26331 --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_moves_2_1.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_moves_2_2.png b/components/viz/test/data/video_capture/overlay_moves_2_2.png new file mode 100644 index 0000000..04b9a350 --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_moves_2_2.png Binary files differ
diff --git a/components/viz/test/data/video_capture/overlay_moves_lr.png b/components/viz/test/data/video_capture/overlay_moves_lr.png new file mode 100644 index 0000000..352b6e4a --- /dev/null +++ b/components/viz/test/data/video_capture/overlay_moves_lr.png Binary files differ
diff --git a/components/web_contents_delegate_android/BUILD.gn b/components/web_contents_delegate_android/BUILD.gn deleted file mode 100644 index 7c83085..0000000 --- a/components/web_contents_delegate_android/BUILD.gn +++ /dev/null
@@ -1,114 +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. - -import("//build/config/android/rules.gni") - -java_strings_grd("web_contents_delegate_android_strings_grd") { - grd_file = "java/strings/web_contents_delegate_android_strings.grd" - outputs = [ - "values-am/web_contents_delegate_android_strings.xml", - "values-ar/web_contents_delegate_android_strings.xml", - "values-bg/web_contents_delegate_android_strings.xml", - "values-ca/web_contents_delegate_android_strings.xml", - "values-cs/web_contents_delegate_android_strings.xml", - "values-da/web_contents_delegate_android_strings.xml", - "values-de/web_contents_delegate_android_strings.xml", - "values-el/web_contents_delegate_android_strings.xml", - "values/web_contents_delegate_android_strings.xml", - "values-en-rGB/web_contents_delegate_android_strings.xml", - "values-es/web_contents_delegate_android_strings.xml", - "values-es-rUS/web_contents_delegate_android_strings.xml", - "values-fa/web_contents_delegate_android_strings.xml", - "values-fi/web_contents_delegate_android_strings.xml", - "values-tl/web_contents_delegate_android_strings.xml", - "values-fr/web_contents_delegate_android_strings.xml", - "values-hi/web_contents_delegate_android_strings.xml", - "values-hr/web_contents_delegate_android_strings.xml", - "values-hu/web_contents_delegate_android_strings.xml", - "values-in/web_contents_delegate_android_strings.xml", - "values-it/web_contents_delegate_android_strings.xml", - "values-iw/web_contents_delegate_android_strings.xml", - "values-ja/web_contents_delegate_android_strings.xml", - "values-ko/web_contents_delegate_android_strings.xml", - "values-lt/web_contents_delegate_android_strings.xml", - "values-lv/web_contents_delegate_android_strings.xml", - "values-nl/web_contents_delegate_android_strings.xml", - "values-nb/web_contents_delegate_android_strings.xml", - "values-pl/web_contents_delegate_android_strings.xml", - "values-pt-rBR/web_contents_delegate_android_strings.xml", - "values-pt-rPT/web_contents_delegate_android_strings.xml", - "values-ro/web_contents_delegate_android_strings.xml", - "values-ru/web_contents_delegate_android_strings.xml", - "values-sk/web_contents_delegate_android_strings.xml", - "values-sl/web_contents_delegate_android_strings.xml", - "values-sr/web_contents_delegate_android_strings.xml", - "values-sv/web_contents_delegate_android_strings.xml", - "values-sw/web_contents_delegate_android_strings.xml", - "values-th/web_contents_delegate_android_strings.xml", - "values-tr/web_contents_delegate_android_strings.xml", - "values-uk/web_contents_delegate_android_strings.xml", - "values-vi/web_contents_delegate_android_strings.xml", - "values-zh-rCN/web_contents_delegate_android_strings.xml", - "values-zh-rTW/web_contents_delegate_android_strings.xml", - ] -} - -static_library("web_contents_delegate_android") { - sources = [ - "color_chooser_android.cc", - "color_chooser_android.h", - "web_contents_delegate_android.cc", - "web_contents_delegate_android.h", - ] - - deps = [ - ":web_contents_delegate_android_jni_headers", - "//base", - "//content/public/browser", - "//content/public/common", - "//net", - "//skia", - "//ui/android", - "//ui/base", - "//ui/gfx", - "//ui/gfx/geometry", - ] -} - -android_resources("web_contents_delegate_android_java_resources") { - custom_package = "org.chromium.components.web_contents_delegate_android" - resource_dirs = [ "java/res" ] - deps = [ - ":web_contents_delegate_android_strings_grd", - ] -} - -android_library("web_contents_delegate_android_java") { - deps = [ - ":web_contents_delegate_android_java_resources", - "//base:base_java", - "//content/public/android:content_java", - "//ui/android:ui_java", - ] - java_files = [ - "java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java", - "java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvanced.java", - "java/src/org/chromium/components/web_contents_delegate_android/ColorPickerAdvancedComponent.java", - "java/src/org/chromium/components/web_contents_delegate_android/ColorPickerDialog.java", - "java/src/org/chromium/components/web_contents_delegate_android/ColorPickerMoreButton.java", - "java/src/org/chromium/components/web_contents_delegate_android/ColorPickerSimple.java", - "java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestion.java", - "java/src/org/chromium/components/web_contents_delegate_android/ColorSuggestionListAdapter.java", - "java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java", - "java/src/org/chromium/components/web_contents_delegate_android/OnColorChangedListener.java", - ] -} - -generate_jni("web_contents_delegate_android_jni_headers") { - sources = [ - "java/src/org/chromium/components/web_contents_delegate_android/ColorChooserAndroid.java", - "java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java", - ] - jni_package = "web_contents_delegate_android" -}
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index 2c2b314..091031a 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc
@@ -312,7 +312,6 @@ DownloadManagerImpl::~DownloadManagerImpl() { DCHECK(!shutdown_needed_); - download::SetIOTaskRunner(nullptr); } download::DownloadItemImpl* DownloadManagerImpl::CreateActiveItem(
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index 075eeed..d42c8c0b 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -1294,6 +1294,13 @@ browser_context, navigating_frame_host->GetSiteInstance()); DCHECK(partition); + // |loader_| should not exist if the service worker handle and app cache + // handles will be destroyed, since it holds raw pointers to them. See the + // comment in the header for |loader_|. + // TODO(falken): Turn this into a DCHECK if it holds, or else manually call + // loader_.reset() here. + CHECK(!loader_); + // Only initialize the ServiceWorkerNavigationHandle if it can be created for // this frame. bool can_create_service_worker =
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc index 6dde8e24..8dc3131 100644 --- a/content/browser/indexed_db/indexed_db_backing_store.cc +++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -3072,9 +3072,7 @@ } void IndexedDBBackingStore::ForceRunBlobCleanup() { - base::OnceClosure task = journal_cleaning_timer_.user_task(); - journal_cleaning_timer_.AbandonAndStop(); - std::move(task).Run(); + journal_cleaning_timer_.FireNow(); } IndexedDBBackingStore::Transaction::Transaction(
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc index 9f752ba..0031ef8 100644 --- a/content/browser/indexed_db/indexed_db_factory_unittest.cc +++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -212,7 +212,7 @@ EXPECT_FALSE(store_ptr->close_timer()->IsRunning()); factory->TestReleaseBackingStore(store_ptr, false); EXPECT_TRUE(store_ptr->close_timer()->IsRunning()); - store_ptr->close_timer()->user_task().Run(); + store_ptr->close_timer()->FireNow(); // Backing store should be totally closed. EXPECT_FALSE(factory->IsBackingStoreOpen(origin)); @@ -228,7 +228,7 @@ // Sweep should NOT be occurring. EXPECT_TRUE(store_ptr->close_timer()->IsRunning()); - store_ptr->close_timer()->user_task().Run(); + store_ptr->close_timer()->FireNow(); // Backing store should be totally closed. EXPECT_FALSE(factory->IsBackingStoreOpen(origin)); @@ -271,7 +271,7 @@ EXPECT_FALSE(store_ptr->close_timer()->IsRunning()); factory->TestReleaseBackingStore(store_ptr, false); EXPECT_TRUE(store_ptr->close_timer()->IsRunning()); - store_ptr->close_timer()->user_task().Run(); + store_ptr->close_timer()->FireNow(); // Backing store should be totally closed. EXPECT_FALSE(factory->IsBackingStoreOpen(origin)); @@ -287,8 +287,7 @@ // Sweep should be occuring. EXPECT_TRUE(store_ptr->close_timer()->IsRunning()); - store_ptr->close_timer()->user_task().Run(); - store_ptr->close_timer()->AbandonAndStop(); + store_ptr->close_timer()->FireNow(); ASSERT_NE(nullptr, store_ptr->pre_close_task_queue()); EXPECT_TRUE(store_ptr->pre_close_task_queue()->started()); @@ -312,8 +311,7 @@ // Sweep should be occuring. EXPECT_TRUE(store_ptr->close_timer()->IsRunning()); - store_ptr->close_timer()->user_task().Run(); - store_ptr->close_timer()->AbandonAndStop(); + store_ptr->close_timer()->FireNow(); ASSERT_NE(nullptr, store_ptr->pre_close_task_queue()); EXPECT_TRUE(store_ptr->pre_close_task_queue()->started());
diff --git a/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc b/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc index c10af2f5..a13243f 100644 --- a/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc +++ b/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc
@@ -102,9 +102,7 @@ TRACE_EVENT_INSTANT0("input", "MouseWheelPhaseHandler Dispatched", TRACE_EVENT_SCOPE_THREAD); - base::Closure task = mouse_wheel_end_dispatch_timer_.user_task(); - mouse_wheel_end_dispatch_timer_.Stop(); - std::move(task).Run(); + mouse_wheel_end_dispatch_timer_.FireNow(); } void MouseWheelPhaseHandler::IgnorePendingWheelEndEvent() {
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc index d39e1392..c7e802e 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -537,8 +537,6 @@ gfx::ConvertPointToPixel(device_scale_factor, point); viz::SurfaceId surface_id = GetCurrentSurfaceId(); if (!surface_id.is_valid()) { - // Force a query of the renderer if we don't have a surface id yet. - *out_query_renderer = true; return GetFrameSinkId(); } viz::SurfaceHittest hittest(delegate,
diff --git a/content/browser/webui/url_data_manager_backend.cc b/content/browser/webui/url_data_manager_backend.cc index 7fdaadd..d0560bd 100644 --- a/content/browser/webui/url_data_manager_backend.cc +++ b/content/browser/webui/url_data_manager_backend.cc
@@ -16,7 +16,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/ref_counted_memory.h" -#include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" @@ -405,18 +404,14 @@ } // namespace URLDataManagerBackend::URLDataManagerBackend() - : next_request_id_(0) { + : next_request_id_(0), weak_factory_(this) { URLDataSource* shared_source = new SharedResourcesDataSource(); URLDataSourceImpl* source_impl = new URLDataSourceImpl(shared_source->GetSource(), shared_source); AddDataSource(source_impl); } -URLDataManagerBackend::~URLDataManagerBackend() { - for (const auto& i : data_sources_) - i.second->backend_ = nullptr; - data_sources_.clear(); -} +URLDataManagerBackend::~URLDataManagerBackend() = default; // static std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler> @@ -431,14 +426,13 @@ void URLDataManagerBackend::AddDataSource( URLDataSourceImpl* source) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - DataSourceMap::iterator i = data_sources_.find(source->source_name()); - if (i != data_sources_.end()) { - if (!source->source()->ShouldReplaceExistingSource()) + if (!source->source()->ShouldReplaceExistingSource()) { + DataSourceMap::iterator i = data_sources_.find(source->source_name()); + if (i != data_sources_.end()) return; - i->second->backend_ = nullptr; } data_sources_[source->source_name()] = source; - source->backend_ = this; + source->backend_ = weak_factory_.GetWeakPtr(); } void URLDataManagerBackend::UpdateWebUIDataSource(
diff --git a/content/browser/webui/url_data_manager_backend.h b/content/browser/webui/url_data_manager_backend.h index a6f3ab91..d5009883 100644 --- a/content/browser/webui/url_data_manager_backend.h +++ b/content/browser/webui/url_data_manager_backend.h
@@ -12,6 +12,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/supports_user_data.h" #include "base/values.h" #include "content/browser/webui/url_data_manager.h" @@ -123,6 +124,12 @@ // The ID we'll use for the next request we receive. RequestID next_request_id_; + // Vends weak pointers to URLDataSources, allowing them to continue referring + // to the backend that originally owned them, even if they've been replaced + // and detached from the backend. This allows outstanding asynchronous queries + // to be served and routed to the backend to which they were original issued. + base::WeakPtrFactory<URLDataManagerBackend> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(URLDataManagerBackend); };
diff --git a/content/browser/webui/url_data_source_impl.h b/content/browser/webui/url_data_source_impl.h index 77c2e97..62cbd439 100644 --- a/content/browser/webui/url_data_source_impl.h +++ b/content/browser/webui/url_data_source_impl.h
@@ -9,6 +9,7 @@ #include <string> #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "base/sequenced_task_runner_helpers.h" #include "content/browser/webui/url_data_manager.h" #include "content/common/content_export.h" @@ -90,13 +91,18 @@ const std::string source_name_; // This field is set and maintained by URLDataManagerBackend. It is set when - // the DataSource is added, and unset if the DataSource is removed. A - // DataSource can be removed in two ways: the URLDataManagerBackend is - // deleted, or another DataSource is registered with the same name. backend_ - // should only be accessed on the IO thread. This reference can't be via a - // scoped_refptr else there would be a cycle between the backend and data - // source. - URLDataManagerBackend* backend_; + // the DataSource is added. A DataSource can be removed in two ways: + // (1) The URLDataManagerBackend is deleted, and the weak ptr is invalidated. + // In this case queries pending against this data source will implicitly + // be dropped as their responses will have no backend for routing. + // (2) Another DataSource is registered with the same name. In this case the + // backend still exists and remains referenced by this data source, + // allowing pending queries to be routed to the backend that formerly + // owned them. + // This field should only be referenced on the IO thread. This reference can't + // be via a scoped_refptr else there would be a cycle between the backend and + // the data source. + base::WeakPtr<URLDataManagerBackend> backend_; std::unique_ptr<URLDataSource> source_; };
diff --git a/content/public/common/previews_state.h b/content/public/common/previews_state.h index 3b0d8d9d..e5ab4b7 100644 --- a/content/public/common/previews_state.h +++ b/content/public/common/previews_state.h
@@ -40,7 +40,9 @@ NOSCRIPT_ON = 1 << 6, // Request that script be disabled for page load. RESOURCE_LOADING_HINTS_ON = 1 << 7, // Request that resource loading hints be used during pageload. - PREVIEWS_STATE_LAST = RESOURCE_LOADING_HINTS_ON + OFFLINE_PAGE_ON = + 1 << 8, // Request that an offline page be used if one is stored. + PREVIEWS_STATE_LAST = OFFLINE_PAGE_ON }; // Combination of all previews that are guaranteed not to provide partial @@ -65,6 +67,8 @@ STATIC_ASSERT_PREVIEWS_ENUM(NOSCRIPT_ON, blink::WebURLRequest::kNoScriptOn); STATIC_ASSERT_PREVIEWS_ENUM(RESOURCE_LOADING_HINTS_ON, blink::WebURLRequest::kResourceLoadingHintsOn); +STATIC_ASSERT_PREVIEWS_ENUM(OFFLINE_PAGE_ON, + blink::WebURLRequest::kOfflinePageOn); STATIC_ASSERT_PREVIEWS_ENUM(PREVIEWS_STATE_LAST, blink::WebURLRequest::kPreviewsStateLast);
diff --git a/content/test/data/accessibility/event/live-region-change-expected-win.txt b/content/test/data/accessibility/event/live-region-change-expected-win.txt index db735e05..8a07480 100644 --- a/content/test/data/accessibility/event/live-region-change-expected-win.txt +++ b/content/test/data/accessibility/event/live-region-change-expected-win.txt
@@ -1,6 +1,4 @@ EVENT_OBJECT_LIVEREGIONCHANGED on <div#live> role=DIV EVENT_OBJECT_NAMECHANGE on role=ROLE_SYSTEM_STATICTEXT name="After" IA2_EVENT_TEXT_INSERTED on <div#live> role=DIV new_text={'After' start=0 end=5} -IA2_EVENT_TEXT_INSERTED on role=ROLE_SYSTEM_STATICTEXT name="After" new_text={'After' start=0 end=5} IA2_EVENT_TEXT_REMOVED on <div#live> role=DIV old_text={'Before' start=0 end=6} -IA2_EVENT_TEXT_REMOVED on role=ROLE_SYSTEM_STATICTEXT name="After" old_text={'Before' start=0 end=6}
diff --git a/content/test/data/accessibility/event/text-changed-expected-win.txt b/content/test/data/accessibility/event/text-changed-expected-win.txt index c6357f5..a590526 100644 --- a/content/test/data/accessibility/event/text-changed-expected-win.txt +++ b/content/test/data/accessibility/event/text-changed-expected-win.txt
@@ -5,7 +5,4 @@ IA2_EVENT_TEXT_INSERTED on <div> role=DIV name="div" new_text={'Text modified' start=0 end=13} IA2_EVENT_TEXT_INSERTED on <h2#h> role=H2 name="Heading" level=2 new_text={'Modified ' start=0 end=9} IA2_EVENT_TEXT_INSERTED on <p#p> role=P new_text={'Modified ' start=0 end=9} -IA2_EVENT_TEXT_INSERTED on role=ROLE_SYSTEM_STATICTEXT name="Modified Heading" new_text={'Modified ' start=0 end=9} -IA2_EVENT_TEXT_INSERTED on role=ROLE_SYSTEM_STATICTEXT name="Text modified" new_text={'Text modified' start=0 end=13} IA2_EVENT_TEXT_REMOVED on <div> role=DIV name="div" old_text={'Div' start=0 end=3} -IA2_EVENT_TEXT_REMOVED on role=ROLE_SYSTEM_STATICTEXT name="Text modified" old_text={'Div' start=0 end=3}
diff --git a/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py b/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py index 17d756e..c3328e6 100644 --- a/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py +++ b/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py
@@ -2,7 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import math import os import random import sys @@ -120,17 +119,9 @@ "window.draw({{ red }}, {{ green }}, {{ blue }});", red=canvasRGB.r, green=canvasRGB.g, blue=canvasRGB.b) screenshot = tab.Screenshot(10) - # Avoid checking along antialiased boundary due to limited Adreno 3xx - # interpolation precision (crbug.com/847984). We inset by one CSS pixel - # adjusted by the device pixel ratio. - inset = int(math.ceil(tab.EvaluateJavaScript('window.devicePixelRatio'))) - # In the div version of the test the inner div's absolute position has - # left = 1. We need to account for that in start_x. - # For reasons not fully understood we must inset an additional pixel on - # mac_chromium_rel_ng - start_x = 2 * inset + 1 - start_y = inset - outer_size = 256 - inset + start_x = 10 + start_y = 0 + outer_size = 256 skip = 10 for y in range(start_y, outer_size, skip): for x in range(start_x, outer_size, skip):
diff --git a/device/base/features.cc b/device/base/features.cc index 19501b43..eaf9cd93f 100644 --- a/device/base/features.cc +++ b/device/base/features.cc
@@ -15,11 +15,16 @@ base::FEATURE_DISABLED_BY_DEFAULT}; #endif // defined(OS_WIN) -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if defined(OS_CHROMEOS) // Enables or disables the use of newblue Bluetooth daemon on Chrome OS. const base::Feature kNewblueDaemon{"Newblue", base::FEATURE_DISABLED_BY_DEFAULT}; -#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) +// Shows all Bluetooth devices in UI (System Tray/Settings Page). +// Needed for working on the early integration with NewBlue. +// TODO(crbug.com/862492): Remove this feature once NewBlue gets stable. +const base::Feature kUnfilteredBluetoothDevices{ + "UnfilteredBluetoothDevices", base::FEATURE_DISABLED_BY_DEFAULT}; +#endif // defined(OS_CHROMEOS) #if defined(OS_MACOSX) // Controls whether the CTAP2 implementation should use a built-in platform
diff --git a/device/base/features.h b/device/base/features.h index e8f1c78..565df3ae 100644 --- a/device/base/features.h +++ b/device/base/features.h
@@ -16,9 +16,10 @@ DEVICE_BASE_EXPORT extern const base::Feature kNewBLEWinImplementation; #endif // defined(OS_WIN) -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if defined(OS_CHROMEOS) DEVICE_BASE_EXPORT extern const base::Feature kNewblueDaemon; -#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) +DEVICE_BASE_EXPORT extern const base::Feature kUnfilteredBluetoothDevices; +#endif // defined(OS_CHROMEOS) DEVICE_BASE_EXPORT extern const base::Feature kNewCtap2Device;
diff --git a/device/bluetooth/chromeos/bluetooth_utils.cc b/device/bluetooth/chromeos/bluetooth_utils.cc index 71f45bf0..fcc6450 100644 --- a/device/bluetooth/chromeos/bluetooth_utils.cc +++ b/device/bluetooth/chromeos/bluetooth_utils.cc
@@ -4,6 +4,9 @@ #include "device/bluetooth/chromeos/bluetooth_utils.h" +#include "base/feature_list.h" +#include "device/base/features.h" + namespace device { namespace { @@ -46,6 +49,9 @@ // Filter out unknown devices from the list. BluetoothAdapter::DeviceList FilterUnknownDevices( const BluetoothAdapter::DeviceList& devices) { + if (base::FeatureList::IsEnabled(device::kUnfilteredBluetoothDevices)) + return devices; + BluetoothAdapter::DeviceList result; for (BluetoothDevice* device : devices) { switch (device->GetType()) {
diff --git a/device/bluetooth/dbus/bluez_dbus_manager.cc b/device/bluetooth/dbus/bluez_dbus_manager.cc index a76d08a..c58018c9 100644 --- a/device/bluetooth/dbus/bluez_dbus_manager.cc +++ b/device/bluetooth/dbus/bluez_dbus_manager.cc
@@ -212,7 +212,12 @@ } std::string BluezDBusManager::GetBluetoothServiceName() { - return base::FeatureList::IsEnabled(device::kNewblueDaemon) + bool use_newblue = false; +#if defined(OS_CHROMEOS) + use_newblue = base::FeatureList::IsEnabled(device::kNewblueDaemon); +#endif // defined(OS_CHROMEOS) + + return use_newblue ? bluetooth_object_manager::kBluetoothObjectManagerServiceName : bluez_object_manager::kBluezObjectManagerServiceName; }
diff --git a/device/vr/OWNERS b/device/vr/OWNERS index 30239eea..1638f07 100644 --- a/device/vr/OWNERS +++ b/device/vr/OWNERS
@@ -5,4 +5,5 @@ per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS -# COMPONENT: Internals>VR +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR
diff --git a/device/vr/oculus/OWNERS b/device/vr/oculus/OWNERS index a166098..5b1397a 100644 --- a/device/vr/oculus/OWNERS +++ b/device/vr/oculus/OWNERS
@@ -1,2 +1,5 @@ per-file *_type_converter*.*=set noparent per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS + +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR>VR
diff --git a/device/vr/openvr/OWNERS b/device/vr/openvr/OWNERS index a166098..5b1397a 100644 --- a/device/vr/openvr/OWNERS +++ b/device/vr/openvr/OWNERS
@@ -1,2 +1,5 @@ per-file *_type_converter*.*=set noparent per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS + +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR>VR
diff --git a/device/vr/public/mojom/OWNERS b/device/vr/public/mojom/OWNERS index 08850f4..fd66a0a 100644 --- a/device/vr/public/mojom/OWNERS +++ b/device/vr/public/mojom/OWNERS
@@ -1,2 +1,5 @@ per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS + +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR
diff --git a/docs/chromoting_android_hacking.md b/docs/chromoting_android_hacking.md index 53ac53c..834b5e2 100644 --- a/docs/chromoting_android_hacking.md +++ b/docs/chromoting_android_hacking.md
@@ -54,7 +54,7 @@ <classpathentry kind="src" path="components/cronet/android/sample/src"/> <classpathentry kind="src" path="components/cronet/android/sample/javatests/src"/> <classpathentry kind="src" path="components/autofill/core/browser/android/java/src"/> -<classpathentry kind="src" path="components/web_contents_delegate_android/java/src"/> +<classpathentry kind="src" path="components/embedder_support/android/java/src"/> <classpathentry kind="src" path="components/dom_distiller/android/java/src"/> <classpathentry kind="src" path="components/navigation_interception/android/java/src"/> <classpathentry kind="src" path="ui/android/java/src"/>
diff --git a/extensions/browser/api/app_runtime/app_runtime_api.cc b/extensions/browser/api/app_runtime/app_runtime_api.cc index 76088287..c8489e6 100644 --- a/extensions/browser/api/app_runtime/app_runtime_api.cc +++ b/extensions/browser/api/app_runtime/app_runtime_api.cc
@@ -53,6 +53,9 @@ UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchSource", source, app_runtime::LaunchSource::LAUNCH_SOURCE_LAST + 1); + launch_data->SetBoolean("isDemoSession", + ExtensionsBrowserClient::Get()->IsInDemoMode()); + // "Forced app mode" is true for Chrome OS kiosk mode. launch_data->SetBoolean( "isKioskSession",
diff --git a/extensions/browser/api/declarative_net_request/rules_monitor_service.cc b/extensions/browser/api/declarative_net_request/rules_monitor_service.cc index a4bf991..48534bc 100644 --- a/extensions/browser/api/declarative_net_request/rules_monitor_service.cc +++ b/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
@@ -15,8 +15,10 @@ #include "base/task_scheduler/post_task.h" #include "base/threading/thread_restrictions.h" #include "content/public/browser/browser_thread.h" +#include "content/public/common/service_manager_connection.h" #include "extensions/browser/api/declarative_net_request/ruleset_manager.h" #include "extensions/browser/api/declarative_net_request/ruleset_matcher.h" +#include "extensions/browser/api/declarative_net_request/utils.h" #include "extensions/browser/extension_file_task_runner.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_prefs_factory.h" @@ -28,6 +30,7 @@ #include "extensions/common/api/declarative_net_request/utils.h" #include "extensions/common/extension_id.h" #include "extensions/common/file_util.h" +#include "services/service_manager/public/cpp/connector.h" namespace extensions { namespace declarative_net_request { @@ -95,7 +98,13 @@ // should only be accessed on the extension file task runner. class RulesMonitorService::FileSequenceState { public: - FileSequenceState() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } + FileSequenceState() + : connector_(content::ServiceManagerConnection::GetForProcess() + ->GetConnector() + ->Clone()), + weak_factory_(this) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + } ~FileSequenceState() { DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence()); @@ -108,6 +117,21 @@ // instance created, passing null on failure. void LoadRuleset(LoadRulesetInfo info, LoadRulesetUICallback ui_callback) const { + LoadRulesetInternal(std::move(info), std::move(ui_callback), + LoadFailedAction::kReindex); + } + + private: + // Describes the action to take if ruleset loading fails. + enum class LoadFailedAction { + kReindex, // Reindexes the JSON ruleset. + kSignalFailure, // Signals failure on the UI thread. + }; + + // Internal helper to load the ruleset for |info|. + void LoadRulesetInternal(LoadRulesetInfo info, + LoadRulesetUICallback ui_callback, + LoadFailedAction failed_action) const { DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence()); std::unique_ptr<RulesetMatcher> matcher; @@ -122,13 +146,70 @@ // |matcher| is valid only on success. DCHECK_EQ(result == RulesetMatcher::kLoadSuccess, !!matcher); - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::BindOnce(std::move(ui_callback), std::move(info), - std::move(matcher))); + const bool reindex_ruleset = result != RulesetMatcher::kLoadSuccess && + failed_action == LoadFailedAction::kReindex; + + if (!reindex_ruleset) { + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::BindOnce(std::move(ui_callback), std::move(info), + std::move(matcher))); + return; + } + + // Attempt to reindex the extension ruleset. + + // Store the extension pointer since |info| will subsequently be moved. + const Extension* extension = info.extension.get(); + + // Using a weak pointer here is safe since |ruleset_reindexed_callback| will + // be called on this sequence itself. + IndexAndPersistRulesCallback ruleset_reindexed_callback = base::BindOnce( + &FileSequenceState::OnRulesetReindexed, weak_factory_.GetWeakPtr(), + std::move(info), std::move(ui_callback)); + IndexAndPersistRules(connector_.get(), nullptr /*identity*/, *extension, + std::move(ruleset_reindexed_callback)); } - private: + // Callback invoked when the JSON ruleset is reindexed. + void OnRulesetReindexed(LoadRulesetInfo info, + LoadRulesetUICallback ui_callback, + IndexAndPersistRulesResult result) const { + DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence()); + + // The checksum of the reindexed ruleset should have been the same as the + // expected checksum obtained from prefs. If this is not the case, then + // there is some other issue (like the JSON rules file has been modified + // from the one used during installation or preferences are corrupted). But + // taking care of these is beyond our scope here, so simply signal a + // failure. + bool reindexing_success = + result.success && + info.expected_ruleset_checksum == result.ruleset_checksum; + UMA_HISTOGRAM_BOOLEAN( + "Extensions.DeclarativeNetRequest.RulesetReindexSuccessful", + reindexing_success); + if (!reindexing_success) { + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::BindOnce(std::move(ui_callback), std::move(info), + nullptr /* matcher */)); + return; + } + + // We already reindexed the extension ruleset once and it succeeded. If the + // ruleset load fails again, there is some other issue. To prevent a cycle, + // don't reindex on failure again. + LoadRulesetInternal(std::move(info), std::move(ui_callback), + LoadFailedAction::kSignalFailure); + } + + const std::unique_ptr<service_manager::Connector> connector_; + + // Must be the last member variable. See WeakPtrFactory documentation for + // details. Mutable to allow GetWeakPtr() usage from const methods. + mutable base::WeakPtrFactory<FileSequenceState> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(FileSequenceState); };
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.cc b/extensions/browser/api/declarative_net_request/ruleset_manager.cc index 5a3d38b4..64c99e5 100644 --- a/extensions/browser/api/declarative_net_request/ruleset_manager.cc +++ b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
@@ -263,6 +263,9 @@ DCHECK(inserted) << "AddRuleset called twice in succession for " << extension_id; + if (test_observer_) + test_observer_->OnRulesetCountChanged(rulesets_.size()); + // Clear the renderers' cache so that they take the new rules into account. ClearRendererCacheOnNavigation(); } @@ -283,6 +286,9 @@ base::EraseIf(rulesets_, compare_by_id); + if (test_observer_) + test_observer_->OnRulesetCountChanged(rulesets_.size()); + // Clear the renderers' cache so that they take the removed rules into // account. ClearRendererCacheOnNavigation();
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.h b/extensions/browser/api/declarative_net_request/ruleset_manager.h index 92fae10..c1f2cacc 100644 --- a/extensions/browser/api/declarative_net_request/ruleset_manager.h +++ b/extensions/browser/api/declarative_net_request/ruleset_manager.h
@@ -42,11 +42,14 @@ explicit RulesetManager(const InfoMap* info_map); ~RulesetManager(); - // An interface used for testing purposes. + // An observer used for testing purposes. class TestObserver { public: virtual void OnEvaluateRequest(const WebRequestInfo& request, - bool is_incognito_context) = 0; + bool is_incognito_context) {} + + // Called whenever a ruleset is added or removed. + virtual void OnRulesetCountChanged(size_t new_count) {} protected: virtual ~TestObserver() {}
diff --git a/extensions/browser/api/declarative_net_request/utils.cc b/extensions/browser/api/declarative_net_request/utils.cc index 4f9ee72..2770a8e 100644 --- a/extensions/browser/api/declarative_net_request/utils.cc +++ b/extensions/browser/api/declarative_net_request/utils.cc
@@ -232,7 +232,7 @@ } void IndexAndPersistRules(service_manager::Connector* connector, - const service_manager::Identity& identity, + service_manager::Identity* identity, const Extension& extension, IndexAndPersistRulesCallback callback) { DCHECK(IsAPIAvailable()); @@ -252,12 +252,20 @@ // the callee interface. auto repeating_callback = base::AdaptCallbackForRepeating(std::move(callback)); - data_decoder::SafeJsonParser::ParseBatch( - connector, json_contents, + auto success_callback = base::BindRepeating(&OnSafeJSONParserSuccess, - base::RetainedRef(&extension), repeating_callback), - base::BindRepeating(&OnSafeJSONParserError, repeating_callback), - identity.instance()); + base::RetainedRef(&extension), repeating_callback); + auto error_callback = + base::BindRepeating(&OnSafeJSONParserError, repeating_callback); + + if (identity) { + data_decoder::SafeJsonParser::ParseBatch(connector, json_contents, + success_callback, error_callback, + identity->instance()); + } else { + data_decoder::SafeJsonParser::Parse(connector, json_contents, + success_callback, error_callback); + } } bool IsValidRulesetData(const uint8_t* data,
diff --git a/extensions/browser/api/declarative_net_request/utils.h b/extensions/browser/api/declarative_net_request/utils.h index 308415c..6b126a8 100644 --- a/extensions/browser/api/declarative_net_request/utils.h +++ b/extensions/browser/api/declarative_net_request/utils.h
@@ -12,6 +12,7 @@ #include "base/callback_forward.h" #include "base/macros.h" +#include "base/optional.h" namespace base { class ListValue; @@ -67,11 +68,11 @@ base::OnceCallback<void(IndexAndPersistRulesResult)>; // Same as IndexAndPersistRulesUnsafe but parses the JSON rules file out-of- // process. |connector| should be a connector to the ServiceManager usable on -// the current sequence. |identity| is used when accessing the data decoder -// service which is used internally to parse JSON. -// Note: This must be called on a sequence where file IO is allowed. +// the current sequence. Optionally clients can pass a valid |identity| to be +// used when accessing the data decoder service which is used internally to +// parse JSON. Note: This must be called on a sequence where file IO is allowed. void IndexAndPersistRules(service_manager::Connector* connector, - const service_manager::Identity& identity, + service_manager::Identity* identity, const Extension& extension, IndexAndPersistRulesCallback callback);
diff --git a/extensions/browser/extensions_browser_client.h b/extensions/browser/extensions_browser_client.h index 9e8ebb1..0a0003d 100644 --- a/extensions/browser/extensions_browser_client.h +++ b/extensions/browser/extensions_browser_client.h
@@ -201,6 +201,9 @@ // ExternalProtocolHandler::PermitLaunchUrl() in Chrome. virtual void PermitExternalProtocolHandler() = 0; + // Return true if the device is enrolled in Demo Mode. + virtual bool IsInDemoMode() = 0; + // Return true if the system is run in forced app mode. virtual bool IsRunningInForcedAppMode() = 0;
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc index 2167e50..62569da 100644 --- a/extensions/browser/sandboxed_unpacker.cc +++ b/extensions/browser/sandboxed_unpacker.cc
@@ -690,7 +690,7 @@ } declarative_net_request::IndexAndPersistRules( - connector_.get(), data_decoder_identity_, *extension_, + connector_.get(), &data_decoder_identity_, *extension_, base::BindOnce(&SandboxedUnpacker::OnJSONRulesetIndexed, this, std::move(manifest))); }
diff --git a/extensions/browser/test_extensions_browser_client.cc b/extensions/browser/test_extensions_browser_client.cc index 1975203..766f077 100644 --- a/extensions/browser/test_extensions_browser_client.cc +++ b/extensions/browser/test_extensions_browser_client.cc
@@ -189,6 +189,10 @@ void TestExtensionsBrowserClient::PermitExternalProtocolHandler() { } +bool TestExtensionsBrowserClient::IsInDemoMode() { + return false; +} + bool TestExtensionsBrowserClient::IsRunningInForcedAppMode() { return false; } bool TestExtensionsBrowserClient::IsAppModeForcedForApp(
diff --git a/extensions/browser/test_extensions_browser_client.h b/extensions/browser/test_extensions_browser_client.h index 9e0210d..5daf46d8 100644 --- a/extensions/browser/test_extensions_browser_client.h +++ b/extensions/browser/test_extensions_browser_client.h
@@ -117,6 +117,7 @@ std::unique_ptr<ExtensionHostDelegate> CreateExtensionHostDelegate() override; bool DidVersionUpdate(content::BrowserContext* context) override; void PermitExternalProtocolHandler() override; + bool IsInDemoMode() override; bool IsRunningInForcedAppMode() override; bool IsAppModeForcedForApp(const ExtensionId& extension_id) override; bool IsLoggedInAsPublicAccount() override;
diff --git a/extensions/common/api/app_runtime.idl b/extensions/common/api/app_runtime.idl index 25175b1..494731f 100644 --- a/extensions/common/api/app_runtime.idl +++ b/extensions/common/api/app_runtime.idl
@@ -107,6 +107,10 @@ // matching URL handler in the <code>url_handlers</code> manifest key. DOMString? referrerUrl; + // Whether the app is launched in a Chrome OS Demo Mode session. Used for + // default-installed Demo Mode Chrome apps. + [nodoc] boolean? isDemoSession; + // Whether the app is being launched in a <a // href="https://support.google.com/chromebook/answer/3134673">Chrome OS // kiosk session</a>.
diff --git a/extensions/renderer/resources/app_runtime_custom_bindings.js b/extensions/renderer/resources/app_runtime_custom_bindings.js index 9fd41c5..16759b4 100644 --- a/extensions/renderer/resources/app_runtime_custom_bindings.js +++ b/extensions/renderer/resources/app_runtime_custom_bindings.js
@@ -54,6 +54,7 @@ } if (--numItems === 0) { var data = { + isDemoSession: launchData.isDemoSession, isKioskSession: launchData.isKioskSession, isPublicSession: launchData.isPublicSession, source: launchData.source,
diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc index 587f57b..714773e 100644 --- a/extensions/shell/browser/shell_extensions_browser_client.cc +++ b/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -191,6 +191,10 @@ void ShellExtensionsBrowserClient::PermitExternalProtocolHandler() { } +bool ShellExtensionsBrowserClient::IsInDemoMode() { + return false; +} + bool ShellExtensionsBrowserClient::IsRunningInForcedAppMode() { return false; }
diff --git a/extensions/shell/browser/shell_extensions_browser_client.h b/extensions/shell/browser/shell_extensions_browser_client.h index df7ee34..ac5576c 100644 --- a/extensions/shell/browser/shell_extensions_browser_client.h +++ b/extensions/shell/browser/shell_extensions_browser_client.h
@@ -88,6 +88,7 @@ std::unique_ptr<ExtensionHostDelegate> CreateExtensionHostDelegate() override; bool DidVersionUpdate(content::BrowserContext* context) override; void PermitExternalProtocolHandler() override; + bool IsInDemoMode() override; bool IsRunningInForcedAppMode() override; bool IsAppModeForcedForApp(const ExtensionId& extension_id) override; bool IsLoggedInAsPublicAccount() override;
diff --git a/google_apis/gcm/BUILD.gn b/google_apis/gcm/BUILD.gn index d5f2361c6..2b4edb15 100644 --- a/google_apis/gcm/BUILD.gn +++ b/google_apis/gcm/BUILD.gn
@@ -68,6 +68,7 @@ "//base/third_party/dynamic_annotations", "//net", "//services/network:network_service", + "//services/network/public/cpp", "//third_party/leveldatabase", "//url", ] @@ -150,15 +151,18 @@ "engine/mcs_client_unittest.cc", "engine/registration_request_unittest.cc", "engine/unregistration_request_unittest.cc", + "test/run_all_unittests.cc", ] deps = [ ":gcm", ":test_support", "//base", - "//base/test:run_all_unittests", + "//base/test:test_support", + "//mojo/core/embedder", "//net", "//net:test_support", + "//services/network:test_support", "//testing/gtest", "//third_party/protobuf:protobuf_lite", ]
diff --git a/google_apis/gcm/engine/gcm_request_test_base.cc b/google_apis/gcm/engine/gcm_request_test_base.cc index 4968790..ccaf7edbc 100644 --- a/google_apis/gcm/engine/gcm_request_test_base.cc +++ b/google_apis/gcm/engine/gcm_request_test_base.cc
@@ -6,6 +6,9 @@ #include "google_apis/gcm/engine/gcm_request_test_base.h" #include "net/url_request/url_fetcher_delegate.h" +#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" +#include "services/network/test/test_url_loader_factory.h" +#include "services/network/test/test_utils.h" namespace { @@ -36,17 +39,32 @@ false, }; +const network::TestURLLoaderFactory::PendingRequest* PendingForURL( + network::TestURLLoaderFactory* factory, + const std::string& url) { + GURL gurl(url); + std::vector<network::TestURLLoaderFactory::PendingRequest>* pending = + factory->pending_requests(); + for (const auto& pending_request : *pending) { + if (pending_request.request.url == gurl) + return &pending_request; + } + return nullptr; +} + } // namespace namespace gcm { GCMRequestTestBase::GCMRequestTestBase() - : task_runner_(new base::TestMockTimeTaskRunner), - task_runner_handle_(task_runner_), - url_request_context_getter_(new net::TestURLRequestContextGetter( - task_runner_)), - retry_count_(0) { -} + : task_runner_(new base::TestMockTimeTaskRunner( + base::TestMockTimeTaskRunner::Type::kBoundToThread)), + url_request_context_getter_( + new net::TestURLRequestContextGetter(task_runner_)), + shared_factory_( + base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( + &test_url_loader_factory_)), + retry_count_(0) {} GCMRequestTestBase::~GCMRequestTestBase() { } @@ -96,6 +114,56 @@ ASSERT_EQ(0UL, expected_pairs->size()); } +void GCMRequestTestBase::SetResponseForURLAndComplete( + const std::string& url, + net::HttpStatusCode status_code, + const std::string& response_body, + int net_error_code) { + if (retry_count_++) + FastForwardToTriggerNextRetry(); + + EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest( + GURL(url), network::URLLoaderCompletionStatus(net_error_code), + network::CreateResourceResponseHead(status_code), response_body)); +} + +const net::HttpRequestHeaders* GCMRequestTestBase::GetExtraHeadersForURL( + const std::string& url) { + const network::TestURLLoaderFactory::PendingRequest* pending_request = + PendingForURL(&test_url_loader_factory_, url); + return pending_request ? &pending_request->request.headers : nullptr; +} + +bool GCMRequestTestBase::GetUploadDataForURL(const std::string& url, + std::string* data_out) { + const network::TestURLLoaderFactory::PendingRequest* pending_request = + PendingForURL(&test_url_loader_factory_, url); + if (!pending_request) + return false; + *data_out = network::GetUploadData(pending_request->request); + return true; +} + +void GCMRequestTestBase::VerifyFetcherUploadDataForURL( + const std::string& url, + std::map<std::string, std::string>* expected_pairs) { + std::string upload_data; + ASSERT_TRUE(GetUploadDataForURL(url, &upload_data)); + + // Verify data was formatted properly. + base::StringTokenizer data_tokenizer(upload_data, "&="); + while (data_tokenizer.GetNext()) { + auto iter = expected_pairs->find(data_tokenizer.token()); + ASSERT_TRUE(iter != expected_pairs->end()) << data_tokenizer.token(); + ASSERT_TRUE(data_tokenizer.GetNext()) << data_tokenizer.token(); + ASSERT_EQ(iter->second, data_tokenizer.token()); + // Ensure that none of the keys appears twice. + expected_pairs->erase(iter); + } + + ASSERT_EQ(0UL, expected_pairs->size()); +} + void GCMRequestTestBase::FastForwardToTriggerNextRetry() { // Here we compute the maximum delay time by skipping the jitter fluctuation // that only affects in the negative way.
diff --git a/google_apis/gcm/engine/gcm_request_test_base.h b/google_apis/gcm/engine/gcm_request_test_base.h index b0a1b5b3..93f23f2b 100644 --- a/google_apis/gcm/engine/gcm_request_test_base.h +++ b/google_apis/gcm/engine/gcm_request_test_base.h
@@ -12,8 +12,13 @@ #include "net/base/backoff_entry.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_request_test_util.h" +#include "services/network/test/test_url_loader_factory.h" #include "testing/gtest/include/gtest/gtest.h" +namespace network { +class SharedURLLoaderFactory; +} + namespace gcm { // The base class for testing various GCM requests that contains all the common @@ -44,16 +49,47 @@ return url_request_context_getter_.get(); } + // The code is in transition away from URLRequestContextGetter + + // URLFetcherFactory to SharedURLLoaderFactory. For now, both are needed. + // Things that use url_loader_factory() will be matched with test APIs with + // "ForURL" in their names below. + network::SharedURLLoaderFactory* url_loader_factory() const { + return shared_factory_.get(); + } + + network::TestURLLoaderFactory* test_url_loader_factory() { + return &test_url_loader_factory_; + } + + // This is a version for the TestURLLoaderFactory path; it also needs a URL. + void SetResponseForURLAndComplete(const std::string& url, + net::HttpStatusCode status_code, + const std::string& response_body, + int net_error_code = net::OK); + + // Note: may return null if URL isn't pending. + const net::HttpRequestHeaders* GetExtraHeadersForURL(const std::string& url); + + // Returns false if URL isn't pending or extraction failed. + bool GetUploadDataForURL(const std::string& url, std::string* data_out); + + // See docs for VerifyFetcherUploadData. + void VerifyFetcherUploadDataForURL( + const std::string& url, + std::map<std::string, std::string>* expected_pairs); + private: // Fast forward the timer used in the test to retry the request immediately. void FastForwardToTriggerNextRetry(); scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; - base::ThreadTaskRunnerHandle task_runner_handle_; - scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_; + scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_; net::TestURLFetcherFactory url_fetcher_factory_; + network::TestURLLoaderFactory test_url_loader_factory_; + scoped_refptr<network::SharedURLLoaderFactory> shared_factory_; + // Tracks the number of retries so far. int retry_count_;
diff --git a/google_apis/gcm/engine/registration_request.cc b/google_apis/gcm/engine/registration_request.cc index a4bdf42..455bbb28 100644 --- a/google_apis/gcm/engine/registration_request.cc +++ b/google_apis/gcm/engine/registration_request.cc
@@ -20,9 +20,9 @@ #include "net/http/http_request_headers.h" #include "net/http/http_status_code.h" #include "net/traffic_annotation/network_traffic_annotation.h" -#include "net/url_request/url_fetcher.h" -#include "net/url_request/url_request_context_getter.h" -#include "net/url_request/url_request_status.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" #include "url/gurl.h" namespace gcm { @@ -123,7 +123,7 @@ const net::BackoffEntry::Policy& backoff_policy, const RegistrationCallback& callback, int max_retry_count, - scoped_refptr<net::URLRequestContextGetter> request_context_getter, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, GCMStatsRecorder* recorder, const std::string& source_to_record) : callback_(callback), @@ -131,7 +131,7 @@ custom_request_handler_(std::move(custom_request_handler)), registration_url_(registration_url), backoff_entry_(&backoff_policy), - request_context_getter_(request_context_getter), + url_loader_factory_(std::move(url_loader_factory)), retries_left_(max_retry_count), recorder_(recorder), source_to_record_(source_to_record), @@ -143,7 +143,7 @@ void RegistrationRequest::Start() { DCHECK(!callback_.is_null()); - DCHECK(!url_fetcher_.get()); + DCHECK(!url_loader_.get()); net::NetworkTrafficAnnotationTag traffic_annotation = net::DefineNetworkTrafficAnnotation("gcm_registration", R"( semantics { @@ -173,34 +173,36 @@ policy_exception_justification: "Not implemented, considered not useful." })"); - url_fetcher_ = net::URLFetcher::Create( - registration_url_, net::URLFetcher::POST, this, traffic_annotation); - url_fetcher_->SetRequestContext(request_context_getter_.get()); - url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | - net::LOAD_DO_NOT_SAVE_COOKIES); - - std::string extra_headers; - BuildRequestHeaders(&extra_headers); - url_fetcher_->SetExtraRequestHeaders(extra_headers); + auto request = std::make_unique<network::ResourceRequest>(); + request->url = registration_url_; + request->method = "POST"; + request->load_flags = + net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES; + BuildRequestHeaders(&request->headers); std::string body; BuildRequestBody(&body); DVLOG(1) << "Performing registration for: " << request_info_.app_id(); DVLOG(1) << "Registration request: " << body; - url_fetcher_->SetUploadData(kRegistrationRequestContentType, body); + url_loader_ = + network::SimpleURLLoader::Create(std::move(request), traffic_annotation); + url_loader_->AttachStringForUpload(body, kRegistrationRequestContentType); recorder_->RecordRegistrationSent(request_info_.app_id(), source_to_record_); request_start_time_ = base::TimeTicks::Now(); - url_fetcher_->Start(); + url_loader_->SetAllowHttpErrorResults(true); + url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + url_loader_factory_.get(), + base::BindOnce(&RegistrationRequest::OnURLLoadComplete, + base::Unretained(this), url_loader_.get())); } -void RegistrationRequest::BuildRequestHeaders(std::string* extra_headers) { - net::HttpRequestHeaders headers; - headers.SetHeader(net::HttpRequestHeaders::kAuthorization, - std::string(kLoginHeader) + " " + - base::NumberToString(request_info_.android_id) + ":" + - base::NumberToString(request_info_.security_token)); - *extra_headers = headers.ToString(); +void RegistrationRequest::BuildRequestHeaders( + net::HttpRequestHeaders* headers) { + headers->SetHeader(net::HttpRequestHeaders::kAuthorization, + std::string(kLoginHeader) + " " + + base::NumberToString(request_info_.android_id) + ":" + + base::NumberToString(request_info_.security_token)); } void RegistrationRequest::BuildRequestBody(std::string* body) { @@ -218,7 +220,7 @@ void RegistrationRequest::RetryWithBackoff() { DCHECK_GT(retries_left_, 0); --retries_left_; - url_fetcher_.reset(); + url_loader_.reset(); backoff_entry_.InformOfRequest(false); DVLOG(1) << "Delaying GCM registration of app: " << request_info_.app_id() @@ -235,17 +237,20 @@ } RegistrationRequest::Status RegistrationRequest::ParseResponse( - const net::URLFetcher* source, std::string* token) { - if (!source->GetStatus().is_success()) { + const network::SimpleURLLoader* source, + std::unique_ptr<std::string> body, + std::string* token) { + if (source->NetError() != net::OK) { DVLOG(1) << "Registration URL fetching failed."; return URL_FETCHING_FAILED; } std::string response; - if (!source->GetResponseAsString(&response)) { + if (!body) { DVLOG(1) << "Failed to get registration response body."; return NO_RESPONSE_BODY; } + response = std::move(*body); // If we are able to parse a meaningful known error, let's do so. Note that // some errors will have HTTP_OK response code! @@ -257,11 +262,17 @@ return GetStatusFromError(error); } + // Can't even get any header info. + if (!source->ResponseInfo() || !source->ResponseInfo()->headers) { + DVLOG(1) << "Registration HTTP response info or header missing"; + return HTTP_NOT_OK; + } + // If we cannot tell what the error is, but at least we know response code was // not OK. - if (source->GetResponseCode() != net::HTTP_OK) { + if (source->ResponseInfo()->headers->response_code() != net::HTTP_OK) { DVLOG(1) << "Registration HTTP response code not OK: " - << source->GetResponseCode(); + << source->ResponseInfo()->headers->response_code(); return HTTP_NOT_OK; } @@ -274,9 +285,11 @@ return RESPONSE_PARSING_FAILED; } -void RegistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) { +void RegistrationRequest::OnURLLoadComplete( + const network::SimpleURLLoader* source, + std::unique_ptr<std::string> body) { std::string token; - Status status = ParseResponse(source, &token); + Status status = ParseResponse(source, std::move(body), &token); recorder_->RecordRegistrationResponse(request_info_.app_id(), source_to_record_, status);
diff --git a/google_apis/gcm/engine/registration_request.h b/google_apis/gcm/engine/registration_request.h index 1b5708c..7349e5a5 100644 --- a/google_apis/gcm/engine/registration_request.h +++ b/google_apis/gcm/engine/registration_request.h
@@ -19,11 +19,15 @@ #include "base/time/time.h" #include "google_apis/gcm/base/gcm_export.h" #include "net/base/backoff_entry.h" -#include "net/url_request/url_fetcher_delegate.h" #include "url/gurl.h" namespace net { -class URLRequestContextGetter; +class HttpRequestHeaders; +} + +namespace network { +class SharedURLLoaderFactory; +class SimpleURLLoader; } namespace gcm { @@ -34,7 +38,7 @@ // want to use GCM. It requires a set of parameters to be specified to identify // the Chrome instance, the user, the application and a set of senders that will // be authorized to address the application using it's assigned registration ID. -class GCM_EXPORT RegistrationRequest : public net::URLFetcherDelegate { +class GCM_EXPORT RegistrationRequest { public: // This enum is also used in an UMA histogram (GCMRegistrationRequestStatus // enum defined in tools/metrics/histograms/histogram.xml). Hence the entries @@ -116,26 +120,29 @@ const net::BackoffEntry::Policy& backoff_policy, const RegistrationCallback& callback, int max_retry_count, - scoped_refptr<net::URLRequestContextGetter> request_context_getter, + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, GCMStatsRecorder* recorder, const std::string& source_to_record); - ~RegistrationRequest() override; + ~RegistrationRequest(); void Start(); - // URLFetcherDelegate implementation. - void OnURLFetchComplete(const net::URLFetcher* source) override; + // Invoked from SimpleURLLoader. + void OnURLLoadComplete(const network::SimpleURLLoader* source, + std::unique_ptr<std::string> body); private: // Schedules a retry attempt with a backoff. void RetryWithBackoff(); - void BuildRequestHeaders(std::string* extra_headers); + void BuildRequestHeaders(net::HttpRequestHeaders* headers); void BuildRequestBody(std::string* body); - // Parse the response returned by the URL fetcher into token, and returns the + // Parse the response returned by the URL loader into token, and returns the // status. - Status ParseResponse(const net::URLFetcher* source, std::string* token); + Status ParseResponse(const network::SimpleURLLoader* source, + std::unique_ptr<std::string> body, + std::string* token); RegistrationCallback callback_; RequestInfo request_info_; @@ -143,8 +150,8 @@ GURL registration_url_; net::BackoffEntry backoff_entry_; - scoped_refptr<net::URLRequestContextGetter> request_context_getter_; - std::unique_ptr<net::URLFetcher> url_fetcher_; + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + std::unique_ptr<network::SimpleURLLoader> url_loader_; int retries_left_; base::TimeTicks request_start_time_;
diff --git a/google_apis/gcm/engine/registration_request_unittest.cc b/google_apis/gcm/engine/registration_request_unittest.cc index 02ccd3c4..e85864a 100644 --- a/google_apis/gcm/engine/registration_request_unittest.cc +++ b/google_apis/gcm/engine/registration_request_unittest.cc
@@ -18,6 +18,7 @@ #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/url_request/url_request_status.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" namespace gcm { @@ -107,7 +108,7 @@ GetBackoffPolicy(), base::Bind(&RegistrationRequestTest::RegistrationCallback, base::Unretained(this)), - max_retry_count_, url_request_context_getter(), &recorder_, sender_ids)); + max_retry_count_, url_loader_factory(), &recorder_, sender_ids)); } TEST_F(GCMRegistrationRequestTest, RequestSuccessful) { @@ -115,9 +116,7 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); EXPECT_EQ("2501", registration_id_); @@ -127,17 +126,13 @@ CreateRequest(kDeveloperId); request_->Start(); - // Get data sent by request. - net::TestURLFetcher* fetcher = GetFetcher(); - ASSERT_TRUE(fetcher); - - EXPECT_EQ(GURL(kRegistrationURL), fetcher->GetOriginalURL()); - - // Verify that authorization header was put together properly. - net::HttpRequestHeaders headers; - fetcher->GetExtraRequestHeaders(&headers); + // Get data sent by request and verify that authorization header was put + // together properly. + const net::HttpRequestHeaders* headers = + GetExtraHeadersForURL(kRegistrationURL); + ASSERT_TRUE(headers != nullptr); std::string auth_header; - headers.GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header); + headers->GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header); base::StringTokenizer auth_tokenizer(auth_header, " :"); ASSERT_TRUE(auth_tokenizer.GetNext()); EXPECT_EQ(kLoginHeader, auth_tokenizer.token()); @@ -151,18 +146,18 @@ expected_pairs["sender"] = kDeveloperId; expected_pairs["device"] = base::NumberToString(kAndroidId); - ASSERT_NO_FATAL_FAILURE(VerifyFetcherUploadData(&expected_pairs)); + ASSERT_NO_FATAL_FAILURE( + VerifyFetcherUploadDataForURL(kRegistrationURL, &expected_pairs)); } TEST_F(GCMRegistrationRequestTest, RequestRegistrationWithMultipleSenderIds) { CreateRequest("sender1,sender2@gmail.com"); request_->Start(); - net::TestURLFetcher* fetcher = GetFetcher(); - ASSERT_TRUE(fetcher); // Verify data was formatted properly. - std::string upload_data = fetcher->upload_data(); + std::string upload_data; + ASSERT_TRUE(GetUploadDataForURL(kRegistrationURL, &upload_data)); base::StringTokenizer data_tokenizer(upload_data, "&="); // Skip all tokens until you hit entry for senders. @@ -185,9 +180,7 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); EXPECT_EQ("2501", registration_id_); @@ -197,15 +190,12 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_OK, "tok"); // Simulate truncated message. - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, + "tok"); // Simulate truncated message. EXPECT_FALSE(callback_called_); // Ensuring a retry happened and succeeds. - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); EXPECT_EQ("2501", registration_id_); @@ -215,14 +205,11 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_UNAUTHORIZED, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_UNAUTHORIZED, + "token=2501"); EXPECT_FALSE(callback_called_); - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); EXPECT_EQ("2501", registration_id_); @@ -232,20 +219,15 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_OK, ""); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, ""); EXPECT_FALSE(callback_called_); - SetResponse(net::HTTP_OK, "some error in response"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, + "some error in response"); EXPECT_FALSE(callback_called_); // Ensuring a retry happened and succeeds. - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); EXPECT_EQ("2501", registration_id_); @@ -255,15 +237,12 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_OK, "Error=PHONE_REGISTRATION_ERROR"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, + "Error=PHONE_REGISTRATION_ERROR"); EXPECT_FALSE(callback_called_); // Ensuring a retry happened and succeeds. - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); EXPECT_EQ("2501", registration_id_); @@ -273,16 +252,12 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_UNAUTHORIZED, - "Error=AUTHENTICATION_FAILED"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_UNAUTHORIZED, + "Error=AUTHENTICATION_FAILED"); EXPECT_FALSE(callback_called_); // Ensuring a retry happened and succeeds. - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); EXPECT_EQ("2501", registration_id_); @@ -292,15 +267,13 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_INTERNAL_SERVER_ERROR, "Error=InternalServerError"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, + net::HTTP_INTERNAL_SERVER_ERROR, + "Error=InternalServerError"); EXPECT_FALSE(callback_called_); // Ensuring a retry happened and succeeds. - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); EXPECT_EQ("2501", registration_id_); @@ -310,9 +283,8 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_OK, "Error=INVALID_PARAMETERS"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, + "Error=INVALID_PARAMETERS"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::INVALID_PARAMETERS, status_); EXPECT_EQ(std::string(), registration_id_); @@ -322,9 +294,8 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_OK, "Error=INVALID_SENDER"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, + "Error=INVALID_SENDER"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::INVALID_SENDER, status_); EXPECT_EQ(std::string(), registration_id_); @@ -334,9 +305,8 @@ CreateRequest("sender1"); request_->Start(); - SetResponse(net::HTTP_BAD_REQUEST, "Error=INVALID_SENDER"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_BAD_REQUEST, + "Error=INVALID_SENDER"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::INVALID_SENDER, status_); EXPECT_EQ(std::string(), registration_id_); @@ -346,9 +316,8 @@ CreateRequest("sender1"); request_->Start(); - SetResponse(net::HTTP_SERVICE_UNAVAILABLE, "Error=QUOTA_EXCEEDED"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_SERVICE_UNAVAILABLE, + "Error=QUOTA_EXCEEDED"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::QUOTA_EXCEEDED, status_); EXPECT_EQ(std::string(), registration_id_); @@ -358,9 +327,8 @@ CreateRequest("sender1"); request_->Start(); - SetResponse(net::HTTP_OK, "Error=TOO_MANY_REGISTRATIONS"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, + "Error=TOO_MANY_REGISTRATIONS"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::TOO_MANY_REGISTRATIONS, status_); EXPECT_EQ(std::string(), registration_id_); @@ -370,19 +338,12 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_OK, "token=2501"); - - net::TestURLFetcher* fetcher = GetFetcher(); - ASSERT_TRUE(fetcher); - GetFetcher()->set_status(net::URLRequestStatus::FromError(net::ERR_FAILED)); - - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501", + net::ERR_FAILED); EXPECT_FALSE(callback_called_); // Ensuring a retry happened and succeeded. - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); @@ -393,14 +354,12 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_GATEWAY_TIMEOUT, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT, + "token=2501"); EXPECT_FALSE(callback_called_); // Ensuring a retry happened and succeeded. - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); @@ -412,8 +371,8 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_GATEWAY_TIMEOUT, "token=2501"); - CompleteFetch(); + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT, + "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::REACHED_MAX_RETRIES, status_); @@ -424,19 +383,16 @@ CreateRequest("sender1,sender2"); request_->Start(); - SetResponse(net::HTTP_GATEWAY_TIMEOUT, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT, + "token=2501"); EXPECT_FALSE(callback_called_); - SetResponse(net::HTTP_GATEWAY_TIMEOUT, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT, + "token=2501"); EXPECT_FALSE(callback_called_); - SetResponse(net::HTTP_GATEWAY_TIMEOUT, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT, + "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::REACHED_MAX_RETRIES, status_); EXPECT_EQ(std::string(), registration_id_); @@ -478,8 +434,7 @@ GetBackoffPolicy(), base::Bind(&RegistrationRequestTest::RegistrationCallback, base::Unretained(this)), - max_retry_count_, url_request_context_getter(), &recorder_, - authorized_entity)); + max_retry_count_, url_loader_factory(), &recorder_, authorized_entity)); } TEST_F(InstanceIDGetTokenRequestTest, RequestSuccessful) { @@ -491,9 +446,7 @@ options); request_->Start(); - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); EXPECT_EQ("2501", registration_id_); @@ -506,22 +459,18 @@ options); request_->Start(); - // Get data sent by request. - net::TestURLFetcher* fetcher = GetFetcher(); - ASSERT_TRUE(fetcher); - - EXPECT_EQ(GURL(kRegistrationURL), fetcher->GetOriginalURL()); - // Verify that the no-cookie flag is set. - int flags = fetcher->GetLoadFlags(); + int flags = 0; + ASSERT_TRUE(test_url_loader_factory()->IsPending(kRegistrationURL, &flags)); EXPECT_TRUE(flags & net::LOAD_DO_NOT_SEND_COOKIES); EXPECT_TRUE(flags & net::LOAD_DO_NOT_SAVE_COOKIES); // Verify that authorization header was put together properly. - net::HttpRequestHeaders headers; - fetcher->GetExtraRequestHeaders(&headers); + const net::HttpRequestHeaders* headers = + GetExtraHeadersForURL(kRegistrationURL); + ASSERT_TRUE(headers != nullptr); std::string auth_header; - headers.GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header); + headers->GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header); base::StringTokenizer auth_tokenizer(auth_header, " :"); ASSERT_TRUE(auth_tokenizer.GetNext()); EXPECT_EQ(kLoginHeader, auth_tokenizer.token()); @@ -540,7 +489,8 @@ expected_pairs["X-scope"] = kScope; expected_pairs["X-Foo"] = "Bar"; - ASSERT_NO_FATAL_FAILURE(VerifyFetcherUploadData(&expected_pairs)); + ASSERT_NO_FATAL_FAILURE( + VerifyFetcherUploadDataForURL(kRegistrationURL, &expected_pairs)); } TEST_F(InstanceIDGetTokenRequestTest, RequestDataWithSubtype) { @@ -550,10 +500,6 @@ options); request_->Start(); - // Get data sent by request. - net::TestURLFetcher* fetcher = GetFetcher(); - ASSERT_TRUE(fetcher); - // Same as RequestDataAndURL except "app" and "X-subtype". std::map<std::string, std::string> expected_pairs; expected_pairs["gmsv"] = base::IntToString(kGCMVersion); @@ -567,7 +513,8 @@ expected_pairs["X-Foo"] = "Bar"; // Verify data was formatted properly. - std::string upload_data = fetcher->upload_data(); + std::string upload_data; + ASSERT_TRUE(GetUploadDataForURL(kRegistrationURL, &upload_data)); base::StringTokenizer data_tokenizer(upload_data, "&="); while (data_tokenizer.GetNext()) { auto iter = expected_pairs.find(data_tokenizer.token()); @@ -587,14 +534,11 @@ options); request_->Start(); - SetResponse(net::HTTP_UNAUTHORIZED, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_UNAUTHORIZED, + "token=2501"); EXPECT_FALSE(callback_called_); - SetResponse(net::HTTP_OK, "token=2501"); - CompleteFetch(); - + SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "token=2501"); EXPECT_TRUE(callback_called_); EXPECT_EQ(RegistrationRequest::SUCCESS, status_); EXPECT_EQ("2501", registration_id_);
diff --git a/google_apis/gcm/test/DEPS b/google_apis/gcm/test/DEPS new file mode 100644 index 0000000..9243dcd6 --- /dev/null +++ b/google_apis/gcm/test/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+mojo/core/embedder", +]
diff --git a/google_apis/gcm/test/run_all_unittests.cc b/google_apis/gcm/test/run_all_unittests.cc new file mode 100644 index 0000000..939a23ce --- /dev/null +++ b/google_apis/gcm/test/run_all_unittests.cc
@@ -0,0 +1,17 @@ +// 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. + +#include "base/message_loop/message_loop.h" +#include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_suite.h" +#include "mojo/core/embedder/embedder.h" + +int main(int argc, char** argv) { + base::TestSuite test_suite(argc, argv); + + mojo::core::Init(); + return base::LaunchUnitTests( + argc, argv, + base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite))); +}
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg index 1668be4a..ba80d4f 100644 --- a/infra/config/global/cr-buildbucket.cfg +++ b/infra/config/global/cr-buildbucket.cfg
@@ -1672,7 +1672,7 @@ builders { name: "Oreo Phone Tester" dimensions: "os:Ubuntu-14.04" - mixins: "android-fyi-ci" + mixins: "android-ci" } builders { name: "Android Remoting Tests"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg index 9797d77..ddd7f4f 100644 --- a/infra/config/global/luci-milo.cfg +++ b/infra/config/global/luci-milo.cfg
@@ -1578,6 +1578,11 @@ short_name: "N" } builders { + name: "buildbucket/luci.chromium.ci/Oreo Phone Tester" + category: "tester|phone" + short_name: "O" + } + builders { name: "buildbucket/luci.chromium.ci/KitKat Tablet Tester" category: "tester|tablet" short_name: "K" @@ -1659,12 +1664,6 @@ short_name: "N" } builders { - name: "buildbot/chromium.android.fyi/Oreo Phone Tester" - name: "buildbucket/luci.chromium.ci/Oreo Phone Tester" - category: "Testers" - short_name: "O" - } - builders { name: "buildbot/chromium.android.fyi/x64 Device Tester" name: "buildbucket/luci.chromium.ci/x64 Device Tester" category: "Testers"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg index 4fd7165d..5c7e103 100644 --- a/infra/config/global/luci-scheduler.cfg +++ b/infra/config/global/luci-scheduler.cfg
@@ -725,13 +725,11 @@ id: "Oreo Phone Tester" # triggered by "Android arm64 Builder (dbg)" acl_sets: "triggered-by-parent-builders" - # TODO(bpastene): s/noop/buildbucket. - noop: {} - # buildbucket: { - # server: "cr-buildbucket.appspot.com" - # bucket: "luci.chromium.ci" - # builder: "Oreo Phone Tester" - # } + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Oreo Phone Tester" + } } ################################################################################
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index e31aa8a..438c9728 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -15,6 +15,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #import "base/test/ios/wait_util.h" +#include "base/test/scoped_feature_list.h" #import "ios/testing/ocmock_complex_type_helper.h" #import "ios/testing/wait_util.h" #import "ios/web/navigation/crw_session_controller.h" @@ -24,6 +25,7 @@ #import "ios/web/public/crw_session_storage.h" #import "ios/web/public/download/download_controller.h" #import "ios/web/public/download/download_task.h" +#include "ios/web/public/features.h" #include "ios/web/public/referrer.h" #include "ios/web/public/test/fakes/fake_download_controller_delegate.h" #import "ios/web/public/test/fakes/test_native_content.h" @@ -115,15 +117,71 @@ }); } +// Tests in this file are parameterized on this enum to test both +// LegacyNavigationManagerImpl and WKBasedNavigationManagerImpl. +enum class NavigationManagerChoice { + LEGACY, + WK_BASED, +}; + +// A mixin class that encapsulates the parameterization of navigation manager +// choice. +class ProgrammaticTestMixin + : public ::testing::WithParamInterface<NavigationManagerChoice> { + public: + void SetUp() { + if (GetParam() == NavigationManagerChoice::LEGACY) { + scoped_feature_list_.InitAndDisableFeature( + features::kSlimNavigationManager); + } else { + scoped_feature_list_.InitAndEnableFeature( + features::kSlimNavigationManager); + } + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// Base class for WebTestWithWebState tests to enable navigation manager mixin. +class ProgrammaticWebTestWithWebState : public WebTestWithWebState, + public ProgrammaticTestMixin { + public: + void SetUp() override { + ProgrammaticTestMixin::SetUp(); + WebTestWithWebState::SetUp(); + } +}; + +// Base class for WebTestWithWebController tests to enable navigation manager +// mixin. +class ProgrammaticWebTestWithWebController : public WebTestWithWebController, + public ProgrammaticTestMixin { + public: + void SetUp() override { + ProgrammaticTestMixin::SetUp(); + WebTestWithWebState::SetUp(); + } +}; + +// Macro to simplify instantiation of parameterized tests. +#define INSTANTIATE_TEST_CASES(cls) \ + INSTANTIATE_TEST_CASE_P( \ + Programmatic##cls, cls, \ + ::testing::Values(NavigationManagerChoice::LEGACY, \ + NavigationManagerChoice::WK_BASED)); + } // namespace // Test fixture for testing CRWWebController. Stubs out web view. -class CRWWebControllerTest : public WebTestWithWebController { +class CRWWebControllerTest : public WebTestWithWebController, + public ProgrammaticTestMixin { protected: CRWWebControllerTest() : WebTestWithWebController(std::make_unique<TestWebClient>()) {} void SetUp() override { + ProgrammaticTestMixin::SetUp(); WebTestWithWebController::SetUp(); mock_web_view_ = CreateMockWebView(); scroll_view_ = [[UIScrollView alloc] init]; @@ -183,6 +241,7 @@ options:0 context:nullptr]; [[result stub] removeObserver:web_controller() forKeyPath:OCMOCK_ANY]; + [[result stub] evaluateJavaScript:OCMOCK_ANY completionHandler:OCMOCK_ANY]; return result; } @@ -196,7 +255,7 @@ // Tests that AllowCertificateError is called with correct arguments if // WKWebView fails to load a page with bad SSL cert. -TEST_F(CRWWebControllerTest, SslCertError) { +TEST_P(CRWWebControllerTest, SslCertError) { // Last arguments passed to AllowCertificateError must be in default state. ASSERT_FALSE(GetWebClient()->last_cert_error_code()); ASSERT_FALSE(GetWebClient()->last_cert_error_ssl_info().is_valid()); @@ -236,18 +295,60 @@ EXPECT_FALSE(GetWebClient()->last_cert_error_overridable()); } +// Tests that when a placeholder navigation is preempted by another navigation, +// WebStateObservers get neither a DidStartNavigation nor a DidFinishNavigation +// call for the corresponding native URL navigation. +TEST_P(CRWWebControllerTest, AbortNativeUrlNavigation) { + // The legacy navigation manager doesn't have the concept of placeholder + // navigations. + if (!GetWebClient()->IsSlimNavigationManagerEnabled()) + return; + GURL native_url( + url::SchemeHostPort(kTestNativeContentScheme, "ui", 0).Serialize()); + NSString* placeholder_url = [NSString + stringWithFormat:@"%s%s", "about:blank?for=", native_url.spec().c_str()]; + TestWebStateObserver observer(web_state()); + + WKNavigation* navigation = + static_cast<WKNavigation*>([[NSObject alloc] init]); + [static_cast<WKWebView*>([[mock_web_view_ stub] andReturn:navigation]) + loadRequest:OCMOCK_ANY]; + TestNativeContentProvider* mock_native_provider = + [[TestNativeContentProvider alloc] init]; + [web_controller() setNativeProvider:mock_native_provider]; + + AddPendingItem(native_url, ui::PAGE_TRANSITION_TYPED); + + // Trigger a placeholder navigation. + [web_controller() loadCurrentURL]; + + // Simulate the WKNavigationDelegate callbacks for the placeholder navigation + // arriving after another pending item has already been created. + AddPendingItem(GURL(kTestURLString), ui::PAGE_TRANSITION_TYPED); + SetWebViewURL(placeholder_url); + [navigation_delegate_ webView:mock_web_view_ + didStartProvisionalNavigation:navigation]; + [navigation_delegate_ webView:mock_web_view_ didCommitNavigation:navigation]; + [navigation_delegate_ webView:mock_web_view_ didFinishNavigation:navigation]; + + EXPECT_FALSE(observer.did_start_navigation_info()); + EXPECT_FALSE(observer.did_finish_navigation_info()); +} + +INSTANTIATE_TEST_CASES(CRWWebControllerTest); + // Test fixture to test |WebState::SetShouldSuppressDialogs|. -class DialogsSuppressionTest : public WebTestWithWebState { +class DialogsSuppressionTest : public ProgrammaticWebTestWithWebState { protected: DialogsSuppressionTest() : page_url_("https://chromium.test/") {} void SetUp() override { - WebTestWithWebState::SetUp(); + ProgrammaticWebTestWithWebState::SetUp(); LoadHtml(@"<html><body></body></html>", page_url_); web_state()->SetDelegate(&test_web_delegate_); } void TearDown() override { web_state()->SetDelegate(nullptr); - WebTestWithWebState::TearDown(); + ProgrammaticWebTestWithWebState::TearDown(); } TestJavaScriptDialogPresenter* js_dialog_presenter() { return test_web_delegate_.GetTestJavaScriptDialogPresenter(); @@ -263,7 +364,7 @@ }; // Tests that window.alert dialog is suppressed. -TEST_F(DialogsSuppressionTest, SuppressAlert) { +TEST_P(DialogsSuppressionTest, SuppressAlert) { TestWebStateObserver observer(web_state()); ASSERT_FALSE(observer.did_suppress_dialog_info()); web_state()->SetShouldSuppressDialogs(true); @@ -273,7 +374,7 @@ }; // Tests that window.alert dialog is shown. -TEST_F(DialogsSuppressionTest, AllowAlert) { +TEST_P(DialogsSuppressionTest, AllowAlert) { TestWebStateObserver observer(web_state()); ASSERT_FALSE(observer.did_suppress_dialog_info()); ASSERT_TRUE(requested_dialogs().empty()); @@ -292,7 +393,7 @@ }; // Tests that window.confirm dialog is suppressed. -TEST_F(DialogsSuppressionTest, SuppressConfirm) { +TEST_P(DialogsSuppressionTest, SuppressConfirm) { TestWebStateObserver observer(web_state()); ASSERT_FALSE(observer.did_suppress_dialog_info()); ASSERT_TRUE(requested_dialogs().empty()); @@ -306,7 +407,7 @@ }; // Tests that window.confirm dialog is shown and its result is true. -TEST_F(DialogsSuppressionTest, AllowConfirmWithTrue) { +TEST_P(DialogsSuppressionTest, AllowConfirmWithTrue) { TestWebStateObserver observer(web_state()); ASSERT_FALSE(observer.did_suppress_dialog_info()); ASSERT_TRUE(requested_dialogs().empty()); @@ -327,7 +428,7 @@ } // Tests that window.confirm dialog is shown and its result is false. -TEST_F(DialogsSuppressionTest, AllowConfirmWithFalse) { +TEST_P(DialogsSuppressionTest, AllowConfirmWithFalse) { TestWebStateObserver observer(web_state()); ASSERT_FALSE(observer.did_suppress_dialog_info()); ASSERT_TRUE(requested_dialogs().empty()); @@ -346,7 +447,7 @@ } // Tests that window.prompt dialog is suppressed. -TEST_F(DialogsSuppressionTest, SuppressPrompt) { +TEST_P(DialogsSuppressionTest, SuppressPrompt) { TestWebStateObserver observer(web_state()); ASSERT_FALSE(observer.did_suppress_dialog_info()); ASSERT_TRUE(requested_dialogs().empty()); @@ -360,7 +461,7 @@ } // Tests that window.prompt dialog is shown. -TEST_F(DialogsSuppressionTest, AllowPrompt) { +TEST_P(DialogsSuppressionTest, AllowPrompt) { TestWebStateObserver observer(web_state()); ASSERT_FALSE(observer.did_suppress_dialog_info()); ASSERT_TRUE(requested_dialogs().empty()); @@ -381,7 +482,7 @@ } // Tests that window.open is suppressed. -TEST_F(DialogsSuppressionTest, SuppressWindowOpen) { +TEST_P(DialogsSuppressionTest, SuppressWindowOpen) { TestWebStateObserver observer(web_state()); ASSERT_FALSE(observer.did_suppress_dialog_info()); ASSERT_TRUE(requested_dialogs().empty()); @@ -393,9 +494,12 @@ EXPECT_EQ(web_state(), observer.did_suppress_dialog_info()->web_state); } +INSTANTIATE_TEST_CASES(DialogsSuppressionTest); + // A separate test class, as none of the |CRWWebControllerTest| setup is // needed. -class CRWWebControllerPageScrollStateTest : public WebTestWithWebController { +class CRWWebControllerPageScrollStateTest + : public ProgrammaticWebTestWithWebController { protected: // Returns a PageDisplayState that will scroll a WKWebView to // |scrollOffset| and zoom the content by |relativeZoomScale|. @@ -413,7 +517,7 @@ }; // TODO(crbug/493427): Flaky on the bots. -TEST_F(CRWWebControllerPageScrollStateTest, +TEST_P(CRWWebControllerPageScrollStateTest, FLAKY_SetPageDisplayStateWithUserScalableDisabled) { #if !TARGET_IPHONE_SIMULATOR // TODO(crbug.com/493427): fails flakily on device, so skip it there. @@ -444,7 +548,7 @@ }; // TODO(crbug/493427): Flaky on the bots. -TEST_F(CRWWebControllerPageScrollStateTest, +TEST_P(CRWWebControllerPageScrollStateTest, FLAKY_SetPageDisplayStateWithUserScalableEnabled) { #if !TARGET_IPHONE_SIMULATOR // TODO(crbug.com/493427): fails flakily on device, so skip it there. @@ -475,11 +579,13 @@ final_zoom_state.minimum_zoom_scale()); }; +INSTANTIATE_TEST_CASES(CRWWebControllerPageScrollStateTest); + // Test fixture for testing visible security state. -typedef WebTestWithWebState CRWWebStateSecurityStateTest; +typedef ProgrammaticWebTestWithWebState CRWWebStateSecurityStateTest; // Tests that loading HTTP page updates the SSLStatus. -TEST_F(CRWWebStateSecurityStateTest, LoadHttpPage) { +TEST_P(CRWWebStateSecurityStateTest, LoadHttpPage) { TestWebStateObserver observer(web_state()); ASSERT_FALSE(observer.did_change_visible_security_state_info()); LoadHtml(@"<html><body></body></html>", GURL("http://chromium.test")); @@ -491,25 +597,29 @@ observer.did_change_visible_security_state_info()->web_state); } +INSTANTIATE_TEST_CASES(CRWWebStateSecurityStateTest); + // Real WKWebView is required for CRWWebControllerInvalidUrlTest. -typedef WebTestWithWebState CRWWebControllerInvalidUrlTest; +typedef ProgrammaticWebTestWithWebState CRWWebControllerInvalidUrlTest; // Tests that web controller does not navigate to about:blank if iframe src // has invalid url. Web controller loads about:blank if page navigates to // invalid url, but should do nothing if navigation is performed in iframe. This // test prevents crbug.com/694865 regression. -TEST_F(CRWWebControllerInvalidUrlTest, IFrameWithInvalidURL) { +TEST_P(CRWWebControllerInvalidUrlTest, IFrameWithInvalidURL) { GURL url("http://chromium.test"); ASSERT_FALSE(GURL(kInvalidURL).is_valid()); LoadHtml([NSString stringWithFormat:@"<iframe src='%s'/>", kInvalidURL], url); EXPECT_EQ(url, web_state()->GetLastCommittedURL()); } +INSTANTIATE_TEST_CASES(CRWWebControllerInvalidUrlTest); + // Real WKWebView is required for CRWWebControllerMessageFromIFrame. -typedef WebTestWithWebState CRWWebControllerMessageFromIFrame; +typedef ProgrammaticWebTestWithWebState CRWWebControllerMessageFromIFrame; // Tests that invalid message from iframe does not cause a crash. -TEST_F(CRWWebControllerMessageFromIFrame, InvalidMessage) { +TEST_P(CRWWebControllerMessageFromIFrame, InvalidMessage) { static NSString* const kHTMLIFrameSendsInvalidMessage = @"<body><iframe name='f'></iframe></body>"; @@ -521,18 +631,20 @@ "frames['f'].__gCrWeb.message.invokeOnHost(bad_message);"); } +INSTANTIATE_TEST_CASES(CRWWebControllerMessageFromIFrame); + // Real WKWebView is required for CRWWebControllerJSExecutionTest. -typedef WebTestWithWebController CRWWebControllerJSExecutionTest; +typedef ProgrammaticWebTestWithWebController CRWWebControllerJSExecutionTest; // Tests that a script correctly evaluates to boolean. -TEST_F(CRWWebControllerJSExecutionTest, Execution) { +TEST_P(CRWWebControllerJSExecutionTest, Execution) { LoadHtml(@"<p></p>"); EXPECT_NSEQ(@YES, ExecuteJavaScript(@"true")); EXPECT_NSEQ(@NO, ExecuteJavaScript(@"false")); } // Tests that a script is not executed on windowID mismatch. -TEST_F(CRWWebControllerJSExecutionTest, WindowIdMissmatch) { +TEST_P(CRWWebControllerJSExecutionTest, WindowIdMissmatch) { LoadHtml(@"<p></p>"); // Script is evaluated since windowID is matched. ExecuteJavaScript(@"window.test1 = '1';"); @@ -546,6 +658,8 @@ EXPECT_FALSE(ExecuteJavaScript(@"window.test2")); } +INSTANTIATE_TEST_CASES(CRWWebControllerJSExecutionTest); + // Test fixture to test that DownloadControllerDelegate::OnDownloadCreated // callback is trigerred if CRWWebController can not display the response. class CRWWebControllerDownloadTest : public CRWWebControllerTest { @@ -590,7 +704,7 @@ // Tests that webView:decidePolicyForNavigationResponse:decisionHandler: creates // the DownloadTask for NSURLResponse. -TEST_F(CRWWebControllerDownloadTest, CreationWithNSURLResponse) { +TEST_P(CRWWebControllerDownloadTest, CreationWithNSURLResponse) { // Simulate download response. int64_t content_length = 10; NSURLResponse* response = @@ -617,7 +731,7 @@ // Tests that webView:decidePolicyForNavigationResponse:decisionHandler: creates // the DownloadTask for NSHTTPURLResponse. -TEST_F(CRWWebControllerDownloadTest, CreationWithNSHTTPURLResponse) { +TEST_P(CRWWebControllerDownloadTest, CreationWithNSHTTPURLResponse) { // Simulate download response. const char kContentDisposition[] = "attachment; filename=download.test"; NSURLResponse* response = [[NSHTTPURLResponse alloc] @@ -646,7 +760,7 @@ // Tests that webView:decidePolicyForNavigationResponse:decisionHandler: creates // the DownloadTask for NSHTTPURLResponse and iframes. -TEST_F(CRWWebControllerDownloadTest, IFrameCreationWithNSHTTPURLResponse) { +TEST_P(CRWWebControllerDownloadTest, IFrameCreationWithNSHTTPURLResponse) { // Simulate download response. const char kContentDisposition[] = "attachment; filename=download.test"; NSURLResponse* response = [[NSHTTPURLResponse alloc] @@ -675,7 +789,7 @@ // Tests that webView:decidePolicyForNavigationResponse:decisionHandler: does // not create the DownloadTask for unsupported data:// URLs. -TEST_F(CRWWebControllerDownloadTest, DataUrlResponse) { +TEST_P(CRWWebControllerDownloadTest, DataUrlResponse) { // Simulate download response. NSURLResponse* response = [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"data:data"] @@ -690,7 +804,7 @@ } // Tests |currentURLWithTrustLevel:| method. -TEST_F(CRWWebControllerTest, CurrentUrlWithTrustLevel) { +TEST_P(CRWWebControllerTest, CurrentUrlWithTrustLevel) { AddPendingItem(GURL("http://chromium.test"), ui::PAGE_TRANSITION_TYPED); [[[mock_web_view_ stub] andReturnBool:NO] hasOnlySecureContent]; @@ -713,45 +827,7 @@ EXPECT_EQ(kAbsolute, trust_level); } -// Tests that when a placeholder navigation is preempted by another navigation, -// WebStateObservers get neither a DidStartNavigation nor a DidFinishNavigation -// call for the corresponding native URL navigation. -TEST_F(CRWWebControllerTest, AbortNativeUrlNavigation) { - // The legacy navigation manager doesn't have the concept of placeholder - // navigations. - if (!GetWebClient()->IsSlimNavigationManagerEnabled()) - return; - GURL native_url( - url::SchemeHostPort(kTestNativeContentScheme, "ui", 0).Serialize()); - NSString* placeholder_url = [NSString - stringWithFormat:@"%s%s", "about:blank?for=", native_url.spec().c_str()]; - TestWebStateObserver observer(web_state()); - - WKNavigation* navigation = - static_cast<WKNavigation*>([[NSObject alloc] init]); - [static_cast<WKWebView*>([[mock_web_view_ stub] andReturn:navigation]) - loadRequest:OCMOCK_ANY]; - TestNativeContentProvider* mock_native_provider = - [[TestNativeContentProvider alloc] init]; - [web_controller() setNativeProvider:mock_native_provider]; - - AddPendingItem(native_url, ui::PAGE_TRANSITION_TYPED); - - // Trigger a placeholder navigation. - [web_controller() loadCurrentURL]; - - // Simulate the WKNavigationDelegate callbacks for the placeholder navigation - // arriving after another pending item has already been created. - AddPendingItem(GURL(kTestURLString), ui::PAGE_TRANSITION_TYPED); - SetWebViewURL(placeholder_url); - [navigation_delegate_ webView:mock_web_view_ - didStartProvisionalNavigation:navigation]; - [navigation_delegate_ webView:mock_web_view_ didCommitNavigation:navigation]; - [navigation_delegate_ webView:mock_web_view_ didFinishNavigation:navigation]; - - EXPECT_FALSE(observer.did_start_navigation_info()); - EXPECT_FALSE(observer.did_finish_navigation_info()); -} +INSTANTIATE_TEST_CASES(CRWWebControllerDownloadTest); // Test fixture to test decidePolicyForNavigationAction:decisionHandler: // decisionHandler's callback result. @@ -795,7 +871,7 @@ // specific URL. App specific pages have elevated privileges and WKWebView uses // the same renderer process for all page frames. With that running App specific // pages are not allowed in the same process as a web site from the internet. -TEST_F(CRWWebControllerPolicyDeciderTest, +TEST_P(CRWWebControllerPolicyDeciderTest, AllowAppSpecificIFrameFromAppSpecificPage) { NSURL* app_url = [NSURL URLWithString:@(kTestAppSpecificURL)]; NSMutableURLRequest* app_url_request = @@ -807,7 +883,7 @@ // Tests that App specific URLs in iframes are not allowed if the main frame is // not App specific URL. -TEST_F(CRWWebControllerPolicyDeciderTest, +TEST_P(CRWWebControllerPolicyDeciderTest, DisallowAppSpecificIFrameFromRegularPage) { NSURL* app_url = [NSURL URLWithString:@(kTestAppSpecificURL)]; NSMutableURLRequest* app_url_request = @@ -817,11 +893,14 @@ app_url_request, WKNavigationActionPolicyCancel)); } +INSTANTIATE_TEST_CASES(CRWWebControllerPolicyDeciderTest); + // Test fixture for testing CRWWebController presenting native content. -class CRWWebControllerNativeContentTest : public WebTestWithWebController { +class CRWWebControllerNativeContentTest + : public ProgrammaticWebTestWithWebController { protected: void SetUp() override { - WebTestWithWebController::SetUp(); + ProgrammaticWebTestWithWebController::SetUp(); mock_native_provider_ = [[TestNativeContentProvider alloc] init]; [web_controller() setNativeProvider:mock_native_provider_]; } @@ -850,7 +929,7 @@ }; // Tests WebState and NavigationManager correctly return native content URL. -TEST_F(CRWWebControllerNativeContentTest, NativeContentURL) { +TEST_P(CRWWebControllerNativeContentTest, NativeContentURL) { GURL url_to_load(kTestAppSpecificURL); TestNativeContent* content = [[TestNativeContent alloc] initWithURL:url_to_load virtualURL:GURL()]; @@ -872,7 +951,7 @@ // Tests WebState and NavigationManager correctly return native content URL and // VirtualURL -TEST_F(CRWWebControllerNativeContentTest, NativeContentVirtualURL) { +TEST_P(CRWWebControllerNativeContentTest, NativeContentVirtualURL) { GURL url_to_load(kTestAppSpecificURL); GURL virtual_url(kTestURLString); TestNativeContent* content = @@ -894,13 +973,15 @@ virtual_url); } +INSTANTIATE_TEST_CASES(CRWWebControllerNativeContentTest); + // Test fixture for window.open tests. -class WindowOpenByDomTest : public WebTestWithWebController { +class WindowOpenByDomTest : public ProgrammaticWebTestWithWebController { protected: WindowOpenByDomTest() : opener_url_("http://test") {} void SetUp() override { - WebTestWithWebController::SetUp(); + ProgrammaticWebTestWithWebController::SetUp(); web_state()->SetDelegate(&delegate_); LoadHtml(@"<html><body></body></html>", opener_url_); } @@ -923,7 +1004,7 @@ }; // Tests that absence of web state delegate is handled gracefully. -TEST_F(WindowOpenByDomTest, NoDelegate) { +TEST_P(WindowOpenByDomTest, NoDelegate) { web_state()->SetDelegate(nullptr); EXPECT_NSEQ([NSNull null], OpenWindowByDom()); @@ -934,7 +1015,7 @@ // Tests that window.open triggered by user gesture opens a new non-popup // window. -TEST_F(WindowOpenByDomTest, OpenWithUserGesture) { +TEST_P(WindowOpenByDomTest, OpenWithUserGesture) { [web_controller() touched:YES]; EXPECT_NSEQ(@"[object Window]", OpenWindowByDom()); @@ -945,7 +1026,7 @@ // Tests that window.open executed w/o user gesture does not open a new window, // but blocks popup instead. -TEST_F(WindowOpenByDomTest, BlockPopup) { +TEST_P(WindowOpenByDomTest, BlockPopup) { ASSERT_FALSE([web_controller() userIsInteracting]); EXPECT_NSEQ([NSNull null], OpenWindowByDom()); @@ -957,7 +1038,7 @@ // Tests that window.open executed w/o user gesture opens a new window, assuming // that delegate allows popups. -TEST_F(WindowOpenByDomTest, DontBlockPopup) { +TEST_P(WindowOpenByDomTest, DontBlockPopup) { delegate_.allow_popups(opener_url_); EXPECT_NSEQ(@"[object Window]", OpenWindowByDom()); @@ -967,7 +1048,7 @@ } // Tests that window.close closes the web state. -TEST_F(WindowOpenByDomTest, CloseWindow) { +TEST_P(WindowOpenByDomTest, CloseWindow) { delegate_.allow_popups(opener_url_); ASSERT_NSEQ(@"[object Window]", OpenWindowByDom()); @@ -982,9 +1063,11 @@ EXPECT_TRUE(delegate_.popups().empty()); } +INSTANTIATE_TEST_CASES(WindowOpenByDomTest); + // Tests page title changes. -typedef WebTestWithWebState CRWWebControllerTitleTest; -TEST_F(CRWWebControllerTitleTest, TitleChange) { +typedef ProgrammaticWebTestWithWebState CRWWebControllerTitleTest; +TEST_P(CRWWebControllerTitleTest, TitleChange) { // Observes and waits for TitleWasSet call. class TitleObserver : public WebStateObserver { public: @@ -1023,15 +1106,17 @@ }; // Tests that fragment change navigations use title from the previous page. -TEST_F(CRWWebControllerTitleTest, FragmentChangeNavigationsUsePreviousTitle) { +TEST_P(CRWWebControllerTitleTest, FragmentChangeNavigationsUsePreviousTitle) { LoadHtml(@"<title>Title1</title>"); ASSERT_EQ("Title1", base::UTF16ToUTF8(web_state()->GetTitle())); ExecuteJavaScript(@"window.location.hash = '#1'"); EXPECT_EQ("Title1", base::UTF16ToUTF8(web_state()->GetTitle())); } +INSTANTIATE_TEST_CASES(CRWWebControllerTitleTest); + // Test fixture for JavaScript execution. -class ScriptExecutionTest : public WebTestWithWebController { +class ScriptExecutionTest : public ProgrammaticWebTestWithWebController { protected: // Calls |executeUserJavaScript:completionHandler:|, waits for script // execution completion, and synchronously returns the result. @@ -1059,7 +1144,7 @@ }; // Tests evaluating user script on an http page. -TEST_F(ScriptExecutionTest, UserScriptOnHttpPage) { +TEST_P(ScriptExecutionTest, UserScriptOnHttpPage) { LoadHtml(@"<html></html>", GURL(kTestURLString)); NSError* error = nil; EXPECT_NSEQ(@0, ExecuteUserJavaScript(@"window.w = 0;", &error)); @@ -1071,7 +1156,7 @@ // Tests evaluating user script on app-specific page. Pages with app-specific // URLs have elevated privileges and JavaScript execution should not be allowed // for them. -TEST_F(ScriptExecutionTest, UserScriptOnAppSpecificPage) { +TEST_P(ScriptExecutionTest, UserScriptOnAppSpecificPage) { LoadHtml(@"<html></html>", GURL(kTestURLString)); // Change last committed URL to app-specific URL. @@ -1081,7 +1166,7 @@ GURL(kTestAppSpecificURL), Referrer(), ui::PAGE_TRANSITION_TYPED, NavigationInitiationType::BROWSER_INITIATED, NavigationManager::UserAgentOverrideOption::INHERIT); - [nav_manager.GetSessionController() commitPendingItem]; + nav_manager.CommitPendingItem(); NSError* error = nil; EXPECT_FALSE(ExecuteUserJavaScript(@"window.w = 0;", &error)); @@ -1092,11 +1177,14 @@ EXPECT_FALSE(ExecuteJavaScript(@"window.w")); }; +INSTANTIATE_TEST_CASES(ScriptExecutionTest); + // Fixture class to test WKWebView crashes. -class CRWWebControllerWebProcessTest : public WebTestWithWebController { +class CRWWebControllerWebProcessTest + : public ProgrammaticWebTestWithWebController { protected: void SetUp() override { - WebTestWithWebController::SetUp(); + ProgrammaticWebTestWithWebController::SetUp(); webView_ = BuildTerminatedWKWebView(); TestWebViewContentView* webViewContentView = [[TestWebViewContentView alloc] initWithMockWebView:webView_ @@ -1111,7 +1199,7 @@ // Tests that WebStateDelegate::RenderProcessGone is called when WKWebView web // process has crashed. -TEST_F(CRWWebControllerWebProcessTest, Crash) { +TEST_P(CRWWebControllerWebProcessTest, Crash) { ASSERT_TRUE([web_controller() isViewAlive]); ASSERT_FALSE([web_controller() isWebProcessCrashed]); ASSERT_FALSE(web_state()->IsCrashed()); @@ -1132,7 +1220,7 @@ // Tests that WebState is considered as evicted but not crashed when calling // SetWebUsageEnabled(false). -TEST_F(CRWWebControllerWebProcessTest, Eviction) { +TEST_P(CRWWebControllerWebProcessTest, Eviction) { ASSERT_TRUE([web_controller() isViewAlive]); ASSERT_FALSE([web_controller() isWebProcessCrashed]); ASSERT_FALSE(web_state()->IsCrashed()); @@ -1145,10 +1233,13 @@ EXPECT_TRUE(web_state()->IsEvicted()); }; +INSTANTIATE_TEST_CASES(CRWWebControllerWebProcessTest); + // Test fixture for -[CRWWebController loadCurrentURLIfNecessary] method. -class LoadIfNecessaryTest : public WebTest { +class LoadIfNecessaryTest : public WebTest, public ProgrammaticTestMixin { protected: void SetUp() override { + ProgrammaticTestMixin::SetUp(); WebTest::SetUp(); web_state_ = std::make_unique<WebStateImpl>( WebState::CreateParams(GetBrowserState()), GetTestSessionStorage()); @@ -1184,7 +1275,7 @@ // Tests that |loadCurrentURLIfNecessary| restores the page after disabling and // re-enabling web usage. -TEST_F(LoadIfNecessaryTest, RestoredFromHistory) { +TEST_P(LoadIfNecessaryTest, RestoredFromHistory) { ASSERT_FALSE(test::IsWebViewContainingText(web_state_.get(), "pony")); [web_state_->GetWebController() loadCurrentURLIfNecessary]; EXPECT_TRUE(test::WaitForWebViewContainingText(web_state_.get(), "pony")); @@ -1192,7 +1283,7 @@ // Tests that |loadCurrentURLIfNecessary| restores the page after disabling and // re-enabling web usage. -TEST_F(LoadIfNecessaryTest, DisableAndReenableWebUsage) { +TEST_P(LoadIfNecessaryTest, DisableAndReenableWebUsage) { [web_state_->GetWebController() loadCurrentURLIfNecessary]; EXPECT_TRUE(test::WaitForWebViewContainingText(web_state_.get(), "pony")); @@ -1205,4 +1296,9 @@ [web_state_->GetWebController() loadCurrentURLIfNecessary]; EXPECT_TRUE(test::WaitForWebViewContainingText(web_state_.get(), "pony")); }; + +INSTANTIATE_TEST_CASES(LoadIfNecessaryTest); + +#undef INSTANTIATE_TEST_CASES + } // namespace web
diff --git a/ios/web_view/internal/autofill/cwv_autofill_suggestion.mm b/ios/web_view/internal/autofill/cwv_autofill_suggestion.mm index 611f5d3..e013ae16 100644 --- a/ios/web_view/internal/autofill/cwv_autofill_suggestion.mm +++ b/ios/web_view/internal/autofill/cwv_autofill_suggestion.mm
@@ -4,8 +4,11 @@ #import "ios/web_view/internal/autofill/cwv_autofill_suggestion_internal.h" +#include "base/strings/sys_string_conversions.h" +#include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/popup_item_ids.h" #import "components/autofill/ios/browser/form_suggestion.h" +#include "ui/base/resource/resource_bundle.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -42,6 +45,17 @@ return [_formSuggestion.displayDescription copy]; } +- (UIImage* __nullable)icon { + if ([_formSuggestion.icon length] == 0) { + return nil; + } + int resourceID = autofill::CreditCard::IconResourceId( + base::SysNSStringToUTF8(_formSuggestion.icon)); + return ui::ResourceBundle::GetSharedInstance() + .GetNativeImageNamed(resourceID) + .ToUIImage(); +} + #pragma mark - NSObject - (NSString*)debugDescription {
diff --git a/ios/web_view/public/cwv_autofill_suggestion.h b/ios/web_view/public/cwv_autofill_suggestion.h index 172e7f0..05ca843 100644 --- a/ios/web_view/public/cwv_autofill_suggestion.h +++ b/ios/web_view/public/cwv_autofill_suggestion.h
@@ -6,6 +6,7 @@ #define IOS_WEB_VIEW_PUBLIC_CWV_AUTOFILL_SUGGESTION_H_ #import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> #import "cwv_export.h" @@ -56,6 +57,10 @@ // suggestions. @property(nonatomic, copy, readonly, nullable) NSString* displayDescription; +// The icon image of the suggestion, currently this is only used for displaying +// credit card network icon. +@property(nonatomic, readonly, nullable) UIImage* icon; + - (instancetype)init NS_UNAVAILABLE; @end
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn index 8c665fb..bfebba7 100644 --- a/ipc/BUILD.gn +++ b/ipc/BUILD.gn
@@ -83,6 +83,7 @@ ":mojom", ":native_handle_type_converters", ":param_traits", + "//mojo/public/cpp/base", "//mojo/public/cpp/bindings", "//mojo/public/cpp/system", ] @@ -182,7 +183,7 @@ ] public_deps = [ "//mojo/public/interfaces/bindings", - "//mojo/public/mojom/base:read_only_buffer", + "//mojo/public/mojom/base", ] # Don't generate a variant sources since we depend on generated internal
diff --git a/ipc/OWNERS b/ipc/OWNERS index fa8fd311..da4755b 100644 --- a/ipc/OWNERS +++ b/ipc/OWNERS
@@ -12,8 +12,12 @@ per-file *_messages*.h=file://ipc/SECURITY_OWNERS per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS +per-file *_mojom_traits*.*=set noparent +per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS per-file *_param_traits*.*=set noparent per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS +per-file *.typemap=set noparent +per-file *.typemap=file://ipc/SECURITY_OWNERS per-file *_type_converter*.*=set noparent per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
diff --git a/ipc/ipc.mojom b/ipc/ipc.mojom index 87aedaeb..9631ce8 100644 --- a/ipc/ipc.mojom +++ b/ipc/ipc.mojom
@@ -4,21 +4,27 @@ module IPC.mojom; -import "mojo/public/mojom/base/read_only_buffer.mojom"; +import "mojo/public/mojom/base/big_buffer.mojom"; import "mojo/public/interfaces/bindings/native_struct.mojom"; // A placeholder interface type since we don't yet support generic associated // message pipe handles. interface GenericInterface {}; +// Typemapped such that arbitrarily large IPC::Message objects can be sent and +// received with minimal copying. +struct Message { + mojo_base.mojom.BigBuffer buffer; + array<mojo.native.SerializedHandle>? handles; +}; + interface Channel { // Informs the remote end of this client's PID. Must be called exactly once, // before any calls to Receive() below. SetPeerPid(int32 pid); // Transmits a classical Chrome IPC message. - Receive(mojo_base.mojom.ReadOnlyBuffer data, - array<mojo.native.SerializedHandle>? handles); + Receive(Message message); // Requests a Channel-associated interface. GetAssociatedInterface(string name, associated GenericInterface& request);
diff --git a/ipc/ipc_channel_mojo_unittest.cc b/ipc/ipc_channel_mojo_unittest.cc index c703c87..337e187 100644 --- a/ipc/ipc_channel_mojo_unittest.cc +++ b/ipc/ipc_channel_mojo_unittest.cc
@@ -68,8 +68,8 @@ class ListenerThatExpectsOK : public IPC::Listener { public: - ListenerThatExpectsOK(base::Closure quit_closure) - : received_ok_(false), quit_closure_(quit_closure) {} + explicit ListenerThatExpectsOK(base::OnceClosure quit_closure) + : received_ok_(false), quit_closure_(std::move(quit_closure)) {} ~ListenerThatExpectsOK() override = default; @@ -79,7 +79,7 @@ EXPECT_TRUE(iter.ReadString(&should_be_ok)); EXPECT_EQ(should_be_ok, "OK"); received_ok_ = true; - quit_closure_.Run(); + std::move(quit_closure_).Run(); return true; } @@ -94,24 +94,24 @@ private: bool received_ok_; - base::Closure quit_closure_; + base::OnceClosure quit_closure_; }; class TestListenerBase : public IPC::Listener { public: - TestListenerBase(base::Closure quit_closure) : quit_closure_(quit_closure) {} + explicit TestListenerBase(base::OnceClosure quit_closure) + : quit_closure_(std::move(quit_closure)) {} ~TestListenerBase() override = default; - - void OnChannelError() override { quit_closure_.Run(); } + void OnChannelError() override { RunQuitClosure(); } void set_sender(IPC::Sender* sender) { sender_ = sender; } IPC::Sender* sender() const { return sender_; } - base::Closure quit_closure() const { return quit_closure_; } + void RunQuitClosure() { std::move(quit_closure_).Run(); } private: IPC::Sender* sender_ = nullptr; - base::Closure quit_closure_; + base::OnceClosure quit_closure_; }; using IPCChannelMojoTest = IPCChannelMojoTestBase; @@ -171,8 +171,8 @@ class ListenerExpectingErrors : public TestListenerBase { public: - ListenerExpectingErrors(base::Closure quit_closure) - : TestListenerBase(quit_closure), has_error_(false) {} + ListenerExpectingErrors(base::OnceClosure quit_closure) + : TestListenerBase(std::move(quit_closure)), has_error_(false) {} bool OnMessageReceived(const IPC::Message& message) override { return true; } @@ -189,14 +189,17 @@ class ListenerThatQuits : public IPC::Listener { public: - ListenerThatQuits(base::Closure quit_closure) : quit_closure_(quit_closure) {} + explicit ListenerThatQuits(base::OnceClosure quit_closure) + : quit_closure_(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { return true; } - void OnChannelConnected(int32_t peer_pid) override { quit_closure_.Run(); } + void OnChannelConnected(int32_t peer_pid) override { + std::move(quit_closure_).Run(); + } private: - base::Closure quit_closure_; + base::OnceClosure quit_closure_; }; // A long running process that connects to us. @@ -332,8 +335,8 @@ class ListenerThatExpectsMessagePipe : public TestListenerBase { public: - ListenerThatExpectsMessagePipe(base::Closure quit_closure) - : TestListenerBase(quit_closure) {} + ListenerThatExpectsMessagePipe(base::OnceClosure quit_closure) + : TestListenerBase(std::move(quit_closure)) {} ~ListenerThatExpectsMessagePipe() override = default; @@ -392,9 +395,10 @@ class ListenerThatExpectsMessagePipeUsingParamTrait : public TestListenerBase { public: explicit ListenerThatExpectsMessagePipeUsingParamTrait( - base::Closure quit_closure, + base::OnceClosure quit_closure, bool receiving_valid) - : TestListenerBase(quit_closure), receiving_valid_(receiving_valid) {} + : TestListenerBase(std::move(quit_closure)), + receiving_valid_(receiving_valid) {} ~ListenerThatExpectsMessagePipeUsingParamTrait() override = default; @@ -506,14 +510,14 @@ class ListenerSendingOneOk : public TestListenerBase { public: - ListenerSendingOneOk(base::Closure quit_closure) - : TestListenerBase(quit_closure) {} + ListenerSendingOneOk(base::OnceClosure quit_closure) + : TestListenerBase(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { return true; } void OnChannelConnected(int32_t peer_pid) override { ListenerThatExpectsOK::SendOK(sender()); - quit_closure().Run(); + RunQuitClosure(); } }; @@ -534,7 +538,8 @@ public: static const int kNumMessages; - ListenerWithSimpleAssociatedInterface() : binding_(this) {} + explicit ListenerWithSimpleAssociatedInterface(base::OnceClosure quit_closure) + : quit_closure_(std::move(quit_closure)), binding_(this) {} ~ListenerWithSimpleAssociatedInterface() override = default; @@ -547,12 +552,12 @@ return true; } - void OnChannelError() override { CHECK(received_quit_); } + void OnChannelError() override { CHECK(!quit_closure_); } void RegisterInterfaceFactory(IPC::Channel* channel) { channel->GetAssociatedInterfaceSupport()->AddAssociatedInterface( - base::Bind(&ListenerWithSimpleAssociatedInterface::BindRequest, - base::Unretained(this))); + base::BindRepeating(&ListenerWithSimpleAssociatedInterface::BindRequest, + base::Unretained(this))); } private: @@ -569,9 +574,8 @@ void RequestQuit(RequestQuitCallback callback) override { EXPECT_EQ(kNumMessages, num_messages_received_); - received_quit_ = true; std::move(callback).Run(); - base::RunLoop::QuitCurrentWhenIdleDeprecated(); + std::move(quit_closure_).Run(); } void BindRequest(IPC::mojom::SimpleTestDriverAssociatedRequest request) { @@ -581,7 +585,7 @@ int32_t next_expected_value_ = 0; int num_messages_received_ = 0; - bool received_quit_ = false; + base::OnceClosure quit_closure_; mojo::AssociatedBinding<IPC::mojom::SimpleTestDriver> binding_; }; @@ -590,7 +594,8 @@ class ListenerSendingAssociatedMessages : public IPC::Listener { public: - ListenerSendingAssociatedMessages() = default; + explicit ListenerSendingAssociatedMessages(base::OnceClosure quit_closure) + : quit_closure_(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { return true; } @@ -606,28 +611,31 @@ driver_->ExpectValue(i); SendValue(channel_, i); } - driver_->RequestQuit(base::Bind(&OnQuitAck)); + driver_->RequestQuit(base::BindOnce( + &ListenerSendingAssociatedMessages::OnQuitAck, base::Unretained(this))); } void set_channel(IPC::Channel* channel) { channel_ = channel; } private: - static void OnQuitAck() { base::RunLoop::QuitCurrentWhenIdleDeprecated(); } + void OnQuitAck() { std::move(quit_closure_).Run(); } IPC::Channel* channel_ = nullptr; IPC::mojom::SimpleTestDriverAssociatedPtr driver_; + base::OnceClosure quit_closure_; }; TEST_F(IPCChannelMojoTest, SimpleAssociatedInterface) { Init("SimpleAssociatedInterfaceClient"); - ListenerWithSimpleAssociatedInterface listener; + base::RunLoop run_loop; + ListenerWithSimpleAssociatedInterface listener(run_loop.QuitClosure()); CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); listener.RegisterInterfaceFactory(channel()); - base::RunLoop().Run(); + run_loop.Run(); channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); @@ -635,11 +643,12 @@ } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(SimpleAssociatedInterfaceClient) { - ListenerSendingAssociatedMessages listener; + base::RunLoop run_loop; + ListenerSendingAssociatedMessages listener(run_loop.QuitClosure()); Connect(&listener); listener.set_channel(channel()); - base::RunLoop().Run(); + run_loop.Run(); Close(); } @@ -717,7 +726,9 @@ public: static const int kNumMessages; - ListenerWithSimpleProxyAssociatedInterface() : binding_(this) {} + explicit ListenerWithSimpleProxyAssociatedInterface( + base::OnceClosure quit_closure) + : quit_closure_(std::move(quit_closure)), binding_(this) {} ~ListenerWithSimpleProxyAssociatedInterface() override = default; @@ -730,7 +741,7 @@ return true; } - void OnChannelError() override { CHECK(received_quit_); } + void OnChannelError() override { CHECK(!quit_closure_); } void OnAssociatedInterfaceRequest( const std::string& interface_name, @@ -741,7 +752,7 @@ } bool received_all_messages() const { - return num_messages_received_ == kNumMessages && received_quit_; + return num_messages_received_ == kNumMessages && !quit_closure_; } private: @@ -757,10 +768,9 @@ void RequestValue(RequestValueCallback callback) override { NOTREACHED(); } void RequestQuit(RequestQuitCallback callback) override { - received_quit_ = true; std::move(callback).Run(); binding_.Close(); - base::RunLoop::QuitCurrentWhenIdleDeprecated(); + std::move(quit_closure_).Run(); } void BindRequest(IPC::mojom::SimpleTestDriverAssociatedRequest request) { @@ -770,7 +780,7 @@ int32_t next_expected_value_ = 0; int num_messages_received_ = 0; - bool received_quit_ = false; + base::OnceClosure quit_closure_; mojo::AssociatedBinding<IPC::mojom::SimpleTestDriver> binding_; }; @@ -780,11 +790,12 @@ TEST_F(IPCChannelProxyMojoTest, ProxyThreadAssociatedInterface) { Init("ProxyThreadAssociatedInterfaceClient"); - ListenerWithSimpleProxyAssociatedInterface listener; + base::RunLoop run_loop; + ListenerWithSimpleProxyAssociatedInterface listener(run_loop.QuitClosure()); CreateProxy(&listener); RunProxy(); - base::RunLoop().Run(); + run_loop.Run(); EXPECT_TRUE(WaitForClientShutdown()); EXPECT_TRUE(listener.received_all_messages()); @@ -842,8 +853,9 @@ driver->ExpectValue(i); SendValue(proxy(), i); } - driver->RequestQuit(base::RunLoop::QuitCurrentWhenIdleClosureDeprecated()); - base::RunLoop().Run(); + base::RunLoop run_loop; + driver->RequestQuit(run_loop.QuitClosure()); + run_loop.Run(); DestroyProxy(); } @@ -869,7 +881,7 @@ IPC::mojom::IndirectTestDriverAssociatedRequest(std::move(handle))); } - void set_ping_handler(const base::Closure& handler) { + void set_ping_handler(const base::RepeatingClosure& handler) { ping_handler_ = handler; } @@ -889,7 +901,7 @@ mojo::AssociatedBinding<IPC::mojom::IndirectTestDriver> driver_binding_; mojo::AssociatedBinding<IPC::mojom::PingReceiver> ping_receiver_binding_; - base::Closure ping_handler_; + base::RepeatingClosure ping_handler_; }; TEST_F(IPCChannelProxyMojoTest, ProxyThreadAssociatedInterfaceIndirect) { @@ -972,7 +984,7 @@ } void RequestQuit(RequestQuitCallback callback) override { - quit_closure_.Run(); + std::move(quit_closure_).Run(); std::move(callback).Run(); } @@ -1006,7 +1018,7 @@ IPC::Sender* sync_sender_ = nullptr; int32_t next_expected_value_ = 0; int32_t response_value_ = 0; - base::Closure quit_closure_; + base::OnceClosure quit_closure_; mojo::AssociatedBinding<IPC::mojom::SimpleTestDriver> binding_; }; @@ -1229,8 +1241,10 @@ class ExpectValueSequenceListener : public IPC::Listener { public: - explicit ExpectValueSequenceListener(base::queue<int32_t>* expected_values) - : expected_values_(expected_values) {} + ExpectValueSequenceListener(base::queue<int32_t>* expected_values, + base::OnceClosure quit_closure) + : expected_values_(expected_values), + quit_closure_(std::move(quit_closure)) {} ~ExpectValueSequenceListener() override = default; // IPC::Listener: @@ -1242,12 +1256,13 @@ EXPECT_EQ(expected_values_->front(), should_be_expected); expected_values_->pop(); if (expected_values_->empty()) - base::RunLoop::QuitCurrentWhenIdleDeprecated(); + std::move(quit_closure_).Run(); return true; } private: base::queue<int32_t>* expected_values_; + base::OnceClosure quit_closure_; DISALLOW_COPY_AND_ASSIGN(ExpectValueSequenceListener); }; @@ -1255,7 +1270,9 @@ DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(CreatePausedClient, ChannelProxyClient) { base::queue<int32_t> expected_values; - ExpectValueSequenceListener listener(&expected_values); + base::RunLoop run_loop; + ExpectValueSequenceListener listener(&expected_values, + run_loop.QuitClosure()); CreateProxy(&listener); expected_values.push(1); expected_values.push(4); @@ -1263,7 +1280,7 @@ expected_values.push(2); expected_values.push(3); RunProxy(); - base::RunLoop().Run(); + run_loop.Run(); EXPECT_TRUE(expected_values.empty()); DestroyProxy(); } @@ -1290,19 +1307,19 @@ class AssociatedInterfaceDroppingListener : public IPC::Listener { public: - AssociatedInterfaceDroppingListener(const base::Closure& callback) - : callback_(callback) {} + AssociatedInterfaceDroppingListener(base::OnceClosure callback) + : callback_(std::move(callback)) {} bool OnMessageReceived(const IPC::Message& message) override { return false; } void OnAssociatedInterfaceRequest( const std::string& interface_name, mojo::ScopedInterfaceEndpointHandle handle) override { if (interface_name == IPC::mojom::SimpleTestDriver::Name_) - base::ResetAndReturn(&callback_).Run(); + std::move(callback_).Run(); } private: - base::Closure callback_; + base::OnceClosure callback_; }; DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(DropAssociatedRequest, @@ -1321,8 +1338,8 @@ class ListenerThatExpectsSharedMemory : public TestListenerBase { public: - ListenerThatExpectsSharedMemory(base::Closure quit_closure) - : TestListenerBase(quit_closure) {} + ListenerThatExpectsSharedMemory(base::OnceClosure quit_closure) + : TestListenerBase(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); @@ -1409,7 +1426,7 @@ template <class SharedMemoryRegionType> class ListenerThatExpectsSharedMemoryRegion : public TestListenerBase { public: - ListenerThatExpectsSharedMemoryRegion(base::Closure quit_closure) + explicit ListenerThatExpectsSharedMemoryRegion(base::OnceClosure quit_closure) : TestListenerBase(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { @@ -1504,8 +1521,8 @@ class ListenerThatExpectsFile : public TestListenerBase { public: - ListenerThatExpectsFile(base::Closure quit_closure) - : TestListenerBase(quit_closure) {} + explicit ListenerThatExpectsFile(base::OnceClosure quit_closure) + : TestListenerBase(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); @@ -1550,8 +1567,8 @@ class ListenerThatExpectsFileAndMessagePipe : public TestListenerBase { public: - ListenerThatExpectsFileAndMessagePipe(base::Closure quit_closure) - : TestListenerBase(quit_closure) {} + explicit ListenerThatExpectsFileAndMessagePipe(base::OnceClosure quit_closure) + : TestListenerBase(std::move(quit_closure)) {} ~ListenerThatExpectsFileAndMessagePipe() override = default; @@ -1607,12 +1624,12 @@ class ListenerThatVerifiesPeerPid : public TestListenerBase { public: - ListenerThatVerifiesPeerPid(base::Closure quit_closure) - : TestListenerBase(quit_closure) {} + explicit ListenerThatVerifiesPeerPid(base::OnceClosure quit_closure) + : TestListenerBase(std::move(quit_closure)) {} void OnChannelConnected(int32_t peer_pid) override { EXPECT_EQ(peer_pid, kMagicChildId); - quit_closure().Run(); + RunQuitClosure(); } bool OnMessageReceived(const IPC::Message& message) override {
diff --git a/ipc/ipc_message_pipe_reader.cc b/ipc/ipc_message_pipe_reader.cc index 4a8ca8f..b055d41 100644 --- a/ipc/ipc_message_pipe_reader.cc +++ b/ipc/ipc_message_pipe_reader.cc
@@ -63,10 +63,7 @@ if (!sender_) return false; - sender_->Receive(base::make_span(static_cast<const uint8_t*>(message->data()), - message->size()), - std::move(handles)); - + sender_->Receive(MessageView(*message, std::move(handles))); DVLOG(4) << "Send " << message->type() << ": " << message->size(); return true; } @@ -84,23 +81,20 @@ delegate_->OnPeerPidReceived(peer_pid); } -void MessagePipeReader::Receive( - base::span<const uint8_t> data, - base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles) { - if (data.empty()) { +void MessagePipeReader::Receive(MessageView message_view) { + if (!message_view.size()) { delegate_->OnBrokenDataReceived(); return; } - Message message(reinterpret_cast<const char*>(data.data()), - static_cast<uint32_t>(data.size())); + Message message(message_view.data(), message_view.size()); if (!message.IsValid()) { delegate_->OnBrokenDataReceived(); return; } DVLOG(4) << "Receive " << message.type() << ": " << message.size(); - MojoResult write_result = - ChannelMojo::WriteToMessageAttachmentSet(std::move(handles), &message); + MojoResult write_result = ChannelMojo::WriteToMessageAttachmentSet( + message_view.TakeHandles(), &message); if (write_result != MOJO_RESULT_OK) { OnPipeError(write_result); return;
diff --git a/ipc/ipc_message_pipe_reader.h b/ipc/ipc_message_pipe_reader.h index 77dd9ee..e1c3fd4 100644 --- a/ipc/ipc_message_pipe_reader.h +++ b/ipc/ipc_message_pipe_reader.h
@@ -22,7 +22,6 @@ #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" #include "mojo/public/cpp/system/core.h" #include "mojo/public/cpp/system/message_pipe.h" -#include "mojo/public/interfaces/bindings/native_struct.mojom.h" namespace IPC { namespace internal { @@ -95,9 +94,7 @@ private: // mojom::Channel: void SetPeerPid(int32_t peer_pid) override; - void Receive(base::span<const uint8_t> data, - base::Optional<std::vector<mojo::native::SerializedHandlePtr>> - handles) override; + void Receive(MessageView message_view) override; void GetAssociatedInterface( const std::string& name, mojom::GenericInterfaceAssociatedRequest request) override;
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc index 981b117..01c37988 100644 --- a/ipc/ipc_message_utils.cc +++ b/ipc/ipc_message_utils.cc
@@ -1414,31 +1414,6 @@ l->append(base::StringPrintf("0x%p", p)); } -void ParamTraits<LOGFONT>::Write(base::Pickle* m, const param_type& p) { - m->WriteData(reinterpret_cast<const char*>(&p), sizeof(LOGFONT)); -} - -bool ParamTraits<LOGFONT>::Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* r) { - const char *data; - int data_size = 0; - if (iter->ReadData(&data, &data_size) && data_size == sizeof(LOGFONT)) { - const LOGFONT *font = reinterpret_cast<LOGFONT*>(const_cast<char*>(data)); - if (_tcsnlen(font->lfFaceName, LF_FACESIZE) < LF_FACESIZE) { - memcpy(r, data, sizeof(LOGFONT)); - return true; - } - } - - NOTREACHED(); - return false; -} - -void ParamTraits<LOGFONT>::Log(const param_type& p, std::string* l) { - l->append(base::StringPrintf("<LOGFONT>")); -} - void ParamTraits<MSG>::Write(base::Pickle* m, const param_type& p) { m->WriteData(reinterpret_cast<const char*>(&p), sizeof(MSG)); }
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h index 0dbf500..00a164a 100644 --- a/ipc/ipc_message_utils.h +++ b/ipc/ipc_message_utils.h
@@ -1019,16 +1019,6 @@ }; template <> -struct COMPONENT_EXPORT(IPC) ParamTraits<LOGFONT> { - typedef LOGFONT param_type; - static void Write(base::Pickle* m, const param_type& p); - static bool Read(const base::Pickle* m, - base::PickleIterator* iter, - param_type* r); - static void Log(const param_type& p, std::string* l); -}; - -template <> struct COMPONENT_EXPORT(IPC) ParamTraits<MSG> { typedef MSG param_type; static void Write(base::Pickle* m, const param_type& p);
diff --git a/ipc/ipc_mojo_bootstrap_unittest.cc b/ipc/ipc_mojo_bootstrap_unittest.cc index e5d9518..7772896 100644 --- a/ipc/ipc_mojo_bootstrap_unittest.cc +++ b/ipc/ipc_mojo_bootstrap_unittest.cc
@@ -72,14 +72,11 @@ on_peer_pid_set_.Run(); } - void Receive(base::span<const uint8_t> data, - base::Optional<std::vector<mojo::native::SerializedHandlePtr>> - handles) override { + void Receive(IPC::MessageView message_view) override { ASSERT_NE(MessageExpectation::kNotExpected, message_expectation_); received_message_ = true; - IPC::Message message(reinterpret_cast<const char*>(data.data()), - static_cast<uint32_t>(data.size())); + IPC::Message message(message_view.data(), message_view.size()); bool expected_valid = message_expectation_ == MessageExpectation::kExpectedValid; EXPECT_EQ(expected_valid, message.IsValid()); @@ -196,7 +193,9 @@ auto& sender = connection.GetSender(); uint8_t data = 0; - sender->Receive(base::make_span(&data, 0), {}); + sender->Receive( + IPC::MessageView(mojo_base::BigBufferView(base::make_span(&data, 0)), + base::nullopt /* handles */)); base::RunLoop run_loop; PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
diff --git a/ipc/message.typemap b/ipc/message.typemap new file mode 100644 index 0000000..e150786 --- /dev/null +++ b/ipc/message.typemap
@@ -0,0 +1,18 @@ +# 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. + +mojom = "//ipc/ipc.mojom" +public_headers = [ "//ipc/message_view.h" ] +traits_headers = [ "//ipc/message_mojom_traits.h" ] +sources = [ + "//ipc/message_mojom_traits.cc", + "//ipc/message_mojom_traits.h", + "//ipc/message_view.cc", + "//ipc/message_view.h", +] +public_deps = [ + "//ipc:message_support", + "//mojo/public/cpp/base:shared_typemap_traits", +] +type_mappings = [ "IPC.mojom.Message=IPC::MessageView[move_only]" ]
diff --git a/ipc/message_mojom_traits.cc b/ipc/message_mojom_traits.cc new file mode 100644 index 0000000..4aab924 --- /dev/null +++ b/ipc/message_mojom_traits.cc
@@ -0,0 +1,40 @@ +// 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. + +#include "ipc/message_mojom_traits.h" + +#include "mojo/public/cpp/base/big_buffer_mojom_traits.h" + +namespace mojo { + +// static +mojo_base::BigBufferView +StructTraits<IPC::mojom::MessageDataView, IPC::MessageView>::buffer( + IPC::MessageView& view) { + return view.TakeBufferView(); +} + +// static +base::Optional<std::vector<mojo::native::SerializedHandlePtr>> +StructTraits<IPC::mojom::MessageDataView, IPC::MessageView>::handles( + IPC::MessageView& view) { + return view.TakeHandles(); +} + +// static +bool StructTraits<IPC::mojom::MessageDataView, IPC::MessageView>::Read( + IPC::mojom::MessageDataView data, + IPC::MessageView* out) { + mojo_base::BigBufferView buffer_view; + if (!data.ReadBuffer(&buffer_view)) + return false; + base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles; + if (!data.ReadHandles(&handles)) + return false; + + *out = IPC::MessageView(std::move(buffer_view), std::move(handles)); + return true; +} + +} // namespace mojo
diff --git a/ipc/message_mojom_traits.h b/ipc/message_mojom_traits.h new file mode 100644 index 0000000..617ffbe --- /dev/null +++ b/ipc/message_mojom_traits.h
@@ -0,0 +1,31 @@ +// 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. + +#ifndef IPC_MESSAGE_MOJOM_TRAITS_H_ +#define IPC_MESSAGE_MOJOM_TRAITS_H_ + +#include <vector> + +#include "base/optional.h" +#include "ipc/ipc.mojom-shared.h" +#include "ipc/message_view.h" +#include "mojo/public/cpp/base/big_buffer.h" +#include "mojo/public/cpp/bindings/struct_traits.h" +#include "mojo/public/interfaces/bindings/native_struct.mojom.h" + +namespace mojo { + +template <> +class StructTraits<IPC::mojom::MessageDataView, IPC::MessageView> { + public: + static mojo_base::BigBufferView buffer(IPC::MessageView& view); + static base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles( + IPC::MessageView& view); + + static bool Read(IPC::mojom::MessageDataView data, IPC::MessageView* out); +}; + +} // namespace mojo + +#endif // IPC_MESSAGE_MOJOM_TRAITS_H_
diff --git a/ipc/message_view.cc b/ipc/message_view.cc new file mode 100644 index 0000000..d6ff4fb --- /dev/null +++ b/ipc/message_view.cc
@@ -0,0 +1,30 @@ +// 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. + +#include "ipc/message_view.h" + +namespace IPC { + +MessageView::MessageView() = default; + +MessageView::MessageView( + const Message& message, + base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles) + : buffer_view_(base::make_span<const uint8_t>( + static_cast<const uint8_t*>(message.data()), + message.size())), + handles_(std::move(handles)) {} + +MessageView::MessageView( + mojo_base::BigBufferView buffer_view, + base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles) + : buffer_view_(std::move(buffer_view)), handles_(std::move(handles)) {} + +MessageView::MessageView(MessageView&&) = default; + +MessageView::~MessageView() = default; + +MessageView& MessageView::operator=(MessageView&&) = default; + +} // namespace IPC
diff --git a/ipc/message_view.h b/ipc/message_view.h new file mode 100644 index 0000000..23e5da6 --- /dev/null +++ b/ipc/message_view.h
@@ -0,0 +1,56 @@ +// 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. + +#ifndef IPC_MESSAGE_VIEW_H_ +#define IPC_MESSAGE_VIEW_H_ + +#include <vector> + +#include "base/component_export.h" +#include "base/containers/span.h" +#include "base/macros.h" +#include "ipc/ipc_message.h" +#include "mojo/public/cpp/base/big_buffer.h" +#include "mojo/public/interfaces/bindings/native_struct.mojom.h" + +namespace IPC { + +class COMPONENT_EXPORT(IPC_MOJOM) MessageView { + public: + MessageView(); + MessageView( + const Message& message, + base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles); + MessageView( + mojo_base::BigBufferView buffer_view, + base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles); + MessageView(MessageView&&); + ~MessageView(); + + MessageView& operator=(MessageView&&); + + const char* data() const { + return reinterpret_cast<const char*>(buffer_view_.data().data()); + } + + uint32_t size() const { + return static_cast<uint32_t>(buffer_view_.data().size()); + } + + mojo_base::BigBufferView TakeBufferView() { return std::move(buffer_view_); } + + base::Optional<std::vector<mojo::native::SerializedHandlePtr>> TakeHandles() { + return std::move(handles_); + } + + private: + mojo_base::BigBufferView buffer_view_; + base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles_; + + DISALLOW_COPY_AND_ASSIGN(MessageView); +}; + +} // namespace IPC + +#endif // IPC_MESSAGE_VIEW_H_
diff --git a/ipc/typemaps.gni b/ipc/typemaps.gni new file mode 100644 index 0000000..7896dae6 --- /dev/null +++ b/ipc/typemaps.gni
@@ -0,0 +1,5 @@ +# 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. + +typemaps = [ "//ipc/message.typemap" ]
diff --git a/media/filters/frame_buffer_pool.cc b/media/filters/frame_buffer_pool.cc index 84c0997..1bcbc8df 100644 --- a/media/filters/frame_buffer_pool.cc +++ b/media/filters/frame_buffer_pool.cc
@@ -19,8 +19,12 @@ namespace media { struct FrameBufferPool::FrameBuffer { - std::vector<uint8_t> data; - std::vector<uint8_t> alpha_data; + // Not using std::vector<uint8_t> as resize() calls take a really long time + // for large buffers. + std::unique_ptr<uint8_t[]> data; + size_t data_size = 0u; + std::unique_ptr<uint8_t[]> alpha_data; + size_t alpha_data_size = 0u; bool held_by_library = false; // Needs to be a counter since a frame buffer might be used multiple times. int held_by_frame = 0; @@ -63,12 +67,17 @@ // Resize the frame buffer if necessary. frame_buffer->held_by_library = true; - if (frame_buffer->data.size() < min_size) - frame_buffer->data.resize(min_size); + if (frame_buffer->data_size < min_size) { + // Free the existing |data| first so that the memory can be reused, + // if possible. Note that the new array is purposely not initialized. + frame_buffer->data.reset(); + frame_buffer->data.reset(new uint8_t[min_size]); + frame_buffer->data_size = min_size; + } // Provide the client with a private identifier. *fb_priv = frame_buffer.get(); - return frame_buffer->data.data(); + return frame_buffer->data.get(); } void FrameBufferPool::ReleaseFrameBuffer(void* fb_priv) { @@ -89,9 +98,14 @@ auto* frame_buffer = static_cast<FrameBuffer*>(fb_priv); DCHECK(IsUsed(frame_buffer)); - if (frame_buffer->alpha_data.size() < min_size) - frame_buffer->alpha_data.resize(min_size); - return frame_buffer->alpha_data.data(); + if (frame_buffer->alpha_data_size < min_size) { + // Free the existing |alpha_data| first so that the memory can be reused, + // if possible. Note that the new array is purposely not initialized. + frame_buffer->alpha_data.reset(); + frame_buffer->alpha_data.reset(new uint8_t[min_size]); + frame_buffer->alpha_data_size = min_size; + } + return frame_buffer->alpha_data.get(); } base::Closure FrameBufferPool::CreateFrameCallback(void* fb_priv) { @@ -121,8 +135,8 @@ size_t bytes_reserved = 0; for (const auto& frame_buffer : frame_buffers_) { if (IsUsed(frame_buffer.get())) - bytes_used += frame_buffer->data.size(); - bytes_reserved += frame_buffer->data.size(); + bytes_used += frame_buffer->data_size + frame_buffer->alpha_data_size; + bytes_reserved += frame_buffer->data_size + frame_buffer->alpha_data_size; } memory_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
diff --git a/media/remoting/renderer_controller_unittest.cc b/media/remoting/renderer_controller_unittest.cc index a7336a33..2628b0d 100644 --- a/media/remoting/renderer_controller_unittest.cc +++ b/media/remoting/renderer_controller_unittest.cc
@@ -138,10 +138,7 @@ decoded_frames_ = frame_rate * kDelayedStartDuration.InSeconds(); clock_.Advance(kDelayedStartDuration); RunUntilIdle(); - const base::Closure callback = - controller_->delayed_start_stability_timer_.user_task(); - callback.Run(); - controller_->delayed_start_stability_timer_.Stop(); + controller_->delayed_start_stability_timer_.FireNow(); } void ExpectInDelayedStart() const {
diff --git a/mojo/core/channel_posix.cc b/mojo/core/channel_posix.cc index 9fa4a4f..dc7f3a2 100644 --- a/mojo/core/channel_posix.cc +++ b/mojo/core/channel_posix.cc
@@ -144,8 +144,19 @@ // must also have the ability to extract a send right from the ports that // are already attached. MachPortRelay* relay = Core::Get()->GetMachPortRelay(); - if (relay && remote_process().is_valid() && message->has_mach_ports()) + if (relay && remote_process().is_valid() && message->has_mach_ports()) { + if (relay->port_provider()->TaskForPid(remote_process().get()) == + MACH_PORT_NULL) { + // We also need to have a task port for the remote process before we can + // send it any other ports. If we don't have one yet, queue the message + // until OnProcessReady() is invoked. + base::AutoLock lock(task_port_wait_lock_); + pending_outgoing_with_mach_ports_.emplace_back(std::move(message)); + return; + } + relay->SendPortsToProcess(message.get(), remote_process().get()); + } #endif bool write_error = false;
diff --git a/mojo/core/core.cc b/mojo/core/core.cc index 2917a1d..fb00ca89 100644 --- a/mojo/core/core.cc +++ b/mojo/core/core.cc
@@ -315,7 +315,7 @@ MojoResult Core::CreateTrap(MojoTrapEventHandler handler, const MojoCreateTrapOptions* options, MojoHandle* trap_handle) { - if (options && options->struct_size != sizeof(*options)) + if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; @@ -333,7 +333,7 @@ MojoTriggerCondition condition, uintptr_t context, const MojoAddTriggerOptions* options) { - if (options && options->struct_size != sizeof(*options)) + if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; @@ -352,7 +352,7 @@ MojoResult Core::RemoveTrigger(MojoHandle trap_handle, uintptr_t context, const MojoRemoveTriggerOptions* options) { - if (options && options->struct_size != sizeof(*options)) + if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; @@ -364,26 +364,23 @@ MojoResult Core::ArmTrap(MojoHandle trap_handle, const MojoArmTrapOptions* options, - uint32_t* num_ready_triggers, - uintptr_t* ready_triggers, - MojoResult* ready_results, - MojoHandleSignalsState* ready_signals_states) { - if (options && options->struct_size != sizeof(*options)) + uint32_t* num_blocking_events, + MojoTrapEvent* blocking_events) { + if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle); if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER) return MOJO_RESULT_INVALID_ARGUMENT; - return watcher->Arm(num_ready_triggers, ready_triggers, ready_results, - ready_signals_states); + return watcher->Arm(num_blocking_events, blocking_events); } MojoResult Core::CreateMessage(const MojoCreateMessageOptions* options, MojoMessageHandle* message_handle) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; - if (options && options->struct_size != sizeof(*options)) + if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; *message_handle = reinterpret_cast<MojoMessageHandle>( UserMessageImpl::CreateEventForNewMessage().release()); @@ -403,7 +400,7 @@ const MojoSerializeMessageOptions* options) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; - if (options && options->struct_size != sizeof(*options)) + if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; return reinterpret_cast<ports::UserMessageEvent*>(message_handle) @@ -420,7 +417,7 @@ uint32_t* buffer_size) { if (!message_handle || (num_handles && !handles)) return MOJO_RESULT_INVALID_ARGUMENT; - if (options && options->struct_size != sizeof(*options)) + if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; RequestContext request_context; @@ -453,7 +450,7 @@ uint32_t* num_handles) { if (!message_handle || (num_handles && *num_handles && !handles)) return MOJO_RESULT_INVALID_ARGUMENT; - if (options && options->struct_size != sizeof(*options)) + if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) @@ -502,7 +499,7 @@ const MojoSetMessageContextOptions* options) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; - if (options && options->struct_size != sizeof(*options)) + if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) ->GetMessage<UserMessageImpl>(); @@ -514,7 +511,7 @@ uintptr_t* context) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; - if (options && options->struct_size != sizeof(*options)) + if (options && options->struct_size < sizeof(*options)) return MOJO_RESULT_INVALID_ARGUMENT; auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) @@ -658,7 +655,7 @@ MojoHandle* data_pipe_producer_handle, MojoHandle* data_pipe_consumer_handle) { RequestContext request_context; - if (options && options->struct_size != sizeof(MojoCreateDataPipeOptions)) + if (options && options->struct_size < sizeof(MojoCreateDataPipeOptions)) return MOJO_RESULT_INVALID_ARGUMENT; MojoCreateDataPipeOptions create_options;
diff --git a/mojo/core/core.h b/mojo/core/core.h index 6069ff5..e03a662 100644 --- a/mojo/core/core.h +++ b/mojo/core/core.h
@@ -182,10 +182,8 @@ const MojoRemoveTriggerOptions* options); MojoResult ArmTrap(MojoHandle trap_handle, const MojoArmTrapOptions* options, - uint32_t* num_ready_triggers, - uintptr_t* ready_triggers, - MojoResult* ready_results, - MojoHandleSignalsState* ready_signals_states); + uint32_t* num_blocking_events, + MojoTrapEvent* blocking_events); MojoResult CreateMessage(const MojoCreateMessageOptions* options, MojoMessageHandle* message_handle); MojoResult DestroyMessage(MojoMessageHandle message_handle);
diff --git a/mojo/core/dispatcher.cc b/mojo/core/dispatcher.cc index 49cfe18..4f173bd 100644 --- a/mojo/core/dispatcher.cc +++ b/mojo/core/dispatcher.cc
@@ -34,10 +34,8 @@ return MOJO_RESULT_INVALID_ARGUMENT; } -MojoResult Dispatcher::Arm(uint32_t* num_ready_contexts, - uintptr_t* ready_contexts, - MojoResult* ready_results, - MojoHandleSignalsState* ready_signals_states) { +MojoResult Dispatcher::Arm(uint32_t* num_blocking_events, + MojoTrapEvent* blocking_events) { return MOJO_RESULT_INVALID_ARGUMENT; }
diff --git a/mojo/core/dispatcher.h b/mojo/core/dispatcher.h index 6402f3e..1ef7efe 100644 --- a/mojo/core/dispatcher.h +++ b/mojo/core/dispatcher.h
@@ -79,10 +79,8 @@ MojoTriggerCondition condition, uintptr_t context); virtual MojoResult CancelWatch(uintptr_t context); - virtual MojoResult Arm(uint32_t* num_ready_contexts, - uintptr_t* ready_contexts, - MojoResult* ready_results, - MojoHandleSignalsState* ready_signals_states); + virtual MojoResult Arm(uint32_t* num_blocking_events, + MojoTrapEvent* blocking_events); ///////////// Message pipe API /////////////
diff --git a/mojo/core/entrypoints.cc b/mojo/core/entrypoints.cc index 2e67a680..c9d1d8a 100644 --- a/mojo/core/entrypoints.cc +++ b/mojo/core/entrypoints.cc
@@ -237,12 +237,10 @@ MojoResult MojoArmTrapImpl(MojoHandle trap_handle, const MojoArmTrapOptions* options, - uint32_t* num_ready_triggers, - uintptr_t* ready_triggers, - MojoResult* ready_results, - MojoHandleSignalsState* ready_signals_states) { - return g_core->ArmTrap(trap_handle, options, num_ready_triggers, - ready_triggers, ready_results, ready_signals_states); + uint32_t* num_blocking_events, + MojoTrapEvent* blocking_events) { + return g_core->ArmTrap(trap_handle, options, num_blocking_events, + blocking_events); } MojoResult MojoWrapPlatformHandleImpl(
diff --git a/mojo/core/trap_unittest.cc b/mojo/core/trap_unittest.cc index 376de62..555726f4 100644 --- a/mojo/core/trap_unittest.cc +++ b/mojo/core/trap_unittest.cc
@@ -14,6 +14,7 @@ #include "base/memory/ptr_util.h" #include "base/rand_util.h" #include "base/synchronization/waitable_event.h" +#include "base/test/bind_test_util.h" #include "base/threading/platform_thread.h" #include "base/threading/simple_thread.h" #include "base/time/time.h" @@ -27,61 +28,35 @@ namespace core { namespace { -// TODO(https://crbug.com/819046): These are temporary wrappers to reduce -// changes necessary during the API rename. Remove them. +using TrapTest = test::MojoTestBase; -MojoResult MojoWatch(MojoHandle trap_handle, - MojoHandle handle, - MojoHandleSignals signals, - MojoTriggerCondition condition, - uintptr_t context) { - return MojoAddTrigger(trap_handle, handle, signals, condition, context, - nullptr); -} - -MojoResult MojoCancelWatch(MojoHandle trap_handle, uintptr_t context) { - return MojoRemoveTrigger(trap_handle, context, nullptr); -} - -MojoResult MojoArmWatcher(MojoHandle trap_handle, - uint32_t* num_ready_contexts, - uintptr_t* ready_contexts, - MojoResult* ready_results, - MojoHandleSignalsState* ready_signals) { - return MojoArmTrap(trap_handle, nullptr, num_ready_contexts, ready_contexts, - ready_results, ready_signals); -} - -using WatcherTest = test::MojoTestBase; - -class WatchHelper { +class TriggerHelper { public: - using ContextCallback = - base::Callback<void(MojoResult, MojoHandleSignalsState)>; + using ContextCallback = base::RepeatingCallback<void(const MojoTrapEvent&)>; - WatchHelper() {} - ~WatchHelper() {} + TriggerHelper() {} + ~TriggerHelper() {} - MojoResult CreateWatcher(MojoHandle* handle) { + MojoResult CreateTrap(MojoHandle* handle) { return MojoCreateTrap(&Notify, nullptr, handle); } - uintptr_t CreateContext(const ContextCallback& callback) { - return CreateContextWithCancel(callback, base::Closure()); + template <typename Handler> + uintptr_t CreateContext(Handler handler) { + return CreateContextWithCancel(handler, [] {}); } - uintptr_t CreateContextWithCancel(const ContextCallback& callback, - const base::Closure& cancel_callback) { - auto context = std::make_unique<NotificationContext>(callback); - NotificationContext* raw_context = context.get(); - raw_context->SetCancelCallback(base::Bind( - [](std::unique_ptr<NotificationContext> context, - const base::Closure& cancel_callback) { - if (cancel_callback) - cancel_callback.Run(); - }, - base::Passed(&context), cancel_callback)); - return reinterpret_cast<uintptr_t>(raw_context); + template <typename Handler, typename CancelHandler> + uintptr_t CreateContextWithCancel(Handler handler, + CancelHandler cancel_handler) { + auto* context = + new NotificationContext(base::BindLambdaForTesting(handler)); + context->SetCancelCallback( + base::BindOnce(base::BindLambdaForTesting([cancel_handler, context] { + cancel_handler(); + delete context; + }))); + return reinterpret_cast<uintptr_t>(context); } private: @@ -92,42 +67,42 @@ ~NotificationContext() {} - void SetCancelCallback(const base::Closure& cancel_callback) { - cancel_callback_ = cancel_callback; + void SetCancelCallback(base::OnceClosure cancel_callback) { + cancel_callback_ = std::move(cancel_callback); } - void Notify(MojoResult result, MojoHandleSignalsState state) { - if (result == MOJO_RESULT_CANCELLED) - cancel_callback_.Run(); + void Notify(const MojoTrapEvent& event) { + if (event.result == MOJO_RESULT_CANCELLED && cancel_callback_) + std::move(cancel_callback_).Run(); else - callback_.Run(result, state); + callback_.Run(event); } private: const ContextCallback callback_; - base::Closure cancel_callback_; + base::OnceClosure cancel_callback_; DISALLOW_COPY_AND_ASSIGN(NotificationContext); }; static void Notify(const MojoTrapEvent* event) { reinterpret_cast<NotificationContext*>(event->trigger_context) - ->Notify(event->result, event->signals_state); + ->Notify(*event); } - DISALLOW_COPY_AND_ASSIGN(WatchHelper); + DISALLOW_COPY_AND_ASSIGN(TriggerHelper); }; class ThreadedRunner : public base::SimpleThread { public: - explicit ThreadedRunner(const base::Closure& callback) - : SimpleThread("ThreadedRunner"), callback_(callback) {} + explicit ThreadedRunner(base::OnceClosure callback) + : SimpleThread("ThreadedRunner"), callback_(std::move(callback)) {} ~ThreadedRunner() override {} - void Run() override { callback_.Run(); } + void Run() override { std::move(callback_).Run(); } private: - const base::Closure callback_; + base::OnceClosure callback_; DISALLOW_COPY_AND_ASSIGN(ThreadedRunner); }; @@ -140,76 +115,66 @@ EXPECT_EQ(event->result, MOJO_RESULT_CANCELLED); } -TEST_F(WatcherTest, InvalidArguments) { +TEST_F(TrapTest, InvalidArguments) { EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCreateTrap(&ExpectNoNotification, nullptr, nullptr)); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectNoNotification, nullptr, &w)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectNoNotification, nullptr, &t)); - // Try to watch unwatchable handles. - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoWatch(w, w, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, 0)); - MojoHandle buffer_handle = CreateBuffer(42); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoWatch(w, buffer_handle, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, 0)); - - // Try to cancel a watch on an invalid watcher handle. - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(buffer_handle, 0)); - - // Try to arm an invalid handle. + // Try to add triggers for handles which don't raise trappable signals. EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, - MojoArmWatcher(MOJO_HANDLE_INVALID, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, t, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr)); + MojoHandle buffer_handle = CreateBuffer(42); + EXPECT_EQ( + MOJO_RESULT_INVALID_ARGUMENT, + MojoAddTrigger(t, buffer_handle, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr)); + + // Try to remove a trigger on a non-trap handle. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoArmWatcher(buffer_handle, nullptr, nullptr, nullptr, nullptr)); + MojoRemoveTrigger(buffer_handle, 0, nullptr)); + + // Try to arm an invalid or non-trap handle. + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoArmTrap(MOJO_HANDLE_INVALID, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoArmTrap(buffer_handle, nullptr, nullptr, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(buffer_handle)); - // Try to arm with a non-null count but at least one null output buffer. - uint32_t num_ready_contexts = 1; - uintptr_t ready_context; - MojoResult ready_result; - MojoHandleSignalsState ready_state; + // Try to arm with a non-null count but a null output buffer. + uint32_t num_blocking_events = 1; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoArmWatcher(w, &num_ready_contexts, nullptr, &ready_result, - &ready_state)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoArmWatcher(w, &num_ready_contexts, &ready_context, nullptr, - &ready_state)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoArmWatcher(w, &num_ready_contexts, &ready_context, - &ready_result, nullptr)); + MojoArmTrap(t, nullptr, &num_blocking_events, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); } -TEST_F(WatcherTest, WatchMessagePipeReadable) { +TEST_F(TrapTest, TrapMessagePipeReadable) { MojoHandle a, b; CreateMessagePipe(&a, &b); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; int num_expected_notifications = 1; - const uintptr_t readable_a_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, int* expected_count, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_GT(*expected_count, 0); - *expected_count -= 1; + const uintptr_t readable_a_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_GT(num_expected_notifications, 0); + num_expected_notifications -= 1; - EXPECT_EQ(MOJO_RESULT_OK, result); - event->Signal(); - }, - &event, &num_expected_notifications)); + EXPECT_EQ(MOJO_RESULT_OK, event.result); + wait.Signal(); + }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); const char kMessage1[] = "hey hey hey hey"; const char kMessage2[] = "i said hey"; @@ -218,140 +183,135 @@ // Writing to |b| multiple times should notify exactly once. WriteMessage(b, kMessage1); WriteMessage(b, kMessage2); - event.Wait(); + wait.Wait(); - // This also shouldn't fire a notification; the watcher is still disarmed. + // This also shouldn't fire a notification; the trap is still disarmed. WriteMessage(b, kMessage3); // Arming should fail with relevant information. - constexpr size_t kMaxReadyContexts = 10; - uint32_t num_ready_contexts = kMaxReadyContexts; - uintptr_t ready_contexts[kMaxReadyContexts]; - MojoResult ready_results[kMaxReadyContexts]; - MojoHandleSignalsState ready_states[kMaxReadyContexts]; + constexpr size_t kMaxBlockingEvents = 3; + uint32_t num_blocking_events = kMaxBlockingEvents; + MojoTrapEvent blocking_events[kMaxBlockingEvents] = { + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(readable_a_context, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(readable_a_context, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result); // Flush the three messages from above. EXPECT_EQ(kMessage1, ReadMessage(a)); EXPECT_EQ(kMessage2, ReadMessage(a)); EXPECT_EQ(kMessage3, ReadMessage(a)); - // Now we can rearm the watcher. - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + // Now we can rearm the trap. + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); } -TEST_F(WatcherTest, CloseWatchedMessagePipeHandle) { +TEST_F(TrapTest, CloseWatchedMessagePipeHandle) { MojoHandle a, b; CreateMessagePipe(&a, &b); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; const uintptr_t readable_a_context = helper.CreateContextWithCancel( - WatchHelper::ContextCallback(), - base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event)); + [](const MojoTrapEvent&) {}, [&] { wait.Signal(); }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); // Test that closing a watched handle fires an appropriate notification, even - // when the watcher is unarmed. + // when the trap is unarmed. EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); - event.Wait(); + wait.Wait(); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); } -TEST_F(WatcherTest, CloseWatchedMessagePipeHandlePeer) { +TEST_F(TrapTest, CloseWatchedMessagePipeHandlePeer) { MojoHandle a, b; CreateMessagePipe(&a, &b); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; - const uintptr_t readable_a_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); - event->Signal(); - }, - &event)); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; + const uintptr_t readable_a_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, event.result); + wait.Signal(); + }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); - // Test that closing a watched handle's peer with an armed watcher fires an + // Test that closing a watched handle's peer with an armed trap fires an // appropriate notification. - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); - event.Wait(); + wait.Wait(); // And now arming should fail with correct information about |a|'s state. - constexpr size_t kMaxReadyContexts = 10; - uint32_t num_ready_contexts = kMaxReadyContexts; - uintptr_t ready_contexts[kMaxReadyContexts]; - MojoResult ready_results[kMaxReadyContexts]; - MojoHandleSignalsState ready_states[kMaxReadyContexts]; + constexpr size_t kMaxBlockingEvents = 3; + uint32_t num_blocking_events = kMaxBlockingEvents; + MojoTrapEvent blocking_events[kMaxBlockingEvents] = { + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(readable_a_context, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]); - EXPECT_TRUE(ready_states[0].satisfied_signals & + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(readable_a_context, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, blocking_events[0].result); + EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED); - EXPECT_FALSE(ready_states[0].satisfiable_signals & + EXPECT_FALSE(blocking_events[0].signals_state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); } -TEST_F(WatcherTest, WatchDataPipeConsumerReadable) { +TEST_F(TrapTest, TrapDataPipeConsumerReadable) { constexpr size_t kTestPipeCapacity = 64; MojoHandle producer, consumer; CreateDataPipe(&producer, &consumer, kTestPipeCapacity); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; int num_expected_notifications = 1; - const uintptr_t readable_consumer_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, int* expected_count, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_GT(*expected_count, 0); - *expected_count -= 1; + const uintptr_t readable_consumer_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_GT(num_expected_notifications, 0); + num_expected_notifications -= 1; - EXPECT_EQ(MOJO_RESULT_OK, result); - event->Signal(); - }, - &event, &num_expected_notifications)); + EXPECT_EQ(MOJO_RESULT_OK, event.result); + wait.Signal(); + }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, - readable_consumer_context)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, consumer, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_consumer_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); const char kMessage1[] = "hey hey hey hey"; const char kMessage2[] = "i said hey"; @@ -360,64 +320,61 @@ // Writing to |producer| multiple times should notify exactly once. WriteData(producer, kMessage1); WriteData(producer, kMessage2); - event.Wait(); + wait.Wait(); - // This also shouldn't fire a notification; the watcher is still disarmed. + // This also shouldn't fire a notification; the trap is still disarmed. WriteData(producer, kMessage3); // Arming should fail with relevant information. - constexpr size_t kMaxReadyContexts = 10; - uint32_t num_ready_contexts = kMaxReadyContexts; - uintptr_t ready_contexts[kMaxReadyContexts]; - MojoResult ready_results[kMaxReadyContexts]; - MojoHandleSignalsState ready_states[kMaxReadyContexts]; + constexpr size_t kMaxBlockingEvents = 3; + uint32_t num_blocking_events = kMaxBlockingEvents; + MojoTrapEvent blocking_events[kMaxBlockingEvents] = { + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(readable_consumer_context, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(readable_consumer_context, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result); // Flush the three messages from above. EXPECT_EQ(kMessage1, ReadData(consumer, sizeof(kMessage1) - 1)); EXPECT_EQ(kMessage2, ReadData(consumer, sizeof(kMessage2) - 1)); EXPECT_EQ(kMessage3, ReadData(consumer, sizeof(kMessage3) - 1)); - // Now we can rearm the watcher. - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + // Now we can rearm the trap. + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); } -TEST_F(WatcherTest, WatchDataPipeConsumerNewDataReadable) { +TEST_F(TrapTest, TrapDataPipeConsumerNewDataReadable) { constexpr size_t kTestPipeCapacity = 64; MojoHandle producer, consumer; CreateDataPipe(&producer, &consumer, kTestPipeCapacity); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; int num_new_data_notifications = 0; - const uintptr_t new_data_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, int* notification_count, MojoResult result, - MojoHandleSignalsState state) { - *notification_count += 1; + const uintptr_t new_data_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + num_new_data_notifications += 1; - EXPECT_EQ(MOJO_RESULT_OK, result); - event->Signal(); - }, - &event, &num_new_data_notifications)); + EXPECT_EQ(MOJO_RESULT_OK, event.result); + wait.Signal(); + }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, new_data_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, consumer, MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + new_data_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); const char kMessage1[] = "hey hey hey hey"; const char kMessage2[] = "i said hey"; @@ -426,23 +383,23 @@ // Writing to |producer| multiple times should notify exactly once. WriteData(producer, kMessage1); WriteData(producer, kMessage2); - event.Wait(); + wait.Wait(); - // This also shouldn't fire a notification; the watcher is still disarmed. + // This also shouldn't fire a notification; the trap is still disarmed. WriteData(producer, kMessage3); // Arming should fail with relevant information. - constexpr size_t kMaxReadyContexts = 10; - uint32_t num_ready_contexts = kMaxReadyContexts; - uintptr_t ready_contexts[kMaxReadyContexts]; - MojoResult ready_results[kMaxReadyContexts]; - MojoHandleSignalsState ready_states[kMaxReadyContexts]; + constexpr size_t kMaxBlockingEvents = 3; + uint32_t num_blocking_events = kMaxBlockingEvents; + MojoTrapEvent blocking_events[kMaxBlockingEvents] = { + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(new_data_context, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(new_data_context, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result); // Attempt to read more data than is available. Should fail but clear the // NEW_DATA_READABLE signal. @@ -455,28 +412,26 @@ MojoReadData(consumer, &options, large_buffer, &large_read_size)); // Attempt to arm again. Should succeed. - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); // Write more data. Should notify. - event.Reset(); + wait.Reset(); WriteData(producer, kMessage1); - event.Wait(); + wait.Wait(); // Reading some data should clear NEW_DATA_READABLE again so we can rearm. EXPECT_EQ(kMessage1, ReadData(consumer, sizeof(kMessage1) - 1)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); EXPECT_EQ(2, num_new_data_notifications); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); } -TEST_F(WatcherTest, WatchDataPipeProducerWritable) { +TEST_F(TrapTest, TrapDataPipeProducerWritable) { constexpr size_t kTestPipeCapacity = 8; MojoHandle producer, consumer; CreateDataPipe(&producer, &consumer, kTestPipeCapacity); @@ -486,180 +441,177 @@ static_assert((sizeof(kTestData) - 1) * 2 == kTestPipeCapacity, "Invalid test data for this test."); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; int num_expected_notifications = 1; - const uintptr_t writable_producer_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, int* expected_count, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_GT(*expected_count, 0); - *expected_count -= 1; + const uintptr_t writable_producer_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_GT(num_expected_notifications, 0); + num_expected_notifications -= 1; - EXPECT_EQ(MOJO_RESULT_OK, result); - event->Signal(); - }, - &event, &num_expected_notifications)); + EXPECT_EQ(MOJO_RESULT_OK, event.result); + wait.Signal(); + }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE, - MOJO_WATCH_CONDITION_SATISFIED, - writable_producer_context)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoAddTrigger(t, producer, MOJO_HANDLE_SIGNAL_WRITABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + writable_producer_context, nullptr)); // The producer is already writable, so arming should fail with relevant // information. - constexpr size_t kMaxReadyContexts = 10; - uint32_t num_ready_contexts = kMaxReadyContexts; - uintptr_t ready_contexts[kMaxReadyContexts]; - MojoResult ready_results[kMaxReadyContexts]; - MojoHandleSignalsState ready_states[kMaxReadyContexts]; + constexpr size_t kMaxBlockingEvents = 3; + uint32_t num_blocking_events = kMaxBlockingEvents; + MojoTrapEvent blocking_events[kMaxBlockingEvents] = { + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(writable_producer_context, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); - EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(writable_producer_context, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result); + EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals & + MOJO_HANDLE_SIGNAL_WRITABLE); // Write some data, but don't fill the pipe yet. Arming should fail again. WriteData(producer, kTestData); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(writable_producer_context, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); - EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(writable_producer_context, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result); + EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals & + MOJO_HANDLE_SIGNAL_WRITABLE); // Write more data, filling the pipe to capacity. Arming should succeed now. WriteData(producer, kTestData); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); // Now read from the pipe, making the producer writable again. Should notify. EXPECT_EQ(kTestData, ReadData(consumer, sizeof(kTestData) - 1)); - event.Wait(); + wait.Wait(); // Arming should fail again. EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(writable_producer_context, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); - EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(writable_producer_context, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result); + EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals & + MOJO_HANDLE_SIGNAL_WRITABLE); - // Fill the pipe once more and arm the watcher. Should succeed. + // Fill the pipe once more and arm the trap. Should succeed. WriteData(producer, kTestData); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); }; -TEST_F(WatcherTest, CloseWatchedDataPipeConsumerHandle) { +TEST_F(TrapTest, CloseWatchedDataPipeConsumerHandle) { constexpr size_t kTestPipeCapacity = 8; MojoHandle producer, consumer; CreateDataPipe(&producer, &consumer, kTestPipeCapacity); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; const uintptr_t readable_consumer_context = helper.CreateContextWithCancel( - WatchHelper::ContextCallback(), - base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event)); + [](const MojoTrapEvent&) {}, [&] { wait.Signal(); }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, - readable_consumer_context)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoAddTrigger(t, consumer, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_consumer_context, nullptr)); // Closing the consumer should fire a cancellation notification. EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); - event.Wait(); + wait.Wait(); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); } -TEST_F(WatcherTest, CloseWatcherDataPipeConsumerHandlePeer) { +TEST_F(TrapTest, CloseWatchedDataPipeConsumerHandlePeer) { constexpr size_t kTestPipeCapacity = 8; MojoHandle producer, consumer; CreateDataPipe(&producer, &consumer, kTestPipeCapacity); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; - const uintptr_t readable_consumer_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); - event->Signal(); - }, - &event)); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; + const uintptr_t readable_consumer_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, event.result); + wait.Signal(); + }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, - readable_consumer_context)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, consumer, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_consumer_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - // Closing the producer should fire a notification for an unsatisfiable watch. + // Closing the producer should fire a notification for an unsatisfiable + // condition. EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); - event.Wait(); + wait.Wait(); // Now attempt to rearm and expect appropriate error feedback. - constexpr size_t kMaxReadyContexts = 10; - uint32_t num_ready_contexts = kMaxReadyContexts; - uintptr_t ready_contexts[kMaxReadyContexts]; - MojoResult ready_results[kMaxReadyContexts]; - MojoHandleSignalsState ready_states[kMaxReadyContexts]; + constexpr size_t kMaxBlockingEvents = 3; + uint32_t num_blocking_events = kMaxBlockingEvents; + MojoTrapEvent blocking_events[kMaxBlockingEvents] = { + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(readable_consumer_context, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]); - EXPECT_FALSE(ready_states[0].satisfiable_signals & + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(readable_consumer_context, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, blocking_events[0].result); + EXPECT_FALSE(blocking_events[0].signals_state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); } -TEST_F(WatcherTest, CloseWatchedDataPipeProducerHandle) { +TEST_F(TrapTest, CloseWatchedDataPipeProducerHandle) { constexpr size_t kTestPipeCapacity = 8; MojoHandle producer, consumer; CreateDataPipe(&producer, &consumer, kTestPipeCapacity); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; const uintptr_t writable_producer_context = helper.CreateContextWithCancel( - WatchHelper::ContextCallback(), - base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event)); + [](const MojoTrapEvent&) {}, [&] { wait.Signal(); }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE, - MOJO_WATCH_CONDITION_SATISFIED, - writable_producer_context)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoAddTrigger(t, producer, MOJO_HANDLE_SIGNAL_WRITABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + writable_producer_context, nullptr)); // Closing the consumer should fire a cancellation notification. EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); - event.Wait(); + wait.Wait(); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); } -TEST_F(WatcherTest, CloseWatchedDataPipeProducerHandlePeer) { +TEST_F(TrapTest, CloseWatchedDataPipeProducerHandlePeer) { constexpr size_t kTestPipeCapacity = 8; MojoHandle producer, consumer; CreateDataPipe(&producer, &consumer, kTestPipeCapacity); @@ -671,177 +623,184 @@ // Make the pipe unwritable initially. WriteData(producer, kTestMessageFullCapacity); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; - const uintptr_t writable_producer_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); - event->Signal(); - }, - &event)); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; + const uintptr_t writable_producer_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, event.result); + wait.Signal(); + }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE, - MOJO_WATCH_CONDITION_SATISFIED, - writable_producer_context)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, producer, MOJO_HANDLE_SIGNAL_WRITABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + writable_producer_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - // Closing the consumer should fire a notification for an unsatisfiable watch, - // as the full data pipe can never be read from again and is therefore - // permanently full and unwritable. + // Closing the consumer should fire a notification for an unsatisfiable + // condition, as the full data pipe can never be read from again and is + // therefore permanently full and unwritable. EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer)); - event.Wait(); + wait.Wait(); // Now attempt to rearm and expect appropriate error feedback. - constexpr size_t kMaxReadyContexts = 10; - uint32_t num_ready_contexts = kMaxReadyContexts; - uintptr_t ready_contexts[kMaxReadyContexts]; - MojoResult ready_results[kMaxReadyContexts]; - MojoHandleSignalsState ready_states[kMaxReadyContexts]; + constexpr size_t kMaxBlockingEvents = 3; + uint32_t num_blocking_events = kMaxBlockingEvents; + MojoTrapEvent blocking_events[kMaxBlockingEvents] = { + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(writable_producer_context, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]); - EXPECT_FALSE(ready_states[0].satisfiable_signals & + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(writable_producer_context, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, blocking_events[0].result); + EXPECT_FALSE(blocking_events[0].signals_state.satisfiable_signals & MOJO_HANDLE_SIGNAL_WRITABLE); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer)); } -TEST_F(WatcherTest, ArmWithNoWatches) { - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectNoNotification, nullptr, &w)); - EXPECT_EQ(MOJO_RESULT_NOT_FOUND, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); +TEST_F(TrapTest, ArmWithNoTriggers) { + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectNoNotification, nullptr, &t)); + EXPECT_EQ(MOJO_RESULT_NOT_FOUND, MojoArmTrap(t, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); } -TEST_F(WatcherTest, WatchDuplicateContext) { +TEST_F(TrapTest, DuplicateTriggerContext) { MojoHandle a, b; CreateMessagePipe(&a, &b); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &w)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, 0)); - EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, 0)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &t)); + EXPECT_EQ( + MOJO_RESULT_OK, + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr)); + EXPECT_EQ( + MOJO_RESULT_ALREADY_EXISTS, + MojoAddTrigger(t, b, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); } -TEST_F(WatcherTest, CancelUnknownWatch) { - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectNoNotification, nullptr, &w)); - EXPECT_EQ(MOJO_RESULT_NOT_FOUND, MojoCancelWatch(w, 1234)); +TEST_F(TrapTest, RemoveUnknownTrigger) { + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectNoNotification, nullptr, &t)); + EXPECT_EQ(MOJO_RESULT_NOT_FOUND, MojoRemoveTrigger(t, 1234, nullptr)); } -TEST_F(WatcherTest, ArmWithWatchAlreadySatisfied) { +TEST_F(TrapTest, ArmWithTriggerConditionAlreadySatisfied) { MojoHandle a, b; CreateMessagePipe(&a, &b); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &w)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_WRITABLE, - MOJO_WATCH_CONDITION_SATISFIED, 0)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &t)); + EXPECT_EQ( + MOJO_RESULT_OK, + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_WRITABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr)); - // |a| is always writable, so we can never arm this watcher. - constexpr size_t kMaxReadyContexts = 10; - uint32_t num_ready_contexts = kMaxReadyContexts; - uintptr_t ready_contexts[kMaxReadyContexts]; - MojoResult ready_results[kMaxReadyContexts]; - MojoHandleSignalsState ready_states[kMaxReadyContexts]; + // |a| is always writable, so we can never arm this trap. + constexpr size_t kMaxBlockingEvents = 3; + uint32_t num_blocking_events = kMaxBlockingEvents; + MojoTrapEvent blocking_events[kMaxBlockingEvents] = { + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(0u, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); - EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(0u, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result); + EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals & + MOJO_HANDLE_SIGNAL_WRITABLE); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); } -TEST_F(WatcherTest, ArmWithWatchAlreadyUnsatisfiable) { +TEST_F(TrapTest, ArmWithTriggerConditionAlreadyUnsatisfiable) { MojoHandle a, b; CreateMessagePipe(&a, &b); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &w)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, 0)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &t)); + EXPECT_EQ( + MOJO_RESULT_OK, + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, 0, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); // |b| is closed and never wrote any messages, so |a| won't be readable again. - // MojoArmWatcher() should fail, incidcating as much. - constexpr size_t kMaxReadyContexts = 10; - uint32_t num_ready_contexts = kMaxReadyContexts; - uintptr_t ready_contexts[kMaxReadyContexts]; - MojoResult ready_results[kMaxReadyContexts]; - MojoHandleSignalsState ready_states[kMaxReadyContexts]; + // MojoArmTrap() should fail, incidcating as much. + constexpr size_t kMaxBlockingEvents = 3; + uint32_t num_blocking_events = kMaxBlockingEvents; + MojoTrapEvent blocking_events[kMaxBlockingEvents] = { + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(0u, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]); - EXPECT_TRUE(ready_states[0].satisfied_signals & + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(0u, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, blocking_events[0].result); + EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED); - EXPECT_FALSE(ready_states[0].satisfiable_signals & + EXPECT_FALSE(blocking_events[0].signals_state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); } -TEST_F(WatcherTest, MultipleWatches) { +TEST_F(TrapTest, MultipleTriggers) { MojoHandle a, b; CreateMessagePipe(&a, &b); - base::WaitableEvent a_event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - base::WaitableEvent b_event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; + base::WaitableEvent a_wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent b_wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; int num_a_notifications = 0; int num_b_notifications = 0; - auto notify_callback = - base::Bind([](base::WaitableEvent* event, int* notification_count, - MojoResult result, MojoHandleSignalsState state) { - *notification_count += 1; - EXPECT_EQ(MOJO_RESULT_OK, result); - event->Signal(); + uintptr_t readable_a_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + num_a_notifications += 1; + EXPECT_EQ(MOJO_RESULT_OK, event.result); + a_wait.Signal(); }); - uintptr_t readable_a_context = helper.CreateContext( - base::Bind(notify_callback, &a_event, &num_a_notifications)); - uintptr_t readable_b_context = helper.CreateContext( - base::Bind(notify_callback, &b_event, &num_b_notifications)); + uintptr_t readable_b_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + num_b_notifications += 1; + EXPECT_EQ(MOJO_RESULT_OK, event.result); + b_wait.Signal(); + }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); - // Add two independent watch contexts to watch for |a| or |b| readability. + // Add two independent triggers to trap |a| or |b| readability. EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_b_context)); + MojoAddTrigger(t, b, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_b_context, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); const char kMessage1[] = "things are happening"; const char kMessage2[] = "ok. ok. ok. ok."; @@ -849,49 +808,51 @@ // Writing to |b| should signal |a|'s watch. WriteMessage(b, kMessage1); - a_event.Wait(); - a_event.Reset(); + a_wait.Wait(); + a_wait.Reset(); // Subsequent messages on |b| should not trigger another notification. WriteMessage(b, kMessage2); WriteMessage(b, kMessage3); // Messages on |a| also shouldn't trigger |b|'s notification, since the - // watcher should be disarmed by now. + // trap should be disarmed by now. WriteMessage(a, kMessage1); WriteMessage(a, kMessage2); WriteMessage(a, kMessage3); // Arming should fail. Since we only ask for at most one context's information // that's all we should get back. Which one we get is unspecified. - constexpr size_t kMaxReadyContexts = 10; - uint32_t num_ready_contexts = 1; - uintptr_t ready_contexts[kMaxReadyContexts]; - MojoResult ready_results[kMaxReadyContexts]; - MojoHandleSignalsState ready_states[kMaxReadyContexts]; + constexpr size_t kMaxBlockingEvents = 3; + uint32_t num_blocking_events = 1; + MojoTrapEvent blocking_events[kMaxBlockingEvents] = { + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}, + {sizeof(blocking_events[0])}}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_TRUE(ready_contexts[0] == readable_a_context || - ready_contexts[0] == readable_b_context); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); - EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_TRUE(blocking_events[0].trigger_context == readable_a_context || + blocking_events[0].trigger_context == readable_b_context); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result); + EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals & + MOJO_HANDLE_SIGNAL_WRITABLE); // Now try arming again, verifying that both contexts are returned. - num_ready_contexts = kMaxReadyContexts; + num_blocking_events = kMaxBlockingEvents; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(2u, num_ready_contexts); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[1]); - EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); - EXPECT_TRUE(ready_states[1].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); - EXPECT_TRUE((ready_contexts[0] == readable_a_context && - ready_contexts[1] == readable_b_context) || - (ready_contexts[0] == readable_b_context && - ready_contexts[1] == readable_a_context)); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(2u, num_blocking_events); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[1].result); + EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals & + MOJO_HANDLE_SIGNAL_WRITABLE); + EXPECT_TRUE(blocking_events[1].signals_state.satisfied_signals & + MOJO_HANDLE_SIGNAL_WRITABLE); + EXPECT_TRUE((blocking_events[0].trigger_context == readable_a_context && + blocking_events[1].trigger_context == readable_b_context) || + (blocking_events[0].trigger_context == readable_b_context && + blocking_events[1].trigger_context == readable_a_context)); // Flush out the test messages so we should be able to successfully rearm. EXPECT_EQ(kMessage1, ReadMessage(a)); @@ -901,140 +862,131 @@ EXPECT_EQ(kMessage2, ReadMessage(b)); EXPECT_EQ(kMessage3, ReadMessage(b)); - // Add a watch which is always satisfied, so we can't arm. Arming should fail - // with only this new watch's information. - uintptr_t writable_c_context = helper.CreateContext(base::Bind( - [](MojoResult result, MojoHandleSignalsState state) { NOTREACHED(); })); + // Add a trigger whose condition is always satisfied so we can't arm. Arming + // should fail with only this new watch's information. + uintptr_t writable_c_context = + helper.CreateContext([](const MojoTrapEvent&) { NOTREACHED(); }); MojoHandle c, d; CreateMessagePipe(&c, &d); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, c, MOJO_HANDLE_SIGNAL_WRITABLE, - MOJO_WATCH_CONDITION_SATISFIED, writable_c_context)); - num_ready_contexts = kMaxReadyContexts; + MojoAddTrigger(t, c, MOJO_HANDLE_SIGNAL_WRITABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + writable_c_context, nullptr)); + num_blocking_events = kMaxBlockingEvents; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, ready_contexts, - ready_results, ready_states)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(writable_c_context, ready_contexts[0]); - EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]); - EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_events[0])); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(writable_c_context, blocking_events[0].trigger_context); + EXPECT_EQ(MOJO_RESULT_OK, blocking_events[0].result); + EXPECT_TRUE(blocking_events[0].signals_state.satisfied_signals & + MOJO_HANDLE_SIGNAL_WRITABLE); - // Cancel the new watch and arming should succeed once again. - EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, writable_c_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + // Remove the new trigger and arming should succeed once again. + EXPECT_EQ(MOJO_RESULT_OK, MojoRemoveTrigger(t, writable_c_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d)); } -TEST_F(WatcherTest, NotifyOtherFromNotificationCallback) { +TEST_F(TrapTest, ActivateOtherTriggerFromEventHandler) { MojoHandle a, b; CreateMessagePipe(&a, &b); static const char kTestMessageToA[] = "hello a"; static const char kTestMessageToB[] = "hello b"; - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + TriggerHelper helper; + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); - uintptr_t readable_a_context = helper.CreateContext(base::Bind( - [](MojoHandle w, MojoHandle a, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); + uintptr_t readable_a_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); EXPECT_EQ("hello a", ReadMessage(a)); - // Re-arm the watcher and signal |b|. - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + // Re-arm the trap and signal |b|. + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); WriteMessage(a, kTestMessageToB); - }, - w, a)); + }); - uintptr_t readable_b_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, MojoHandle w, MojoHandle b, - MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); + uintptr_t readable_b_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); EXPECT_EQ(kTestMessageToB, ReadMessage(b)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); - event->Signal(); - }, - &event, w, b)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); + wait.Signal(); + }); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_b_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, b, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_b_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - // Send a message to |a|. The relevant watch context should be notified, and - // should in turn send a message to |b|, waking up the other context. The - // second context signals |event|. + // Send a message to |a|. The relevant trigger should be notified and the + // event handler should send a message to |b|, in turn notifying the other + // trigger. The second event handler will signal |wait|. WriteMessage(b, kTestMessageToA); - event.Wait(); + wait.Wait(); } -TEST_F(WatcherTest, NotifySelfFromNotificationCallback) { +TEST_F(TrapTest, ActivateSameTriggerFromEventHandler) { MojoHandle a, b; CreateMessagePipe(&a, &b); static const char kTestMessageToA[] = "hello a"; - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + TriggerHelper helper; + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); int expected_notifications = 10; - uintptr_t readable_a_context = helper.CreateContext(base::Bind( - [](int* expected_count, MojoHandle w, MojoHandle a, MojoHandle b, - base::WaitableEvent* event, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); + uintptr_t readable_a_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); EXPECT_EQ("hello a", ReadMessage(a)); - EXPECT_GT(*expected_count, 0); - *expected_count -= 1; - if (*expected_count == 0) { - event->Signal(); + EXPECT_GT(expected_notifications, 0); + expected_notifications -= 1; + if (expected_notifications == 0) { + wait.Signal(); return; } else { - // Re-arm the watcher and signal |a| again. - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + // Re-arm the trap and signal |a| again. + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); WriteMessage(b, kTestMessageToA); } - }, - &expected_notifications, w, a, b, &event)); + }); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - // Send a message to |a|. When the watch above is notified, it will rearm and - // send another message to |a|. This will happen until - // |expected_notifications| reaches 0. + // Send a message to |a|. When the trigger above is activated, the event + // handler will rearm the trap and send another message to |a|. This will + // happen until |expected_notifications| reaches 0. WriteMessage(b, kTestMessageToA); - event.Wait(); + wait.Wait(); } -TEST_F(WatcherTest, ImplicitCancelOtherFromNotificationCallback) { +TEST_F(TrapTest, ImplicitRemoveOtherTriggerWithinEventHandler) { MojoHandle a, b; CreateMessagePipe(&a, &b); @@ -1044,30 +996,24 @@ static const char kTestMessageToA[] = "hi a"; static const char kTestMessageToC[] = "hi c"; - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + TriggerHelper helper; + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); uintptr_t readable_a_context = helper.CreateContextWithCancel( - base::Bind([](MojoResult result, MojoHandleSignalsState state) { - NOTREACHED(); - }), - base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event)); + [](const MojoTrapEvent&) { NOTREACHED(); }, [&] { wait.Signal(); }); - uintptr_t readable_c_context = helper.CreateContext(base::Bind( - [](MojoHandle w, MojoHandle a, MojoHandle b, MojoHandle c, - MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); + uintptr_t readable_c_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); EXPECT_EQ(kTestMessageToC, ReadMessage(c)); - // Now rearm the watcher. - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - // Must result in exactly ONE notification on the above context, for + // Must result in exactly ONE notification from the above trigger, for // CANCELLED only. Because we cannot dispatch notifications until the // stack unwinds, and because we must never dispatch non-cancellation // notifications for a handle once it's been closed, we must be certain @@ -1077,35 +1023,34 @@ WriteMessage(b, kTestMessageToA); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); - // Rearming should be fine since |a|'s watch should already be - // implicitly cancelled (even though the notification will not have + // Rearming should be fine since |a|'s trigger should already be + // implicitly removed (even though the notification will not have // been invoked yet.) - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); // Nothing interesting should happen as a result of this. EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); - }, - w, a, b, c)); + }); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, c, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_c_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, c, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_c_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); WriteMessage(d, kTestMessageToC); - event.Wait(); + wait.Wait(); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d)); } -TEST_F(WatcherTest, ExplicitCancelOtherFromNotificationCallback) { +TEST_F(TrapTest, ExplicitRemoveOtherTriggerWithinEventHandler) { MojoHandle a, b; CreateMessagePipe(&a, &b); @@ -1115,64 +1060,61 @@ static const char kTestMessageToA[] = "hi a"; static const char kTestMessageToC[] = "hi c"; - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + TriggerHelper helper; + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); - uintptr_t readable_a_context = helper.CreateContext(base::Bind( - [](MojoResult result, MojoHandleSignalsState state) { NOTREACHED(); })); + uintptr_t readable_a_context = + helper.CreateContext([](const MojoTrapEvent&) { NOTREACHED(); }); - uintptr_t readable_c_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, uintptr_t readable_a_context, MojoHandle w, - MojoHandle a, MojoHandle b, MojoHandle c, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); + uintptr_t readable_c_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); EXPECT_EQ(kTestMessageToC, ReadMessage(c)); - // Now rearm the watcher. - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + // Now rearm the trap. + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - // Should result in no notifications on the above context, because the - // watch will have been cancelled by the time the notification callback - // can execute. + // Should result in no notifications from the above trigger, because the + // trigger will have been removed by the time the event handler can + // execute. WriteMessage(b, kTestMessageToA); WriteMessage(b, kTestMessageToA); - EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoRemoveTrigger(t, readable_a_context, nullptr)); // Rearming should be fine now. - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); // Nothing interesting should happen as a result of these. EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); - event->Signal(); - }, - &event, readable_a_context, w, a, b, c)); + wait.Signal(); + }); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, c, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_c_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, c, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_c_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); WriteMessage(d, kTestMessageToC); - event.Wait(); + wait.Wait(); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d)); } -TEST_F(WatcherTest, NestedCancellation) { +TEST_F(TrapTest, NestedCancellation) { MojoHandle a, b; CreateMessagePipe(&a, &b); @@ -1183,243 +1125,231 @@ static const char kTestMessageToC[] = "hey c"; static const char kTestMessageToD[] = "hey d"; - // This is a tricky test. It establishes a watch on |b| using one watcher and - // watches on |c| and |d| using another watcher. + // This is a tricky test. It establishes a trigger on |b| using one trap and + // triggers on |c| and |d| using another trap. // - // A message is written to |d| to wake up |c|'s watch, and the notification - // handler for that event does the following: - // 1. Writes to |a| to eventually wake up |b|'s watcher. - // 2. Rearms |c|'s watcher. - // 3. Writes to |d| to eventually wake up |c|'s watcher again. + // A message is written to |d| to activate |c|'s trigger, and the resuling + // event handler invocation does the folllowing: + // 1. Writes to |a| to eventually activate |b|'s trigger. + // 2. Rearms |c|'s trap. + // 3. Writes to |d| to eventually activate |c|'s trigger again. // - // Meanwhile, |b|'s watch notification handler cancels |c|'s watch altogether - // before writing to |c| to wake up |d|. + // Meanwhile, |b|'s event handler removes |c|'s trigger altogether before + // writing to |c| to activate |d|'s trigger. // - // The net result should be that |c|'s context only gets notified once (from + // The net result should be that |c|'s trigger only gets activated once (from // the first write to |d| above) and everyone else gets notified as expected. - MojoHandle b_watcher; - MojoHandle cd_watcher; - WatchHelper helper; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&b_watcher)); - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&cd_watcher)); + MojoHandle b_trap; + MojoHandle cd_trap; + TriggerHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&b_trap)); + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&cd_trap)); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - uintptr_t readable_d_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, MojoHandle d, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + uintptr_t readable_d_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); EXPECT_EQ(kTestMessageToD, ReadMessage(d)); - event->Signal(); - }, - &event, d)); + wait.Signal(); + }); - static int num_expected_c_notifications = 1; - uintptr_t readable_c_context = helper.CreateContext(base::Bind( - [](MojoHandle cd_watcher, MojoHandle a, MojoHandle c, MojoHandle d, - MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); + int num_expected_c_notifications = 1; + uintptr_t readable_c_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); EXPECT_GT(num_expected_c_notifications--, 0); // Trigger an eventual |readable_b_context| notification. WriteMessage(a, kTestMessageToA); EXPECT_EQ(kTestMessageToC, ReadMessage(c)); - EXPECT_EQ(MOJO_RESULT_OK, MojoArmWatcher(cd_watcher, nullptr, nullptr, - nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmTrap(cd_trap, nullptr, nullptr, nullptr)); // Trigger another eventual |readable_c_context| notification. WriteMessage(d, kTestMessageToC); - }, - cd_watcher, a, c, d)); + }); - uintptr_t readable_b_context = helper.CreateContext(base::Bind( - [](MojoHandle cd_watcher, uintptr_t readable_c_context, MojoHandle c, - MojoResult result, MojoHandleSignalsState state) { + uintptr_t readable_b_context = + helper.CreateContext([&](const MojoTrapEvent& event) { EXPECT_EQ(MOJO_RESULT_OK, - MojoCancelWatch(cd_watcher, readable_c_context)); + MojoRemoveTrigger(cd_trap, readable_c_context, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, MojoArmWatcher(cd_watcher, nullptr, nullptr, - nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoArmTrap(cd_trap, nullptr, nullptr, nullptr)); WriteMessage(c, kTestMessageToD); - }, - cd_watcher, readable_c_context, c)); + }); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(b_watcher, b, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_b_context)); + MojoAddTrigger(b_trap, b, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_b_context, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(cd_watcher, c, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_c_context)); + MojoAddTrigger(cd_trap, c, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_c_context, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(cd_watcher, d, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_d_context)); + MojoAddTrigger(cd_trap, d, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_d_context, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(b_watcher, nullptr, nullptr, nullptr, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(cd_watcher, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(b_trap, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(cd_trap, nullptr, nullptr, nullptr)); WriteMessage(d, kTestMessageToC); - event.Wait(); + wait.Wait(); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(cd_watcher)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_watcher)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(cd_trap)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_trap)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d)); } -TEST_F(WatcherTest, CancelSelfInNotificationCallback) { +TEST_F(TrapTest, RemoveSelfWithinEventHandler) { MojoHandle a, b; CreateMessagePipe(&a, &b); static const char kTestMessageToA[] = "hey a"; - MojoHandle w; - WatchHelper helper; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + TriggerHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); - static uintptr_t readable_a_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, MojoHandle w, MojoHandle a, - MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); + static uintptr_t readable_a_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); - // There should be no problem cancelling this watch from its own + // There should be no problem removing this trigger from its own // notification invocation. - EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoRemoveTrigger(t, readable_a_context, nullptr)); EXPECT_EQ(kTestMessageToA, ReadMessage(a)); // Arming should fail because there are no longer any registered - // watches on the watcher. + // triggers on the trap. EXPECT_EQ(MOJO_RESULT_NOT_FOUND, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoArmTrap(t, nullptr, nullptr, nullptr)); // And closing |a| should be fine (and should not invoke this // notification with MOJO_RESULT_CANCELLED) for the same reason. EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); - event->Signal(); - }, - &event, w, a)); + wait.Signal(); + }); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); WriteMessage(b, kTestMessageToA); - event.Wait(); + wait.Wait(); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); } -TEST_F(WatcherTest, CloseWatcherInNotificationCallback) { +TEST_F(TrapTest, CloseTrapWithinEventHandler) { MojoHandle a, b; CreateMessagePipe(&a, &b); static const char kTestMessageToA1[] = "hey a"; static const char kTestMessageToA2[] = "hey a again"; - MojoHandle w; - WatchHelper helper; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + TriggerHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); - uintptr_t readable_a_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, MojoHandle w, MojoHandle a, MojoHandle b, - MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); + uintptr_t readable_a_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); EXPECT_EQ(kTestMessageToA1, ReadMessage(a)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); - // There should be no problem closing this watcher from its own + // There should be no problem closing this trap from its own // notification callback. - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); - // And these should not trigger more notifications, because |w| has been + // And these should not trigger more notifications, because |t| has been // closed already. WriteMessage(b, kTestMessageToA2); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); - event->Signal(); - }, - &event, w, a, b)); + wait.Signal(); + }); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); WriteMessage(b, kTestMessageToA1); - event.Wait(); + wait.Wait(); } -TEST_F(WatcherTest, CloseWatcherAfterImplicitCancel) { +TEST_F(TrapTest, CloseTrapAfterImplicitTriggerRemoval) { MojoHandle a, b; CreateMessagePipe(&a, &b); static const char kTestMessageToA[] = "hey a"; - MojoHandle w; - WatchHelper helper; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + TriggerHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); - uintptr_t readable_a_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, MojoHandle w, MojoHandle a, - MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); + uintptr_t readable_a_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); EXPECT_EQ(kTestMessageToA, ReadMessage(a)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); // This will cue up a notification for |MOJO_RESULT_CANCELLED|... EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); - // ...but it should never fire because we close the watcher here. - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + // ...but it should never fire because we close the trap here. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); - event->Signal(); - }, - &event, w, a)); + wait.Signal(); + }); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); WriteMessage(b, kTestMessageToA); - event.Wait(); + wait.Wait(); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); } -TEST_F(WatcherTest, OtherThreadCancelDuringNotification) { +TEST_F(TrapTest, OtherThreadRemovesTriggerDuringEventHandler) { MojoHandle a, b; CreateMessagePipe(&a, &b); static const char kTestMessageToA[] = "hey a"; - MojoHandle w; - WatchHelper helper; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + TriggerHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); base::WaitableEvent wait_for_notification( base::WaitableEvent::ResetPolicy::MANUAL, @@ -1431,59 +1361,51 @@ static bool callback_done = false; uintptr_t readable_a_context = helper.CreateContextWithCancel( - base::Bind( - [](base::WaitableEvent* wait_for_notification, MojoHandle w, - MojoHandle a, MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(kTestMessageToA, ReadMessage(a)); + [&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); + EXPECT_EQ(kTestMessageToA, ReadMessage(a)); - wait_for_notification->Signal(); + wait_for_notification.Signal(); - // Give the other thread sufficient time to race with the completion - // of this callback. There should be no race, since the cancellation - // notification must be mutually exclusive to this notification. - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); + // Give the other thread sufficient time to race with the completion + // of this callback. There should be no race, since the cancellation + // notification must be mutually exclusive to this notification. + base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); - callback_done = true; - }, - &wait_for_notification, w, a), - base::Bind( - [](base::WaitableEvent* wait_for_cancellation) { - EXPECT_TRUE(callback_done); - wait_for_cancellation->Signal(); - }, - &wait_for_cancellation)); - - ThreadedRunner runner(base::Bind( - [](base::WaitableEvent* wait_for_notification, - base::WaitableEvent* wait_for_cancellation, MojoHandle w, - uintptr_t readable_a_context) { - wait_for_notification->Wait(); - - // Cancel the watch while the notification is still running. - EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context)); - - wait_for_cancellation->Wait(); - - EXPECT_TRUE(callback_done); + callback_done = true; }, - &wait_for_notification, &wait_for_cancellation, w, readable_a_context)); + [&] { + EXPECT_TRUE(callback_done); + wait_for_cancellation.Signal(); + }); + + ThreadedRunner runner(base::BindOnce(base::BindLambdaForTesting([&] { + wait_for_notification.Wait(); + + // Cancel the watch while the notification is still running. + EXPECT_EQ(MOJO_RESULT_OK, + MojoRemoveTrigger(t, readable_a_context, nullptr)); + + wait_for_cancellation.Wait(); + + EXPECT_TRUE(callback_done); + }))); runner.Start(); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); WriteMessage(b, kTestMessageToA); runner.Join(); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); } -TEST_F(WatcherTest, WatchesCancelEachOtherFromNotifications) { +TEST_F(TrapTest, TriggersRemoveEachOtherWithinEventHandlers) { MojoHandle a, b; CreateMessagePipe(&a, &b); @@ -1503,81 +1425,65 @@ base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); - MojoHandle a_watcher; - MojoHandle b_watcher; - WatchHelper helper; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&a_watcher)); - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&b_watcher)); + MojoHandle a_trap; + MojoHandle b_trap; + TriggerHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&a_trap)); + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&b_trap)); - // We set up two watchers, one on |a| and one on |b|. They cancel each other - // from within their respective watch notifications. This should be safe, - // i.e., it should not deadlock, in spite of the fact that we also guarantee - // mutually exclusive notification execution (including cancellations) on any - // given watch. + // We set up two traps, one triggered on |a| readability and one triggered on + // |b| readability. Each removes the other's trigger from within its own event + // handler. This should be safe, i.e., it should not deadlock in spite of the + // fact that we also guarantee mutually exclusive event handler invocation + // (including cancellations) on any given trap. bool a_cancelled = false; bool b_cancelled = false; static uintptr_t readable_b_context; uintptr_t readable_a_context = helper.CreateContextWithCancel( - base::Bind( - [](base::WaitableEvent* wait_for_a_to_notify, - base::WaitableEvent* wait_for_b_to_notify, MojoHandle b_watcher, - MojoHandle a, MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(kTestMessageToA, ReadMessage(a)); - wait_for_a_to_notify->Signal(); - wait_for_b_to_notify->Wait(); - EXPECT_EQ(MOJO_RESULT_OK, - MojoCancelWatch(b_watcher, readable_b_context)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_watcher)); - }, - &wait_for_a_to_notify, &wait_for_b_to_notify, b_watcher, a), - base::Bind( - [](base::WaitableEvent* wait_for_a_to_cancel, - base::WaitableEvent* wait_for_b_to_cancel, bool* a_cancelled) { - *a_cancelled = true; - wait_for_a_to_cancel->Signal(); - wait_for_b_to_cancel->Wait(); - }, - &wait_for_a_to_cancel, &wait_for_b_to_cancel, &a_cancelled)); + [&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); + EXPECT_EQ(kTestMessageToA, ReadMessage(a)); + wait_for_a_to_notify.Signal(); + wait_for_b_to_notify.Wait(); + EXPECT_EQ(MOJO_RESULT_OK, + MojoRemoveTrigger(b_trap, readable_b_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_trap)); + }, + [&] { + a_cancelled = true; + wait_for_a_to_cancel.Signal(); + wait_for_b_to_cancel.Wait(); + }); readable_b_context = helper.CreateContextWithCancel( - base::Bind( - [](base::WaitableEvent* wait_for_a_to_notify, - base::WaitableEvent* wait_for_b_to_notify, - uintptr_t readable_a_context, MojoHandle a_watcher, MojoHandle b, - MojoResult result, MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - EXPECT_EQ(kTestMessageToB, ReadMessage(b)); - wait_for_b_to_notify->Signal(); - wait_for_a_to_notify->Wait(); - EXPECT_EQ(MOJO_RESULT_OK, - MojoCancelWatch(a_watcher, readable_a_context)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a_watcher)); - }, - &wait_for_a_to_notify, &wait_for_b_to_notify, readable_a_context, - a_watcher, b), - base::Bind( - [](base::WaitableEvent* wait_for_a_to_cancel, - base::WaitableEvent* wait_for_b_to_cancel, bool* b_cancelled) { - *b_cancelled = true; - wait_for_b_to_cancel->Signal(); - wait_for_a_to_cancel->Wait(); - }, - &wait_for_a_to_cancel, &wait_for_b_to_cancel, &b_cancelled)); + [&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); + EXPECT_EQ(kTestMessageToB, ReadMessage(b)); + wait_for_b_to_notify.Signal(); + wait_for_a_to_notify.Wait(); + EXPECT_EQ(MOJO_RESULT_OK, + MojoRemoveTrigger(a_trap, readable_a_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a_trap)); + }, + [&] { + b_cancelled = true; + wait_for_b_to_cancel.Signal(); + wait_for_a_to_cancel.Wait(); + }); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(a_watcher, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); + MojoAddTrigger(a_trap, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(a_trap, nullptr, nullptr, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(a_watcher, nullptr, nullptr, nullptr, nullptr)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(b_watcher, b, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_b_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(b_watcher, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(b_trap, b, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_b_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(b_trap, nullptr, nullptr, nullptr)); - ThreadedRunner runner( - base::Bind([](MojoHandle b) { WriteMessage(b, kTestMessageToA); }, b)); + ThreadedRunner runner(base::BindOnce( + [](MojoHandle b) { WriteMessage(b, kTestMessageToA); }, b)); runner.Start(); WriteMessage(a, kTestMessageToB); @@ -1593,54 +1499,57 @@ EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); } -TEST_F(WatcherTest, AlwaysCancel) { - // Basic sanity check to ensure that all possible ways to cancel a watch +TEST_F(TrapTest, AlwaysCancel) { + // Basic sanity check to ensure that all possible ways to remove a trigger // result in a final MOJO_RESULT_CANCELLED notification. MojoHandle a, b; CreateMessagePipe(&a, &b); - MojoHandle w; - WatchHelper helper; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + TriggerHelper helper; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - const base::Closure signal_event = - base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + auto ignore_event = [](const MojoTrapEvent&) {}; + auto signal_wait = [&] { wait.Signal(); }; - // Cancel via |MojoCancelWatch()|. - uintptr_t context = helper.CreateContextWithCancel( - WatchHelper::ContextCallback(), signal_event); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, context)); - EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, context)); - event.Wait(); - event.Reset(); + // Cancel via |MojoRemoveTrigger()|. + uintptr_t context = helper.CreateContextWithCancel(ignore_event, signal_wait); + EXPECT_EQ(MOJO_RESULT_OK, + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, context, + nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoRemoveTrigger(t, context, nullptr)); + wait.Wait(); + wait.Reset(); - // Cancel by closing the watched handle. - context = helper.CreateContextWithCancel(WatchHelper::ContextCallback(), - signal_event); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, context)); + // Cancel by closing the trigger's watched handle. + context = helper.CreateContextWithCancel(ignore_event, signal_wait); + EXPECT_EQ(MOJO_RESULT_OK, + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, context, + nullptr)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); - event.Wait(); - event.Reset(); + wait.Wait(); + wait.Reset(); - // Cancel by closing the watcher handle. - context = helper.CreateContextWithCancel(WatchHelper::ContextCallback(), - signal_event); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, context)); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); - event.Wait(); + // Cancel by closing the trap handle. + context = helper.CreateContextWithCancel(ignore_event, signal_wait); + EXPECT_EQ(MOJO_RESULT_OK, + MojoAddTrigger(t, b, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, context, + nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); + wait.Wait(); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); } -TEST_F(WatcherTest, ArmFailureCirculation) { - // Sanity check to ensure that all ready handles will eventually be returned - // over a finite number of calls to MojoArmWatcher(). +TEST_F(TrapTest, ArmFailureCirculation) { + // Sanity check to ensure that all ready trigger events will eventually be + // returned over a finite number of calls to MojoArmTrap(). constexpr size_t kNumTestPipes = 100; constexpr size_t kNumTestHandles = kNumTestPipes * 2; @@ -1655,89 +1564,84 @@ WaitForSignals(handles[i + kNumTestPipes], MOJO_HANDLE_SIGNAL_READABLE); } - // Create a watcher and watch all of them. - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &w)); + // Create a trap and watch all of them for readability. + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateTrap(&ExpectOnlyCancel, nullptr, &t)); for (size_t i = 0; i < kNumTestHandles; ++i) { - EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, handles[i], MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, i)); + EXPECT_EQ( + MOJO_RESULT_OK, + MojoAddTrigger(t, handles[i], MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, i, nullptr)); } - // Keep trying to arm |w| until every watch gets an entry in |ready_contexts|. - // If MojoArmWatcher() is well-behaved, this should terminate eventually. + // Keep trying to arm |t| until every trigger gets an entry in + // |ready_contexts|. If MojoArmTrap() is well-behaved, this should terminate + // eventually. std::set<uintptr_t> ready_contexts; while (ready_contexts.size() < kNumTestHandles) { - uint32_t num_ready_contexts = 1; - uintptr_t ready_context; - MojoResult ready_result; - MojoHandleSignalsState ready_state; + uint32_t num_blocking_events = 1; + MojoTrapEvent blocking_event = {sizeof(blocking_event)}; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoArmWatcher(w, &num_ready_contexts, &ready_context, - &ready_result, &ready_state)); - EXPECT_EQ(1u, num_ready_contexts); - EXPECT_EQ(MOJO_RESULT_OK, ready_result); - ready_contexts.insert(ready_context); + MojoArmTrap(t, nullptr, &num_blocking_events, &blocking_event)); + EXPECT_EQ(1u, num_blocking_events); + EXPECT_EQ(MOJO_RESULT_OK, blocking_event.result); + ready_contexts.insert(blocking_event.trigger_context); } for (size_t i = 0; i < kNumTestHandles; ++i) EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handles[i])); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); } -TEST_F(WatcherTest, WatchNotSatisfied) { +TEST_F(TrapTest, TriggerOnUnsatisfiedSignals) { MojoHandle a, b; CreateMessagePipe(&a, &b); - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); - WatchHelper helper; - const uintptr_t readable_a_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - event->Signal(); - }, - &event)); + base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + TriggerHelper helper; + const uintptr_t readable_a_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); + wait.Signal(); + }); - MojoHandle w; - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); + MojoHandle t; + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); EXPECT_EQ(MOJO_RESULT_OK, - MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, readable_a_context)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + readable_a_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); const char kMessage[] = "this is not a message"; WriteMessage(b, kMessage); - event.Wait(); + wait.Wait(); - // Now we know |a| is readable. Cancel the watch and watch for the - // not-readable state. - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); - const uintptr_t not_readable_a_context = helper.CreateContext(base::Bind( - [](base::WaitableEvent* event, MojoResult result, - MojoHandleSignalsState state) { - EXPECT_EQ(MOJO_RESULT_OK, result); - event->Signal(); - }, - &event)); - EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w)); - EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_NOT_SATISFIED, - not_readable_a_context)); + // Now we know |a| is readable. Remove the trigger and add a new one to watch + // for a not-readable state. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); + const uintptr_t not_readable_a_context = + helper.CreateContext([&](const MojoTrapEvent& event) { + EXPECT_EQ(MOJO_RESULT_OK, event.result); + wait.Signal(); + }); + EXPECT_EQ(MOJO_RESULT_OK, helper.CreateTrap(&t)); EXPECT_EQ(MOJO_RESULT_OK, - MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr)); + MojoAddTrigger(t, a, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_UNSATISFIED, + not_readable_a_context, nullptr)); + EXPECT_EQ(MOJO_RESULT_OK, MojoArmTrap(t, nullptr, nullptr, nullptr)); // This should not block, because the event should be signaled by // |not_readable_a_context| when we read the only available message off of // |a|. - event.Reset(); + wait.Reset(); EXPECT_EQ(kMessage, ReadMessage(a)); - event.Wait(); + wait.Wait(); - EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(t)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); } @@ -1761,13 +1665,13 @@ return handles[base::RandInt(0, static_cast<int>(size) - 1)]; } -void DoRandomThing(MojoHandle* watchers, - size_t num_watchers, +void DoRandomThing(MojoHandle* traps, + size_t num_traps, MojoHandle* watched_handles, size_t num_watched_handles) { switch (base::RandInt(0, 10)) { case 0: - MojoClose(RandomHandle(watchers, num_watchers)); + MojoClose(RandomHandle(traps, num_traps)); break; case 1: MojoClose(RandomHandle(watched_handles, num_watched_handles)); @@ -1785,37 +1689,30 @@ } case 5: case 6: { - MojoHandle w = RandomHandle(watchers, num_watchers); + MojoHandle t = RandomHandle(traps, num_traps); MojoHandle h = RandomHandle(watched_handles, num_watched_handles); - MojoWatch(w, h, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_WATCH_CONDITION_SATISFIED, static_cast<uintptr_t>(h)); + MojoAddTrigger(t, h, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, + static_cast<uintptr_t>(h), nullptr); break; } case 7: case 8: { - uint32_t num_ready_contexts = 1; - uintptr_t ready_context; - MojoResult ready_result; - MojoHandleSignalsState ready_state; - if (MojoArmWatcher(RandomHandle(watchers, num_watchers), - &num_ready_contexts, &ready_context, &ready_result, - &ready_state) == MOJO_RESULT_FAILED_PRECONDITION && - ready_result == MOJO_RESULT_OK) { - MojoTrapEvent event; - event.struct_size = sizeof(event); - event.trigger_context = ready_context; - event.result = ready_result; - event.signals_state = ready_state; - event.flags = MOJO_TRAP_EVENT_FLAG_NONE; - ReadAllMessages(&event); + uint32_t num_blocking_events = 1; + MojoTrapEvent blocking_event = {sizeof(blocking_event)}; + if (MojoArmTrap(RandomHandle(traps, num_traps), nullptr, + &num_blocking_events, + &blocking_event) == MOJO_RESULT_FAILED_PRECONDITION && + blocking_event.result == MOJO_RESULT_OK) { + ReadAllMessages(&blocking_event); } break; } case 9: case 10: { - MojoHandle w = RandomHandle(watchers, num_watchers); + MojoHandle t = RandomHandle(traps, num_traps); MojoHandle h = RandomHandle(watched_handles, num_watched_handles); - MojoCancelWatch(w, static_cast<uintptr_t>(h)); + MojoRemoveTrigger(t, static_cast<uintptr_t>(h), nullptr); break; } default: @@ -1824,41 +1721,39 @@ } } -TEST_F(WatcherTest, ConcurrencyStressTest) { +TEST_F(TrapTest, ConcurrencyStressTest) { // Regression test for https://crbug.com/740044. Exercises racy usage of the - // watcher API to weed out potential crashes. + // trap API to weed out potential crashes. - constexpr size_t kNumWatchers = 50; + constexpr size_t kNumTraps = 50; constexpr size_t kNumWatchedHandles = 50; static_assert(kNumWatchedHandles % 2 == 0, "Invalid number of test handles."); constexpr size_t kNumThreads = 10; static constexpr size_t kNumOperationsPerThread = 400; - MojoHandle watchers[kNumWatchers]; + MojoHandle traps[kNumTraps]; MojoHandle watched_handles[kNumWatchedHandles]; - g_do_random_thing_callback = - base::Bind(&DoRandomThing, watchers, kNumWatchers, watched_handles, - kNumWatchedHandles); + g_do_random_thing_callback = base::BindRepeating( + &DoRandomThing, traps, kNumTraps, watched_handles, kNumWatchedHandles); - for (size_t i = 0; i < kNumWatchers; ++i) - MojoCreateTrap(&ReadAllMessages, nullptr, &watchers[i]); + for (size_t i = 0; i < kNumTraps; ++i) + MojoCreateTrap(&ReadAllMessages, nullptr, &traps[i]); for (size_t i = 0; i < kNumWatchedHandles; i += 2) CreateMessagePipe(&watched_handles[i], &watched_handles[i + 1]); std::unique_ptr<ThreadedRunner> threads[kNumThreads]; - auto runner_callback = base::Bind([]() { - for (size_t i = 0; i < kNumOperationsPerThread; ++i) - g_do_random_thing_callback.Run(); - }); for (size_t i = 0; i < kNumThreads; ++i) { - threads[i] = std::make_unique<ThreadedRunner>(runner_callback); + threads[i] = std::make_unique<ThreadedRunner>(base::BindOnce([] { + for (size_t i = 0; i < kNumOperationsPerThread; ++i) + g_do_random_thing_callback.Run(); + })); threads[i]->Start(); } for (size_t i = 0; i < kNumThreads; ++i) threads[i]->Join(); - for (size_t i = 0; i < kNumWatchers; ++i) - MojoClose(watchers[i]); + for (size_t i = 0; i < kNumTraps; ++i) + MojoClose(traps[i]); for (size_t i = 0; i < kNumWatchedHandles; ++i) MojoClose(watched_handles[i]); }
diff --git a/mojo/core/watcher_dispatcher.cc b/mojo/core/watcher_dispatcher.cc index 0c880f6..f2eb2e25 100644 --- a/mojo/core/watcher_dispatcher.cc +++ b/mojo/core/watcher_dispatcher.cc
@@ -204,16 +204,11 @@ return MOJO_RESULT_OK; } -MojoResult WatcherDispatcher::Arm( - uint32_t* num_ready_contexts, - uintptr_t* ready_contexts, - MojoResult* ready_results, - MojoHandleSignalsState* ready_signals_states) { +MojoResult WatcherDispatcher::Arm(uint32_t* num_blocking_events, + MojoTrapEvent* blocking_events) { base::AutoLock lock(lock_); - if (num_ready_contexts && - (!ready_contexts || !ready_results || !ready_signals_states)) { + if (num_blocking_events && !blocking_events) return MOJO_RESULT_INVALID_ARGUMENT; - } if (closed_) return MOJO_RESULT_INVALID_ARGUMENT; @@ -226,10 +221,10 @@ return MOJO_RESULT_OK; } - if (num_ready_contexts) { + if (num_blocking_events) { DCHECK_LE(ready_watches_.size(), std::numeric_limits<uint32_t>::max()); - *num_ready_contexts = std::min( - *num_ready_contexts, static_cast<uint32_t>(ready_watches_.size())); + *num_blocking_events = std::min( + *num_blocking_events, static_cast<uint32_t>(ready_watches_.size())); WatchSet::const_iterator next_ready_iter = ready_watches_.begin(); if (last_watch_to_block_arming_) { @@ -242,11 +237,14 @@ next_ready_iter = ready_watches_.begin(); } - for (size_t i = 0; i < *num_ready_contexts; ++i) { + for (size_t i = 0; i < *num_blocking_events; ++i) { const Watch* const watch = *next_ready_iter; - ready_contexts[i] = watch->context(); - ready_results[i] = watch->last_known_result(); - ready_signals_states[i] = watch->last_known_signals_state(); + if (blocking_events[i].struct_size < sizeof(*blocking_events)) + return MOJO_RESULT_INVALID_ARGUMENT; + blocking_events[i].flags = MOJO_TRAP_EVENT_FLAG_WITHIN_API_CALL; + blocking_events[i].trigger_context = watch->context(); + blocking_events[i].result = watch->last_known_result(); + blocking_events[i].signals_state = watch->last_known_signals_state(); // Iterate and wrap around. last_watch_to_block_arming_ = watch;
diff --git a/mojo/core/watcher_dispatcher.h b/mojo/core/watcher_dispatcher.h index 2f106f6..6a8bced 100644 --- a/mojo/core/watcher_dispatcher.h +++ b/mojo/core/watcher_dispatcher.h
@@ -50,10 +50,8 @@ MojoTriggerCondition condition, uintptr_t context) override; MojoResult CancelWatch(uintptr_t context) override; - MojoResult Arm(uint32_t* num_ready_contexts, - uintptr_t* ready_contexts, - MojoResult* ready_results, - MojoHandleSignalsState* ready_signals_states) override; + MojoResult Arm(uint32_t* num_blocking_events, + MojoTrapEvent* blocking_events) override; private: friend class Watch;
diff --git a/mojo/public/c/system/README.md b/mojo/public/c/system/README.md index 04ee415..ec88e3e 100644 --- a/mojo/public/c/system/README.md +++ b/mojo/public/c/system/README.md
@@ -745,7 +745,7 @@ In this case `a` is clearly not yet readable, so arming should succeed: ``` c -MojoResult result = MojoArmTrap(t, NULL, NULL, NULL, NULL, NULL); +MojoResult result = MojoArmTrap(t, NULL, NULL, NULL); ``` Now we can write to `b` to make `a` readable: @@ -780,28 +780,27 @@ ``` c // Provide some storage for information about triggers that would have been // activated immediately. -uint32_t num_ready_triggers = 4; -uintptr_t reay_triggers[4]; -MojoResult ready_results[4]; -struct MojoHandleSignalsStates ready_states[4]; -MojoResult result = MojoArmTrap(t, NULL, &num_ready_triggers, ready_triggers, - ready_results, ready_states); +uint32_t num_blocking_events = 2; +MojoTrapEvent blocking_events[2] = {{sizeof(MojoTrapEvent)}, + {sizeof(MojoTrapEvent)}}; +MojoResult result = MojoArmTrap(t, NULL, &num_blocking_events, + &blocking_events); ``` Because `a` is still readable this operation will now fail with -`MOJO_RESULT_FAILED_PRECONDITION`. The input value of `num_ready_triggers` -informs `MojoArmTrap` that it may store information regarding up to 4 triggers +`MOJO_RESULT_FAILED_PRECONDITION`. The input value of `num_blocking_events` +informs `MojoArmTrap` that it may store information regarding up to 2 triggers which have prevented arming. In this case of course there is only one active trigger, so upon return we will see: -* `num_ready_triggers` is `1`. -* `ready_triggers[0]` is `1234`. -* `ready_results[0]` is `MOJO_RESULT_OK` -* `ready_states[0]` is the last known signaling state of handle `a`. +* `num_blocking_events` is `1`. +* `blocking_events[0].trigger_context` is `1234`. +* `blocking_events[0].result` is `MOJO_RESULT_OK` +* `blocking_events[0].signals_state` is the last known signaling state of handle + `a`. -In other words the stored information mirrors what would have been the -event handler's arguments if the trap were allowed to arm and thus notify -immediately. +In other words the stored information mirrors what would have been the resulting +event structure if the trap were allowed to arm and then notify immediately. ### Removing a Trigger @@ -873,7 +872,7 @@ // This is the only handle watched by the trap, so as long as we can't arm // the watcher we know something's up with this handle. Try to read messages // until we can successfully arm again or something goes terribly wrong. - while (MojoArmTrap(state->trap, NULL NULL, NULL, NULL, NULL) == + while (MojoArmTrap(state->trap, NULL NULL, NULL) == MOJO_RESULT_FAILED_PRECONDITION) { rv = MojoReadMessageNew(state->handle, NULL, NULL, NULL, MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); @@ -910,8 +909,8 @@ MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED, (uintptr_t)b_state, NULL); -MojoArmTrap(a_trap, NULL, NULL, NULL, NULL, NULL); -MojoArmTrap(b_trap, NULL, NULL, NULL, NULL, NULL); +MojoArmTrap(a_trap, NULL, NULL, NULL); +MojoArmTrap(b_trap, NULL, NULL, NULL); ``` Now any writes to `a` will increment `message_count` in `b_state`, and any
diff --git a/mojo/public/c/system/thunks.cc b/mojo/public/c/system/thunks.cc index fe4c77c..ca5029c 100644 --- a/mojo/public/c/system/thunks.cc +++ b/mojo/public/c/system/thunks.cc
@@ -288,12 +288,10 @@ MojoResult MojoArmTrap(MojoHandle trap_handle, const MojoArmTrapOptions* options, - uint32_t* num_ready_triggers, - uintptr_t* ready_triggers, - MojoResult* ready_results, - MojoHandleSignalsState* ready_signals_states) { - return INVOKE_THUNK(ArmTrap, trap_handle, options, num_ready_triggers, - ready_triggers, ready_results, ready_signals_states); + uint32_t* num_blocking_events, + MojoTrapEvent* blocking_events) { + return INVOKE_THUNK(ArmTrap, trap_handle, options, num_blocking_events, + blocking_events); } MojoResult MojoCreateMessage(const MojoCreateMessageOptions* options,
diff --git a/mojo/public/c/system/thunks.h b/mojo/public/c/system/thunks.h index b1cc6b1..d81c5d94 100644 --- a/mojo/public/c/system/thunks.h +++ b/mojo/public/c/system/thunks.h
@@ -156,10 +156,8 @@ const struct MojoRemoveTriggerOptions* options); MojoResult (*ArmTrap)(MojoHandle trap_handle, const struct MojoArmTrapOptions* options, - uint32_t* num_ready_triggers, - uintptr_t* ready_triggers, - MojoResult* ready_results, - MojoHandleSignalsState* ready_signals_states); + uint32_t* num_blocking_events, + struct MojoTrapEvent* blocking_events); // Platform handle API. MojoResult (*WrapPlatformHandle)(
diff --git a/mojo/public/c/system/trap.h b/mojo/public/c/system/trap.h index 844c3a0..c5e718e 100644 --- a/mojo/public/c/system/trap.h +++ b/mojo/public/c/system/trap.h
@@ -277,51 +277,43 @@ // // Parameters: // |trap_handle|: The handle of the trap to be armed. -// |num_ready_triggers|: An address pointing to the number of elements -// available for storage in the following output buffer parameters. +// |num_blocking_events|: An address pointing to the number of elements +// available for storage at the address given by |blocking_events|. // Optional and only used when |MOJO_RESULT_FAILED_PRECONDITION| is // returned. See below. -// |ready_triggers|: An output buffer for contexts of triggers that would have -// tripped the trap immediately if it were armed. Optional and used only -// when |MOJO_RESULT_FAILED_PRECONDITION| is returned. See below. -// |ready_results|: An output buffer for |MojoResult| values corresponding to -// each trigger in |ready_triggers|. Optional and only used when -// |MOJO_RESULT_FAILED_PRECONDITION| is returned. See below. -// |ready_signals_states|: An output buffer for |MojoHandleSignalsState| -// structures corresponding to the handle observed by each respective -// trigger in |ready_triggers|. Optional and only used when +// |blocking_events|: An output buffer for |MojoTrapEvent| structures to be +// filled in if one or more triggers would have tripped the trap +// immediately if it were armed. Optional and used only when // |MOJO_RESULT_FAILED_PRECONDITION| is returned. See below. // // Returns: -// |MOJO_RESULT_OK| if the trap has been successfully armed. All arguments -// other than |trap_handle| are ignored in this case. -// |MOJO_RESULT_NOT_FOUND| if the trap does not have any triggers. All -// arguments other than |trap_handle| are ignored. +// |MOJO_RESULT_OK| if the trap has been successfully armed. +// |num_blocking_events| and |blocking_events| are ignored. +// |MOJO_RESULT_NOT_FOUND| if the trap does not have any triggers. +// |num_blocking_events| and |blocking_events| are ignored. // |MOJO_RESULT_INVALID_ARGUMENT| if |trap_handle| is not a valid trap handle, -// or if |num_ready_triggers| is non-null and any of the output buffer -// paramters is null. +// or if |num_blocking_events| is non-null but |blocking_events| is +// not. // |MOJO_RESULT_FAILED_PRECONDITION| if one or more triggers would have -// tripped the trap immediately upon arming. If |num_handles| is non-null, -// this assumes there is enough space for |*num_handles| entries in each -// of the subsequent output buffer parameters. +// tripped the trap immediately upon arming. If |num_blocking_events| is +// non-null, this assumes there is enough space for |*num_blocking_events| +// entries at the non-null address in |blocking_events|. // -// At most |*num_handles| entries are populated in the output buffers, -// with each entry corresponding to one of the triggers which would have -// tripped the trap. The actual number of entries populated is written to -// |*num_handles| before returning. +// At most |*num_blocking_events| entries are populated there, with each +// entry corresponding to one of the triggers which would have tripped the +// trap. The actual number of entries populated is written to +// |*num_blocking_events| before returning. // // If there are more ready triggers than available provided storage, the -// subset presented to thecaller is arbitrary. The runtime makes an effort -// to circulate triggers returned by consecutive failed |MojoArmTrap()| -// calls so that callers may avoid handle starvation when observing a -// large number of active handles with a single trap. +// subset presented to the caller is arbitrary. The runtime makes an +// effort to circulate triggers returned by consecutive failed +// |MojoArmTrap()| calls so that callers may avoid handle starvation when +// observing a large number of active handles with a single trap. MOJO_SYSTEM_EXPORT MojoResult MojoArmTrap(MojoHandle trap_handle, const struct MojoArmTrapOptions* options, - uint32_t* num_ready_triggers, - uintptr_t* ready_triggers, - MojoResult* ready_results, - struct MojoHandleSignalsState* ready_signals_states); + uint32_t* num_blocking_events, + struct MojoTrapEvent* blocking_events); #ifdef __cplusplus } // extern "C"
diff --git a/mojo/public/cpp/base/BUILD.gn b/mojo/public/cpp/base/BUILD.gn index e97ccda..c57ac0bf 100644 --- a/mojo/public/cpp/base/BUILD.gn +++ b/mojo/public/cpp/base/BUILD.gn
@@ -30,10 +30,14 @@ sources = [ "big_buffer_mojom_traits.cc", "big_buffer_mojom_traits.h", + "file_info_mojom_traits.cc", + "file_info_mojom_traits.h", "file_path_mojom_traits.cc", "file_path_mojom_traits.h", "shared_memory_mojom_traits.cc", "shared_memory_mojom_traits.h", + "time_mojom_traits.cc", + "time_mojom_traits.h", "values_mojom_traits.cc", "values_mojom_traits.h", ]
diff --git a/mojo/public/cpp/base/file_info.typemap b/mojo/public/cpp/base/file_info.typemap index f6ef16a..4faac8f1 100644 --- a/mojo/public/cpp/base/file_info.typemap +++ b/mojo/public/cpp/base/file_info.typemap
@@ -4,9 +4,10 @@ mojom = "//mojo/public/mojom/base/file_info.mojom" public_headers = [ "//base/files/file.h" ] -traits_headers = [ "//ipc/ipc_message_utils.h" ] +traits_headers = [ "//mojo/public/cpp/base/file_info_mojom_traits.h" ] public_deps = [ - "//ipc", + "//base", + "//mojo/public/cpp/base:shared_typemap_traits", ] type_mappings = [ "mojo_base.mojom.FileInfo=base::File::Info" ]
diff --git a/mojo/public/cpp/base/file_info_mojom_traits.cc b/mojo/public/cpp/base/file_info_mojom_traits.cc new file mode 100644 index 0000000..64a0802 --- /dev/null +++ b/mojo/public/cpp/base/file_info_mojom_traits.cc
@@ -0,0 +1,28 @@ +// 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. + +#include "mojo/public/cpp/base/file_info_mojom_traits.h" + +#include "base/logging.h" +#include "mojo/public/cpp/base/time_mojom_traits.h" + +namespace mojo { + +// static +bool StructTraits<mojo_base::mojom::FileInfoDataView, base::File::Info>::Read( + mojo_base::mojom::FileInfoDataView data, + base::File::Info* out) { + if (!data.ReadLastModified(&out->last_modified)) + return false; + if (!data.ReadLastAccessed(&out->last_accessed)) + return false; + if (!data.ReadCreationTime(&out->creation_time)) + return false; + out->size = data.size(); + out->is_directory = data.is_directory(); + out->is_symbolic_link = data.is_symbolic_link(); + return true; +} + +} // namespace mojo
diff --git a/mojo/public/cpp/base/file_info_mojom_traits.h b/mojo/public/cpp/base/file_info_mojom_traits.h new file mode 100644 index 0000000..4049e03 --- /dev/null +++ b/mojo/public/cpp/base/file_info_mojom_traits.h
@@ -0,0 +1,49 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BASE_FILE_INFO_MOJOM_TRAITS_H_ +#define MOJO_PUBLIC_CPP_BASE_FILE_INFO_MOJOM_TRAITS_H_ + +#include <cstdint> + +#include "base/component_export.h" +#include "base/files/file.h" +#include "base/macros.h" +#include "mojo/public/cpp/bindings/struct_traits.h" +#include "mojo/public/mojom/base/file_info.mojom-shared.h" + +namespace mojo { + +template <> +struct COMPONENT_EXPORT(MOJO_BASE_SHARED_TRAITS) + StructTraits<mojo_base::mojom::FileInfoDataView, base::File::Info> { + static int64_t size(const base::File::Info& info) { return info.size; } + + static bool is_directory(const base::File::Info& info) { + return info.is_directory; + } + + static bool is_symbolic_link(const base::File::Info& info) { + return info.is_symbolic_link; + } + + static base::Time last_modified(const base::File::Info& info) { + return info.last_modified; + } + + static base::Time last_accessed(const base::File::Info& info) { + return info.last_accessed; + } + + static base::Time creation_time(const base::File::Info& info) { + return info.creation_time; + } + + static bool Read(mojo_base::mojom::FileInfoDataView data, + base::File::Info* out); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BASE_FILE_INFO_MOJOM_TRAITS_H_
diff --git a/mojo/public/cpp/base/logfont_win.typemap b/mojo/public/cpp/base/logfont_win.typemap index 43cdc1e..daaf6fcc 100644 --- a/mojo/public/cpp/base/logfont_win.typemap +++ b/mojo/public/cpp/base/logfont_win.typemap
@@ -3,10 +3,16 @@ # found in the LICENSE file. mojom = "//mojo/public/mojom/base/logfont_win.mojom" -os_whitelist = [ "win" ] -public_headers = [ "//base/win/windows_full.h" ] -traits_headers = [ "//ipc/ipc_message_utils.h" ] +public_headers = [ + "//base/win/windows_full.h", + "//base/win/windows_types.h", +] +traits_headers = [ "//mojo/public/cpp/base/logfont_win_mojom_traits.h" ] public_deps = [ - "//ipc", + "//base", +] +sources = [ + "//mojo/public/cpp/base/logfont_win_mojom_traits.cc", + "//mojo/public/cpp/base/logfont_win_mojom_traits.h", ] type_mappings = [ "mojo_base.mojom.LOGFONT=::LOGFONT" ]
diff --git a/mojo/public/cpp/base/logfont_win_mojom_traits.cc b/mojo/public/cpp/base/logfont_win_mojom_traits.cc new file mode 100644 index 0000000..3c73701c --- /dev/null +++ b/mojo/public/cpp/base/logfont_win_mojom_traits.cc
@@ -0,0 +1,39 @@ +// 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. + +#include "mojo/public/cpp/base/logfont_win_mojom_traits.h" + +#include <tchar.h> + +#include "base/logging.h" +#include "base/numerics/safe_conversions.h" + +namespace mojo { + +// static +base::span<const uint8_t> +StructTraits<mojo_base::mojom::LOGFONTDataView, ::LOGFONT>::bytes( + const ::LOGFONT& input) { + return base::make_span(reinterpret_cast<const uint8_t*>(&input), + sizeof(::LOGFONT)); +} + +// static +bool StructTraits<mojo_base::mojom::LOGFONTDataView, ::LOGFONT>::Read( + mojo_base::mojom::LOGFONTDataView data, + ::LOGFONT* out) { + ArrayDataView<uint8_t> bytes_view; + data.GetBytesDataView(&bytes_view); + if (bytes_view.size() != sizeof(::LOGFONT)) + return false; + + const ::LOGFONT* font = reinterpret_cast<const ::LOGFONT*>(bytes_view.data()); + if (_tcsnlen(font->lfFaceName, LF_FACESIZE) >= LF_FACESIZE) + return false; + + memcpy(out, font, sizeof(::LOGFONT)); + return true; +} + +} // namespace mojo
diff --git a/mojo/public/cpp/base/logfont_win_mojom_traits.h b/mojo/public/cpp/base/logfont_win_mojom_traits.h new file mode 100644 index 0000000..09a9fbb --- /dev/null +++ b/mojo/public/cpp/base/logfont_win_mojom_traits.h
@@ -0,0 +1,30 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BASE_LOGFONT_WIN_MOJOM_TRAITS_H_ +#define MOJO_PUBLIC_CPP_BASE_LOGFONT_WIN_MOJOM_TRAITS_H_ + +#include <windows.h> + +#include <cstdint> + +#include "base/component_export.h" +#include "base/containers/span.h" +#include "base/macros.h" +#include "base/win/windows_types.h" +#include "mojo/public/cpp/bindings/struct_traits.h" +#include "mojo/public/mojom/base/logfont_win.mojom-shared.h" + +namespace mojo { + +template <> +struct COMPONENT_EXPORT(MOJO_BASE_MOJOM) + StructTraits<mojo_base::mojom::LOGFONTDataView, ::LOGFONT> { + static base::span<const uint8_t> bytes(const ::LOGFONT& input); + static bool Read(mojo_base::mojom::LOGFONTDataView data, ::LOGFONT* out); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BASE_LOGFONT_WIN_MOJOM_TRAITS_H_
diff --git a/mojo/public/cpp/base/time.typemap b/mojo/public/cpp/base/time.typemap index b3b2e8b..ecd6a27 100644 --- a/mojo/public/cpp/base/time.typemap +++ b/mojo/public/cpp/base/time.typemap
@@ -5,12 +5,9 @@ mojom = "//mojo/public/mojom/base/time.mojom" public_headers = [ "//base/time/time.h" ] traits_headers = [ "//mojo/public/cpp/base/time_mojom_traits.h" ] -sources = [ - "//mojo/public/cpp/base/time_mojom_traits.cc", - "//mojo/public/cpp/base/time_mojom_traits.h", -] public_deps = [ "//base", + "//mojo/public/cpp/base:shared_typemap_traits", ] type_mappings = [
diff --git a/mojo/public/cpp/base/time_mojom_traits.h b/mojo/public/cpp/base/time_mojom_traits.h index db54476..213c6e2 100644 --- a/mojo/public/cpp/base/time_mojom_traits.h +++ b/mojo/public/cpp/base/time_mojom_traits.h
@@ -12,7 +12,7 @@ namespace mojo { template <> -struct COMPONENT_EXPORT(MOJO_BASE_MOJOM) +struct COMPONENT_EXPORT(MOJO_BASE_SHARED_TRAITS) StructTraits<mojo_base::mojom::TimeDataView, base::Time> { static int64_t internal_value(const base::Time& time); @@ -20,7 +20,7 @@ }; template <> -struct COMPONENT_EXPORT(MOJO_BASE_MOJOM) +struct COMPONENT_EXPORT(MOJO_BASE_SHARED_TRAITS) StructTraits<mojo_base::mojom::TimeDeltaDataView, base::TimeDelta> { static int64_t microseconds(const base::TimeDelta& delta); @@ -29,7 +29,7 @@ }; template <> -struct COMPONENT_EXPORT(MOJO_BASE_MOJOM) +struct COMPONENT_EXPORT(MOJO_BASE_SHARED_TRAITS) StructTraits<mojo_base::mojom::TimeTicksDataView, base::TimeTicks> { static int64_t internal_value(const base::TimeTicks& time);
diff --git a/mojo/public/cpp/system/simple_watcher.cc b/mojo/public/cpp/system/simple_watcher.cc index 7b9f079..6384c1ab 100644 --- a/mojo/public/cpp/system/simple_watcher.cc +++ b/mojo/public/cpp/system/simple_watcher.cc
@@ -206,22 +206,21 @@ MojoResult SimpleWatcher::Arm(MojoResult* ready_result, HandleSignalsState* ready_state) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - uint32_t num_ready_contexts = 1; - uintptr_t ready_context; - MojoResult local_ready_result; - HandleSignalsState local_ready_state; - if (!ready_state) - ready_state = &local_ready_state; - MojoResult rv = - MojoArmTrap(trap_handle_.get().value(), nullptr, &num_ready_contexts, - &ready_context, &local_ready_result, - reinterpret_cast<MojoHandleSignalsState*>(ready_state)); + uint32_t num_blocking_events = 1; + MojoTrapEvent blocking_event = {sizeof(blocking_event)}; + MojoResult rv = MojoArmTrap(trap_handle_.get().value(), nullptr, + &num_blocking_events, &blocking_event); if (rv == MOJO_RESULT_FAILED_PRECONDITION) { DCHECK(context_); - DCHECK_EQ(1u, num_ready_contexts); - DCHECK_EQ(context_->value(), ready_context); + DCHECK_EQ(1u, num_blocking_events); + DCHECK_EQ(context_->value(), blocking_event.trigger_context); if (ready_result) - *ready_result = local_ready_result; + *ready_result = blocking_event.result; + if (ready_state) { + *ready_state = + HandleSignalsState(blocking_event.signals_state.satisfied_signals, + blocking_event.signals_state.satisfiable_signals); + } } return rv;
diff --git a/mojo/public/cpp/system/wait.cc b/mojo/public/cpp/system/wait.cc index a1aa4bc1..8defafe4 100644 --- a/mojo/public/cpp/system/wait.cc +++ b/mojo/public/cpp/system/wait.cc
@@ -87,23 +87,21 @@ } DCHECK_EQ(MOJO_RESULT_OK, rv); - uint32_t num_ready_contexts = 1; - uintptr_t ready_context; - MojoResult ready_result; - MojoHandleSignalsState ready_state; - rv = MojoArmTrap(trap.get().value(), nullptr, &num_ready_contexts, - &ready_context, &ready_result, &ready_state); + uint32_t num_blocking_events = 1; + MojoTrapEvent blocking_event = {sizeof(blocking_event)}; + rv = MojoArmTrap(trap.get().value(), nullptr, &num_blocking_events, + &blocking_event); if (rv == MOJO_RESULT_FAILED_PRECONDITION) { - DCHECK_EQ(1u, num_ready_contexts); + DCHECK_EQ(1u, num_blocking_events); if (signals_state) - *signals_state = ready_state; - return ready_result; + *signals_state = blocking_event.signals_state; + return blocking_event.result; } // Wait for the first notification only. context->event().Wait(); - ready_result = context->wait_result(); + MojoResult ready_result = context->wait_result(); DCHECK_NE(MOJO_RESULT_UNKNOWN, ready_result); if (signals_state) @@ -150,22 +148,24 @@ events[i] = &contexts[i]->event(); } - uint32_t num_ready_contexts = 1; - uintptr_t ready_context = 0; - MojoResult ready_result = MOJO_RESULT_UNKNOWN; - MojoHandleSignalsState ready_state{0, 0}; - rv = MojoArmTrap(trap.get().value(), nullptr, &num_ready_contexts, - &ready_context, &ready_result, &ready_state); + uint32_t num_blocking_events = 1; + MojoTrapEvent blocking_event = {sizeof(blocking_event)}; + rv = MojoArmTrap(trap.get().value(), nullptr, &num_blocking_events, + &blocking_event); size_t index = num_handles; + MojoResult ready_result = MOJO_RESULT_UNKNOWN; + MojoHandleSignalsState ready_state = {}; if (rv == MOJO_RESULT_FAILED_PRECONDITION) { - DCHECK_EQ(1u, num_ready_contexts); + DCHECK_EQ(1u, num_blocking_events); // Most commonly we only watch a small number of handles. Just scan for // the right index. for (size_t i = 0; i < num_handles; ++i) { - if (contexts[i]->context_value() == ready_context) { + if (contexts[i]->context_value() == blocking_event.trigger_context) { index = i; + ready_result = blocking_event.result; + ready_state = blocking_event.signals_state; break; } }
diff --git a/mojo/public/cpp/system/wait_set.cc b/mojo/public/cpp/system/wait_set.cc index 3ad9840..cd8b859 100644 --- a/mojo/public/cpp/system/wait_set.cc +++ b/mojo/public/cpp/system/wait_set.cc
@@ -145,22 +145,18 @@ handle_event_.Reset(); DCHECK_LE(*num_ready_handles, std::numeric_limits<uint32_t>::max()); - uint32_t num_ready_contexts = static_cast<uint32_t>(*num_ready_handles); + uint32_t num_blocking_events = + static_cast<uint32_t>(*num_ready_handles); - base::StackVector<uintptr_t, 4> ready_contexts; - ready_contexts.container().resize(num_ready_contexts); - base::StackVector<MojoHandleSignalsState, 4> ready_states; - MojoHandleSignalsState* out_states = signals_states; - if (!out_states) { - // If the caller didn't provide a buffer for signal states, we provide - // our own locally. MojoArmTrap() requires one if we want to handle - // arming failure properly. - ready_states.container().resize(num_ready_contexts); - out_states = ready_states.container().data(); + base::StackVector<MojoTrapEvent, 4> blocking_events; + blocking_events.container().resize(num_blocking_events); + for (size_t i = 0; i < num_blocking_events; ++i) { + blocking_events.container()[i].struct_size = + sizeof(blocking_events.container()[i]); } - MojoResult rv = MojoArmTrap( - trap_handle_.get().value(), nullptr, &num_ready_contexts, - ready_contexts.container().data(), ready_results, out_states); + MojoResult rv = MojoArmTrap(trap_handle_.get().value(), nullptr, + &num_blocking_events, + blocking_events.container().data()); if (rv == MOJO_RESULT_FAILED_PRECONDITION) { // Simulate the handles becoming ready. We do this in lieu of @@ -168,11 +164,12 @@ // starving user events. i.e., we always want to call WaitMany() // below. handle_event_.Signal(); - for (size_t i = 0; i < num_ready_contexts; ++i) { - auto it = contexts_.find(ready_contexts.container()[i]); + for (size_t i = 0; i < num_blocking_events; ++i) { + const auto& event = blocking_events.container()[i]; + auto it = contexts_.find(event.trigger_context); DCHECK(it != contexts_.end()); - ready_handles_[it->second->handle()] = {ready_results[i], - out_states[i]}; + ready_handles_[it->second->handle()] = {event.result, + event.signals_state}; } } else if (rv == MOJO_RESULT_NOT_FOUND) { // Nothing to watch. If there are no user events, always signal to
diff --git a/mojo/public/mojom/base/file_info.mojom b/mojo/public/mojom/base/file_info.mojom index 544f291..5dff3ca 100644 --- a/mojo/public/mojom/base/file_info.mojom +++ b/mojo/public/mojom/base/file_info.mojom
@@ -4,5 +4,14 @@ module mojo_base.mojom; -[Native] -struct FileInfo; +import "mojo/public/mojom/base/time.mojom"; + +// Corresponds to base::File::Info. +struct FileInfo { + int64 size; + bool is_directory; + bool is_symbolic_link; + Time last_modified; + Time last_accessed; + Time creation_time; +};
diff --git a/mojo/public/mojom/base/logfont_win.mojom b/mojo/public/mojom/base/logfont_win.mojom index 81beefa..27922b8 100644 --- a/mojo/public/mojom/base/logfont_win.mojom +++ b/mojo/public/mojom/base/logfont_win.mojom
@@ -5,5 +5,7 @@ module mojo_base.mojom; // Native Windows struct. Its typemap only exists for windows builds. -[Native] -struct LOGFONT; +[EnableIf=is_win] +struct LOGFONT { + array<uint8> bytes; +};
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni index 5e1df16..e0e9e23 100644 --- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni +++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -24,6 +24,7 @@ "//device/bluetooth/public/mojom/test/typemaps.gni", "//device/gamepad/public/cpp/typemaps.gni", "//gpu/ipc/common/typemaps.gni", + "//ipc/typemaps.gni", "//media/capture/mojom/typemaps.gni", "//media/mojo/interfaces/typemaps.gni", "//mojo/public/cpp/base/typemaps.gni",
diff --git a/net/disk_cache/simple/simple_index_unittest.cc b/net/disk_cache/simple/simple_index_unittest.cc index d3ac5f9..2a68b3a8 100644 --- a/net/disk_cache/simple/simple_index_unittest.cc +++ b/net/disk_cache/simple/simple_index_unittest.cc
@@ -735,11 +735,9 @@ index()->Insert(kHash1); index()->UpdateEntrySize(kHash1, 20u); EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning()); - base::Closure user_task(index()->write_to_disk_timer_.user_task()); - index()->write_to_disk_timer_.Stop(); EXPECT_EQ(0, index_file_->disk_writes()); - user_task.Run(); + index()->write_to_disk_timer_.FireNow(); EXPECT_EQ(1, index_file_->disk_writes()); SimpleIndex::EntrySet entry_set; index_file_->GetAndResetDiskWriteEntrySet(&entry_set);
diff --git a/services/ui/ws2/BUILD.gn b/services/ui/ws2/BUILD.gn index 2efc6d8..95009d1 100644 --- a/services/ui/ws2/BUILD.gn +++ b/services/ui/ws2/BUILD.gn
@@ -165,6 +165,7 @@ "focus_handler_unittest.cc", "screen_provider_unittest.cc", "user_activity_monitor_unittest.cc", + "window_delegate_impl_unittest.cc", "window_service_unittest.cc", "window_tree_client_unittest.cc", "window_tree_unittest.cc",
diff --git a/services/ui/ws2/server_window.cc b/services/ui/ws2/server_window.cc index 56f80a38..03ccf990 100644 --- a/services/ui/ws2/server_window.cc +++ b/services/ui/ws2/server_window.cc
@@ -486,11 +486,6 @@ return owning_window_tree_ && owning_window_tree_->IsTopLevel(window_); } -void ServerWindow::SetDragDropDelegate( - std::unique_ptr<DragDropDelegate> drag_drop_delegate) { - drag_drop_delegate_ = std::move(drag_drop_delegate); -} - void ServerWindow::AttachCompositorFrameSink( viz::mojom::CompositorFrameSinkRequest compositor_frame_sink, viz::mojom::CompositorFrameSinkClientPtr client) { @@ -502,6 +497,17 @@ frame_sink_id_, std::move(compositor_frame_sink), std::move(client)); } +void ServerWindow::SetDragDropDelegate( + std::unique_ptr<DragDropDelegate> drag_drop_delegate) { + drag_drop_delegate_ = std::move(drag_drop_delegate); +} + +std::string ServerWindow::GetIdForDebugging() { + return owning_window_tree_ + ? owning_window_tree_->ClientWindowIdForWindow(window_).ToString() + : frame_sink_id_.ToString(); +} + ServerWindow::ServerWindow(aura::Window* window, WindowTree* tree, const viz::FrameSinkId& frame_sink_id,
diff --git a/services/ui/ws2/server_window.h b/services/ui/ws2/server_window.h index 42487ae..eb7d79f 100644 --- a/services/ui/ws2/server_window.h +++ b/services/ui/ws2/server_window.h
@@ -5,6 +5,7 @@ #ifndef SERVICES_UI_WS2_SERVER_WINDOW_H_ #define SERVICES_UI_WS2_SERVER_WINDOW_H_ +#include <string> #include <vector> #include "base/component_export.h" @@ -118,6 +119,10 @@ void SetDragDropDelegate( std::unique_ptr<DragDropDelegate> drag_drop_delegate); + // Returns an id useful for debugging. This returns the id from the client + // that created the window, otherwise |frame_sink_id_|. + std::string GetIdForDebugging(); + private: friend class ServerWindowTestHelper;
diff --git a/services/ui/ws2/window_delegate_impl_unittest.cc b/services/ui/ws2/window_delegate_impl_unittest.cc new file mode 100644 index 0000000..554b38a --- /dev/null +++ b/services/ui/ws2/window_delegate_impl_unittest.cc
@@ -0,0 +1,38 @@ +// 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. + +#include "services/ui/ws2/window_delegate_impl.h" + +#include "services/ui/ws2/test_window_service_delegate.h" +#include "services/ui/ws2/window_service_test_setup.h" +#include "services/ui/ws2/window_tree_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/aura/window.h" +#include "ui/base/cursor/cursor_data.h" +#include "ui/base/cursor/cursor_type.h" +#include "ui/gfx/geometry/point.h" + +namespace ui { +namespace ws2 { + +TEST(WindowDeleteImplTest, GetCursorTopLevel) { + WindowServiceTestSetup setup; + // WindowDelegateImpl deletes itself when the window is deleted. + WindowDelegateImpl* delegate = new WindowDelegateImpl(); + setup.delegate()->set_delegate_for_next_top_level(delegate); + aura::Window* top_level = + setup.window_tree_test_helper()->NewTopLevelWindow(); + delegate->set_window(top_level); + // Verify no crash when no cursor has been set. + top_level->GetCursor(gfx::Point()); + + // Set a cursor and ensure we get it back. + const ui::CursorData help_cursor(ui::CursorType::kHelp); + setup.window_tree_test_helper()->SetCursor(top_level, help_cursor); + EXPECT_EQ(help_cursor.cursor_type(), + top_level->GetCursor(gfx::Point()).native_type()); +} + +} // namespace ws2 +} // namespace ui
diff --git a/services/ui/ws2/window_service.cc b/services/ui/ws2/window_service.cc index f4b0e91..8bf1d36 100644 --- a/services/ui/ws2/window_service.cc +++ b/services/ui/ws2/window_service.cc
@@ -81,7 +81,7 @@ } // static -bool WindowService::HasRemoteClient(aura::Window* window) { +bool WindowService::HasRemoteClient(const aura::Window* window) { return ServerWindow::GetMayBeNull(window); } @@ -95,6 +95,13 @@ server_window->owning_window_tree()->RequestClose(server_window); } +std::string WindowService::GetIdForDebugging(aura::Window* window) { + ServerWindow* server_window = ServerWindow::GetMayBeNull(window); + if (!server_window) + return std::string(); + return server_window->GetIdForDebugging(); +} + void WindowService::OnStart() { window_tree_factory_ = std::make_unique<WindowTreeFactory>(this);
diff --git a/services/ui/ws2/window_service.h b/services/ui/ws2/window_service.h index 9f598918..615d561 100644 --- a/services/ui/ws2/window_service.h +++ b/services/ui/ws2/window_service.h
@@ -7,6 +7,7 @@ #include <memory> #include <set> +#include <string> #include "base/component_export.h" #include "base/macros.h" @@ -77,7 +78,7 @@ int max_title_bar_button_width); // Whether |window| hosts a remote client. - static bool HasRemoteClient(aura::Window* window); + static bool HasRemoteClient(const aura::Window* window); WindowServiceDelegate* delegate() { return delegate_; } @@ -96,6 +97,10 @@ // a top-level window. void RequestClose(aura::Window* window); + // Returns an id useful for debugging. See ServerWindow::GetIdForDebugging() + // for details. + std::string GetIdForDebugging(aura::Window* window); + // service_manager::Service: void OnStart() override; void OnBindInterface(const service_manager::BindSourceInfo& remote_info,
diff --git a/services/ui/ws2/window_tree.cc b/services/ui/ws2/window_tree.cc index d255c53..63de3e2 100644 --- a/services/ui/ws2/window_tree.cc +++ b/services/ui/ws2/window_tree.cc
@@ -186,6 +186,12 @@ DeleteClientRoot(iter->get(), DeleteClientRootReason::kDeleted); } +ClientWindowId WindowTree::ClientWindowIdForWindow(aura::Window* window) { + auto iter = window_to_client_window_id_map_.find(window); + return iter == window_to_client_window_id_map_.end() ? ClientWindowId() + : iter->second; +} + ClientRoot* WindowTree::CreateClientRoot(aura::Window* window, bool is_top_level) { DCHECK(window); @@ -588,18 +594,23 @@ bool WindowTree::DeleteWindowImpl(const ClientWindowId& window_id) { aura::Window* window = GetWindowByClientId(window_id); DVLOG(3) << "deleting window client=" << client_id_ - << " client window_id= " << window_id.ToString(); - if (!window) + << " client window_id=" << window_id.ToString(); + if (!window) { + DVLOG(1) << "DeleteWindow failed (no window)"; return false; + } + const bool is_client_created_window = IsClientCreatedWindow(window); auto iter = FindClientRootWithRoot(window); if (iter != client_roots_.end()) { DeleteClientRoot(iter->get(), DeleteClientRootReason::kUnembed); - return true; - } - - if (!IsClientCreatedWindow(window)) + if (!is_client_created_window) + return true; + // If client created, fall through to delete window. + } else if (!is_client_created_window) { + DVLOG(1) << "DeleteWindow failed (client did not create window)"; return false; + } const bool delete_if_owned = true; RemoveWindowFromKnownWindows(window, delete_if_owned); @@ -689,7 +700,7 @@ aura::Window* child = GetWindowByClientId(child_id); DVLOG(3) << "add window client=" << client_id_ << " client parent window_id=" << parent_id.ToString() - << " client child window_id= " << child_id.ToString(); + << " client child window_id=" << child_id.ToString(); if (!parent) { DVLOG(1) << "AddWindow failed (no parent)"; return false; @@ -720,7 +731,7 @@ const ClientWindowId& client_window_id) { aura::Window* window = GetWindowByClientId(client_window_id); DVLOG(3) << "removing window from parent client=" << client_id_ - << " client window_id= " << client_window_id; + << " client window_id=" << client_window_id; if (!window) { DVLOG(1) << "RemoveWindowFromParent failed (invalid window id=" << client_window_id.ToString() << ")"; @@ -743,7 +754,7 @@ bool WindowTree::AddTransientWindowImpl(const ClientWindowId& parent_id, const ClientWindowId& transient_id) { DVLOG(3) << "adding transient window client=" << client_id_ - << " parent_id= " << parent_id << " transient_id=" << transient_id; + << " parent_id=" << parent_id << " transient_id=" << transient_id; aura::Window* parent = GetWindowByClientId(parent_id); aura::Window* transient = GetWindowByClientId(transient_id); if (!parent || !transient) { @@ -794,7 +805,7 @@ bool WindowTree::SetModalTypeImpl(const ClientWindowId& client_window_id, ui::ModalType type) { DVLOG(3) << "setting window modal type client=" << client_id_ - << " client_window_id= " << client_window_id << " type=" << type; + << " client_window_id=" << client_window_id << " type=" << type; aura::Window* window = GetWindowByClientId(client_window_id); if (!window) { DVLOG(1) << "SetModalType failed (invalid window id=" @@ -827,7 +838,7 @@ bool WindowTree::SetChildModalParentImpl(const ClientWindowId& child_id, const ClientWindowId& parent_id) { DVLOG(3) << "setting child window modal parent client=" << client_id_ - << " child_id= " << child_id << " parent_id=" << parent_id; + << " child_id=" << child_id << " parent_id=" << parent_id; aura::Window* child = GetWindowByClientId(child_id); aura::Window* parent = GetWindowByClientId(parent_id); // A value of null for |parent_id| resets the modal parent. @@ -850,7 +861,7 @@ bool visible) { aura::Window* window = GetWindowByClientId(window_id); DVLOG(3) << "SetWindowVisibility client=" << client_id_ - << " client window_id= " << window_id.ToString(); + << " client window_id=" << window_id.ToString(); if (!window) { DVLOG(1) << "SetWindowVisibility failed (no window)"; return false; @@ -875,7 +886,7 @@ const base::Optional<std::vector<uint8_t>>& value) { aura::Window* window = GetWindowByClientId(window_id); DVLOG(3) << "SetWindowProperty client=" << client_id_ - << " client window_id= " << window_id.ToString(); + << " client window_id=" << window_id.ToString(); if (!window) { DVLOG(1) << "SetWindowProperty failed (no window)"; return false; @@ -934,7 +945,7 @@ float opacity) { aura::Window* window = GetWindowByClientId(window_id); DVLOG(3) << "SetWindowOpacity client=" << client_id_ - << " client window_id= " << window_id.ToString(); + << " client window_id=" << window_id.ToString(); if (IsClientCreatedWindow(window) || (IsClientRootWindow(window) && can_change_root_window_visibility_)) { if (window->layer()->opacity() == opacity) @@ -1101,7 +1112,7 @@ } bool WindowTree::StackAtTopImpl(const ClientWindowId& window_id) { - DVLOG(3) << "StackAtTop window_id= " << window_id; + DVLOG(3) << "StackAtTop window_id=" << window_id; aura::Window* window = GetWindowByClientId(window_id); if (!window || !IsTopLevel(window)) {
diff --git a/services/ui/ws2/window_tree.h b/services/ui/ws2/window_tree.h index bb3c1bd..a8ed189 100644 --- a/services/ui/ws2/window_tree.h +++ b/services/ui/ws2/window_tree.h
@@ -95,6 +95,8 @@ WindowService* window_service() { return window_service_; } + ClientWindowId ClientWindowIdForWindow(aura::Window* window); + private: friend class ClientRoot; // TODO(sky): WindowTree should be refactored such that it is not
diff --git a/services/ui/ws2/window_tree_test_helper.cc b/services/ui/ws2/window_tree_test_helper.cc index 7ee157da..2ad8e87 100644 --- a/services/ui/ws2/window_tree_test_helper.cc +++ b/services/ui/ws2/window_tree_test_helper.cc
@@ -160,6 +160,11 @@ window_tree_->OnEmbeddedClientConnectionLost(embedding); } +aura::Window* WindowTreeTestHelper::GetWindowByClientId( + const ClientWindowId& id) { + return window_tree_->GetWindowByClientId(id); +} + ClientWindowId WindowTreeTestHelper::ClientWindowIdForWindow( aura::Window* window) { return window_tree_->MakeClientWindowId(TransportIdForWindow(window));
diff --git a/services/ui/ws2/window_tree_test_helper.h b/services/ui/ws2/window_tree_test_helper.h index ebc9602..ac4ab4787 100644 --- a/services/ui/ws2/window_tree_test_helper.h +++ b/services/ui/ws2/window_tree_test_helper.h
@@ -102,9 +102,10 @@ void DestroyEmbedding(Embedding* embedding); - private: + aura::Window* GetWindowByClientId(const ClientWindowId& id); ClientWindowId ClientWindowIdForWindow(aura::Window* window); + private: WindowTree* window_tree_; // Next id to use for creating a window (including top-level windows).
diff --git a/services/ui/ws2/window_tree_unittest.cc b/services/ui/ws2/window_tree_unittest.cc index 5990590..cc6832c 100644 --- a/services/ui/ws2/window_tree_unittest.cc +++ b/services/ui/ws2/window_tree_unittest.cc
@@ -971,6 +971,29 @@ SingleChangeToDescription(*setup.changes())); } +TEST(WindowTreeTest2, DeleteTopLevel) { + WindowServiceTestSetup setup; + aura::Window* top_level = + setup.window_tree_test_helper()->NewTopLevelWindow(); + const ClientWindowId top_level_id = + setup.window_tree_test_helper()->ClientWindowIdForWindow(top_level); + ASSERT_TRUE(top_level); + aura::WindowTracker tracker; + tracker.Add(top_level); + setup.changes()->clear(); + + // Ask the tree to delete the window, which should result in deleting the + // Window as well responding with success. + setup.window_tree_test_helper()->DeleteWindow(top_level); + EXPECT_TRUE(tracker.windows().empty()); + EXPECT_EQ("ChangeCompleted id=1 success=true", + SingleChangeToDescription(*setup.changes())); + + // Make sure the WindowTree doesn't have a mapping for the id anymore. + EXPECT_FALSE( + setup.window_tree_test_helper()->GetWindowByClientId(top_level_id)); +} + TEST(WindowTreeTest2, ExternalDeleteWindow) { WindowServiceTestSetup setup; aura::Window* window = setup.window_tree_test_helper()->NewWindow();
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 9f73ddc..92cafc3 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -3325,99 +3325,6 @@ } ] }, - "Oreo Phone Tester": { - "gtest_tests": [ - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "chrome_public_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "OPR3.170623.008", - "device_type": "marlin", - "os": "Android" - } - ], - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "shards": 5 - }, - "test": "chrome_public_test_apk" - }, - { - "args": [ - "--gs-results-bucket=chromium-result-details", - "--recover-devices" - ], - "merge": { - "args": [ - "--bucket", - "chromium-result-details", - "--test-name", - "webview_instrumentation_test_apk" - ], - "script": "//build/android/pylib/results/presentation/test_results_presentation.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/luci/logdog/butler/${platform}", - "location": "bin", - "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" - } - ], - "dimension_sets": [ - { - "device_os": "OPR3.170623.008", - "device_type": "marlin", - "os": "Android" - } - ], - "expiration": 10800, - "output_links": [ - { - "link": [ - "https://luci-logdog.appspot.com/v/?s", - "=android%2Fswarming%2Flogcats%2F", - "${TASK_ID}%2F%2B%2Funified_logcats" - ], - "name": "shard #${SHARD_INDEX} logcats" - } - ], - "shards": 5 - }, - "test": "webview_instrumentation_test_apk" - } - ] - }, "Unswarmed N5 Tests Dummy Builder": { "gtest_tests": [ {
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 112ae15f..28e1d8a5 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -16495,6 +16495,100 @@ } ] }, + "Oreo Phone Tester": { + "gtest_tests": [ + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], + "experiment_percentage": 100, + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "chrome_public_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "device_os": "OPR3.170623.008", + "device_type": "marlin", + "os": "Android" + } + ], + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "shards": 5 + }, + "test": "chrome_public_test_apk" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "webview_instrumentation_test_apk" + ], + "script": "//build/android/pylib/results/presentation/test_results_presentation.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "cipd_packages": [ + { + "cipd_package": "infra/tools/luci/logdog/butler/${platform}", + "location": "bin", + "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c" + } + ], + "dimension_sets": [ + { + "device_os": "OPR3.170623.008", + "device_type": "marlin", + "os": "Android" + } + ], + "expiration": 10800, + "output_links": [ + { + "link": [ + "https://luci-logdog.appspot.com/v/?s", + "=android%2Fswarming%2Flogcats%2F", + "${TASK_ID}%2F%2B%2Funified_logcats" + ], + "name": "shard #${SHARD_INDEX} logcats" + } + ], + "shards": 5 + }, + "test": "webview_instrumentation_test_apk" + } + ] + }, "android-kitkat-arm-rel": { "additional_compile_targets": [ "cronet_test_instrumentation_apk",
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter index 424a2cdf..7e11f2b 100644 --- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter +++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -247,6 +247,11 @@ # Added in r519342. -PreviewsNoScriptBrowserTest.NoScriptPreviewsEnabledHttpRedirectToHttps -PreviewsNoScriptBrowserTest.NoScriptPreviewsEnabledButNoTransformDirective +-ResourceLoadingHintsBrowserTest.ResourceLoadingHintsHttpsWhitelisted +-ResourceLoadingHintsBrowserTest.ResourceLoadingHintsHttpsWhitelistedRedirectToHttps +-ResourceLoadingHintsBrowserTest.ResourceLoadingHintsHttpsWhitelistedNoTransform +-ResourceLoadingHintsBrowserTest.ResourceLoadingHintsHttp +-ResourceLoadingHintsBrowserTest.ResourceLoadingHintsHttpsNoWhitelisted # crbug.com/778860 SecurityStyleExplanations::info_explanations is empty. -BrowserTestNonsecureURLRequest.DidChangeVisibleSecurityStateObserverObsoleteTLSSettings
diff --git a/testing/buildbot/filters/viz.android.content_browsertests.filter b/testing/buildbot/filters/viz.android.content_browsertests.filter index 982fafd7..3216603f 100644 --- a/testing/buildbot/filters/viz.android.content_browsertests.filter +++ b/testing/buildbot/filters/viz.android.content_browsertests.filter
@@ -19,6 +19,7 @@ # InputEventAckWaiter never receives the event: https://crbug.com/848348 -SitePerProcessHitTestBrowserTest.CrossProcessMouseEnterAndLeaveTest* -SitePerProcessHitTestBrowserTest.CrossProcessMouseCapture* +-SitePerProcessHitTestBrowserTest.TouchpadPinchOverOOPIF* # /2 Variant does not handle overlapping surfaces: https://crbug.com/846798 --SitePerProcessHitTestBrowserTest.HitTestStaleDataDeletedView* \ No newline at end of file +-SitePerProcessHitTestBrowserTest.HitTestStaleDataDeletedView*
diff --git a/testing/buildbot/filters/viz.content_browsertests.filter b/testing/buildbot/filters/viz.content_browsertests.filter index 7749b7e..1bc69ef 100644 --- a/testing/buildbot/filters/viz.content_browsertests.filter +++ b/testing/buildbot/filters/viz.content_browsertests.filter
@@ -9,6 +9,7 @@ # InputEventAckWaiter never receives the event: https://crbug.com/848348 -SitePerProcessHitTestBrowserTest.CrossProcessMouseEnterAndLeaveTest* -SitePerProcessHitTestBrowserTest.CrossProcessMouseCapture* +-SitePerProcessHitTestBrowserTest.TouchpadPinchOverOOPIF* ### Mac # BrowserSideFlingBrowserTest timing out https://crbug.com/842325
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index b3bc099..7ce28629 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -419,6 +419,9 @@ 'hard_timeout': 1800, }, }, + 'Oreo Phone Tester': { + 'experiment_percentage': 100, + }, # chromium.android.fyi 'Nougat Phone Tester': { 'swarming': {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 80e2d1a..8fc5d0f84 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -325,6 +325,21 @@ 'skip_output_links': True, 'os_type': 'android', }, + 'Oreo Phone Tester': { + 'swarming': { + 'dimension_sets': [ + { + 'device_os': 'OPR3.170623.008', + 'device_type': 'marlin', + 'os': 'Android', + }, + ], + }, + 'os_type': 'android', + 'test_suites': { + 'gtest_tests': 'android_oreo_gtests', + }, + }, }, }, { @@ -403,21 +418,6 @@ 'gtest_tests': 'chromium_android_gtests', }, }, - 'Oreo Phone Tester': { - 'swarming': { - 'dimension_sets': [ - { - 'device_os': 'OPR3.170623.008', - 'device_type': 'marlin', - 'os': 'Android', - }, - ], - }, - 'os_type': 'android', - 'test_suites': { - 'gtest_tests': 'android_oreo_gtests', - }, - }, 'Unswarmed N5 Tests Dummy Builder': { 'os_type': 'android', 'use_swarming': False,
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService index 08b0215..7a0b5c8 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -7,21 +7,18 @@ crbug.com/829417 external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Timeout ] crbug.com/771118 external/wpt/service-workers/service-worker/mime-sniffing.https.html [ Failure ] -# Passes on NetworkService and fails on non-NetworkService because -# NetworkService isn't affected by https://crbug.com/595993. -Bug(none) external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Pass ] -crbug.com/830472 external/wpt/service-workers/service-worker/navigation-preload/broken-chunked-encoding.https.html [ Pass ] - Bug(none) http/tests/misc/redirect-to-about-blank.html [ Timeout ] Bug(none) http/tests/security/cors-rfc1918 [ Crash Timeout ] Bug(none) http/tests/security/mime-type-execute-as-html-01.html [ Failure ] Bug(none) http/tests/security/mime-type-execute-as-html-04.html [ Failure ] Bug(none) http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin.html [ Pass Timeout ] -# Only passes with Network Servce enabled (unfortunately this expectation still -# allows Timeout from the top-level exctations though). +# Only passes with Network Servce enabled (unfortunately these expectations still +# allow Failure or Timeout from the top-level expectations though). crbug.com/800898 external/wpt/FileAPI/url/url-in-tags-revoke.window.html [ Pass ] crbug.com/800898 external/wpt/workers/worker-from-blob-url.window.html [ Pass ] +crbug.com/595993 external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Pass ] +crbug.com/862886 external/wpt/service-workers/service-worker/navigation-preload/broken-chunked-encoding.https.html [ Pass ] # Flaky on non-NetworkService (disabled), consistent failing on NetworkService. Probably due to DCHECK. crbug.com/849670 http/tests/devtools/service-workers/service-worker-v8-cache.js [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 5beaaf4b..4dc48cf0 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -4168,7 +4168,7 @@ crbug.com/807838 external/wpt/service-workers/service-worker/worker-in-sandboxed-iframe-by-csp-fetch-event.https.html [ Crash Pass ] crbug.com/807838 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/worker-in-sandboxed-iframe-by-csp-fetch-event.https.html [ Crash Pass ] -crbug.com/830472 external/wpt/service-workers/service-worker/navigation-preload/broken-chunked-encoding.https.html [ Failure ] +crbug.com/862886 external/wpt/service-workers/service-worker/navigation-preload/broken-chunked-encoding.https.html [ Failure ] # Sheriff faulures 2017-12-12 crbug.com/794180 http/tests/devtools/layers/layer-compositing-reasons.js [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json index 7921435..929ec848 100644 --- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json +++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -401909,11 +401909,11 @@ "testharness" ], "streams/piping/close-propagation-forward-expected.txt": [ - "6997b4baf781148d3e3173f04ff4636fee85cd4a", + "1d9fa306a29f01252576841a21169b61cb6316fd", "support" ], "streams/piping/close-propagation-forward.dedicatedworker-expected.txt": [ - "6997b4baf781148d3e3173f04ff4636fee85cd4a", + "1d9fa306a29f01252576841a21169b61cb6316fd", "support" ], "streams/piping/close-propagation-forward.dedicatedworker.html": [ @@ -401925,11 +401925,11 @@ "testharness" ], "streams/piping/close-propagation-forward.js": [ - "7840ff0fabf15c8c86b91fbc57a8fca105af4c91", + "37d526eb7789e298fe24a4c1e4545803b8cf1d0b", "support" ], "streams/piping/close-propagation-forward.serviceworker.https-expected.txt": [ - "3d773b1f58442f5f40ffcaa75249c564d8007ab6", + "f2ffdb9a0ad18a8321d9781d616e2a1b1d3ec0a1", "support" ], "streams/piping/close-propagation-forward.serviceworker.https.html": [ @@ -401937,7 +401937,7 @@ "testharness" ], "streams/piping/close-propagation-forward.sharedworker-expected.txt": [ - "6997b4baf781148d3e3173f04ff4636fee85cd4a", + "1d9fa306a29f01252576841a21169b61cb6316fd", "support" ], "streams/piping/close-propagation-forward.sharedworker.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward-expected.txt index 97077ba..5cf58c20 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward-expected.txt
@@ -28,5 +28,6 @@ FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true assert_equals: the pipe must not be complete expected false but got true PASS Closing must be propagated forward: shutdown must not occur until the final write completes; becomes closed after first write FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; becomes closed after first write; preventClose = true assert_false: the pipe should not complete while the second write is pending expected false got true +PASS Closing must be propagated forward: erroring the writable while flushing pending writes should error pipeTo Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.dedicatedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.dedicatedworker-expected.txt index 97077ba..5cf58c20 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.dedicatedworker-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.dedicatedworker-expected.txt
@@ -28,5 +28,6 @@ FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true assert_equals: the pipe must not be complete expected false but got true PASS Closing must be propagated forward: shutdown must not occur until the final write completes; becomes closed after first write FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; becomes closed after first write; preventClose = true assert_false: the pipe should not complete while the second write is pending expected false got true +PASS Closing must be propagated forward: erroring the writable while flushing pending writes should error pipeTo Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.js b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.js index 0f0b7bb..9b1546d 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.js +++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.js
@@ -559,4 +559,36 @@ }, 'Closing must be propagated forward: shutdown must not occur until the final write completes; becomes closed after first write; preventClose = true'); + +promise_test(t => { + const rs = recordingReadableStream({ + start(c) { + c.enqueue('a'); + c.enqueue('b'); + c.close(); + } + }); + let rejectWritePromise; + const ws = recordingWritableStream({ + write() { + return new Promise((resolve, reject) => { + rejectWritePromise = reject; + }); + } + }, { highWaterMark: 3 }); + const pipeToPromise = rs.pipeTo(ws); + return delay(0).then(() => { + rejectWritePromise(error1); + return promise_rejects(t, error1, pipeToPromise, 'pipeTo should reject'); + }).then(() => { + assert_array_equals(rs.events, []); + assert_array_equals(ws.events, ['write', 'a']); + + return Promise.all([ + rs.getReader().closed, + promise_rejects(t, error1, ws.getWriter().closed, 'ws should be errored') + ]); + }); +}, 'Closing must be propagated forward: erroring the writable while flushing pending writes should error pipeTo'); + done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.serviceworker.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.serviceworker.https-expected.txt index 824b9f2b2..6411512 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.serviceworker.https-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.serviceworker.https-expected.txt
@@ -29,5 +29,6 @@ FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true assert_equals: the pipe must not be complete expected false but got true PASS Closing must be propagated forward: shutdown must not occur until the final write completes; becomes closed after first write FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; becomes closed after first write; preventClose = true assert_false: the pipe should not complete while the second write is pending expected false got true +PASS Closing must be propagated forward: erroring the writable while flushing pending writes should error pipeTo Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.sharedworker-expected.txt index 97077ba..5cf58c20 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.sharedworker-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.sharedworker-expected.txt
@@ -28,5 +28,6 @@ FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true assert_equals: the pipe must not be complete expected false but got true PASS Closing must be propagated forward: shutdown must not occur until the final write completes; becomes closed after first write FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; becomes closed after first write; preventClose = true assert_false: the pipe should not complete while the second write is pending expected false got true +PASS Closing must be propagated forward: erroring the writable while flushing pending writes should error pipeTo Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/foreign-object-margin-collapsing.html b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/foreign-object-margin-collapsing.html new file mode 100644 index 0000000..49320f9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/svg/extensibility/foreignObject/foreign-object-margin-collapsing.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="https://svgwg.org/svg2-draft/single-page.html#embedded-ForeignObjectElement"> +<link rel="help" href="https://www.w3.org/TR/CSS22/box.html#collapsing-margins"> +<link rel="match" href="foreign-object-size-ref.html"> +<svg> + <foreignobject width="100" height="100" style="background:red;"> + <div style="margin:100px 0;"> + <div style="margin:100px 0;"></div> + </div> + <div style="margin:100px 0;"> + <div style="margin:100px 0;"></div> + </div> + <div style="margin-top:-100px; height:100px; background:green;"></div> + </foreignobject> +</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webvr/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/webvr/OWNERS index 4c90338..f514e5d4 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/webvr/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/webvr/OWNERS
@@ -1 +1,5 @@ file://third_party/blink/renderer/modules/vr/OWNERS + +# TEAM: xr-dev@chromium.org +# COMPONENT: Blink>WebXR>VR +# WPT-NOTIFY: true
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webxr/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/webxr/OWNERS index a28ee65..cb7f472 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/webxr/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/webxr/OWNERS
@@ -1,4 +1,5 @@ +file://third_party/blink/renderer/modules/xr/OWNERS + # TEAM: xr-dev@chromium.org -# COMPONENT: Blink>WebVR +# COMPONENT: Blink>WebXR # WPT-NOTIFY: true -file://third_party/blink/renderer/modules/xr/OWNERS \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/custom/dominant-baseline-hanging-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/custom/dominant-baseline-hanging-expected.txt deleted file mode 100644 index 69bd685..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/custom/dominant-baseline-hanging-expected.txt +++ /dev/null
@@ -1,96 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 400x400 - LayoutSVGRoot {svg} at (0,0) size 400x400 - LayoutSVGHiddenContainer {defs} at (0,0) size 0x0 - LayoutSVGResourceLinearGradient {linearGradient} [id="gradient"] [gradientUnits=objectBoundingBox] [stops=( #FF72B480@0.00 #FF007B@1.00 )] [start=(0,0)] [end=(0,1)] - LayoutSVGResourceLinearGradient {linearGradient} [id="h_stroke_gradient"] [gradientUnits=objectBoundingBox] [stops=( #000000@0.00 #00000000@1.00 )] [start=(0,0)] [end=(1,0)] - LayoutSVGResourceLinearGradient {linearGradient} [id="v_stroke_gradient"] [gradientUnits=objectBoundingBox] [stops=( #000000@0.00 #00000000@1.00 )] [start=(0,0)] [end=(0,1)] - LayoutSVGRect {rect} at (0,0) size 400x400 [fill={[type=LINEAR-GRADIENT] [id="gradient"]}] [x=0.00] [y=0.00] [width=400.00] [height=400.00] - LayoutSVGContainer {g} at (-0.50,-3.39) size 380.50x28.39 [transform={m=((1.00,0.00)(0.00,1.00)) t=(10.00,10.00)}] - LayoutSVGRect {rect} at (0,0) size 380x25 [opacity=0.50] [fill={[type=SOLID] [color=#FFFFFF]}] [x=0.00] [y=0.00] [width=380.00] [height=25.00] - LayoutSVGContainer {g} at (0,-0.50) size 380x25.50 [transform={m=((1.00,0.00)(0.00,1.00)) t=(-0.50,-0.50)}] - LayoutSVGPath {line} at (0,0) size 380x0 [stroke={[type=LINEAR-GRADIENT] [id="h_stroke_gradient"]}] [fill={[type=SOLID] [color=#000000]}] [x1=0.00] [y1=0.00] [x2=380.00] [y2=0.00] - LayoutSVGPath {line} at (0,-0.50) size 0x25.50 [stroke={[type=LINEAR-GRADIENT] [id="v_stroke_gradient"]}] [fill={[type=SOLID] [color=#000000]}] [x1=0.00] [y1=-0.50] [x2=0.00] [y2=25.00] - LayoutSVGText {text} at (2,-3.39) size 323x22 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (2,-3.39) size 323x22 - chunk 1 text run 1 at (2.00,13.60) startOffset 0 endOffset 40 width 323.00: "This is hanging from the top-left corner" - LayoutSVGForeignObject {foreignObject} at (10,45) size 380x150 - LayoutNGBlockFlow {html} at (0,0) size 380x168 - LayoutNGBlockFlow {body} at (8,16) size 364x136 - LayoutNGBlockFlow {p} at (0,0) size 364x100 - LayoutText {#text} at (0,0) size 347x39 - text run at (0,0) width 347: "The piece of text above should be aligned with the top-" - text run at (0,20) width 286: "left corner of the rectangle below it. Both the " - LayoutInline {code} at (0,0) size 48x16 - LayoutText {#text} at (286,23) size 48x16 - text run at (286,23) width 48: "<text>" - LayoutText {#text} at (334,20) size 361x39 - text run at (334,20) width 27: " and" - text run at (0,40) width 23: "the " - LayoutInline {code} at (0,0) size 48x16 - LayoutText {#text} at (23,43) size 48x16 - text run at (23,43) width 48: "<rect>" - LayoutText {#text} at (71,40) size 272x19 - text run at (71,40) width 272: " are located at the same coordinates and the" - LayoutInline {code} at (0,0) size 48x16 - LayoutText {#text} at (0,63) size 48x16 - text run at (0,63) width 48: "<text>" - LayoutText {#text} at (48,60) size 111x19 - text run at (48,60) width 111: " element uses the " - LayoutInline {code} at (0,0) size 56x16 - LayoutText {#text} at (159,63) size 56x16 - text run at (159,63) width 56: "hanging" - LayoutText {#text} at (215,60) size 78x19 - text run at (215,60) width 78: " value for its" - LayoutInline {code} at (0,0) size 136x16 - LayoutText {#text} at (0,83) size 136x16 - text run at (0,83) width 136: "dominant-baseline" - LayoutText {#text} at (136,80) size 59x19 - text run at (136,80) width 59: " attribute." - LayoutNGBlockFlow {p} at (0,116) size 364x20 - LayoutInline {a} at (0,0) size 91x19 [color=#800000] - LayoutText {#text} at (0,0) size 91x19 - text run at (0,0) width 91: "Antoine Quint" - LayoutText {#text} at (91,0) size 89x19 - text run at (91,0) width 89: ", January 27th" -layer at (10,45) size 380x150 scrollHeight 168 - LayoutSVGForeignObject {foreignObject} at (10,45) size 380x150 - LayoutNGBlockFlow {html} at (0,0) size 380x168 - LayoutNGBlockFlow {body} at (8,16) size 364x136 - LayoutNGBlockFlow {p} at (0,0) size 364x100 - LayoutText {#text} at (0,0) size 347x39 - text run at (0,0) width 347: "The piece of text above should be aligned with the top-" - text run at (0,20) width 286: "left corner of the rectangle below it. Both the " - LayoutInline {code} at (0,0) size 48x16 - LayoutText {#text} at (286,23) size 48x16 - text run at (286,23) width 48: "<text>" - LayoutText {#text} at (334,20) size 361x39 - text run at (334,20) width 27: " and" - text run at (0,40) width 23: "the " - LayoutInline {code} at (0,0) size 48x16 - LayoutText {#text} at (23,43) size 48x16 - text run at (23,43) width 48: "<rect>" - LayoutText {#text} at (71,40) size 272x19 - text run at (71,40) width 272: " are located at the same coordinates and the" - LayoutInline {code} at (0,0) size 48x16 - LayoutText {#text} at (0,63) size 48x16 - text run at (0,63) width 48: "<text>" - LayoutText {#text} at (48,60) size 111x19 - text run at (48,60) width 111: " element uses the " - LayoutInline {code} at (0,0) size 56x16 - LayoutText {#text} at (159,63) size 56x16 - text run at (159,63) width 56: "hanging" - LayoutText {#text} at (215,60) size 78x19 - text run at (215,60) width 78: " value for its" - LayoutInline {code} at (0,0) size 136x16 - LayoutText {#text} at (0,83) size 136x16 - text run at (0,83) width 136: "dominant-baseline" - LayoutText {#text} at (136,80) size 59x19 - text run at (136,80) width 59: " attribute." - LayoutNGBlockFlow {p} at (0,116) size 364x20 - LayoutInline {a} at (0,0) size 91x19 [color=#800000] - LayoutText {#text} at (0,0) size 91x19 - text run at (0,0) width 91: "Antoine Quint" - LayoutText {#text} at (91,0) size 89x19 - text run at (91,0) width 89: ", January 27th"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/custom/foreign-object-skew-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/custom/foreign-object-skew-expected.txt deleted file mode 100644 index 18d531d..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/custom/foreign-object-skew-expected.txt +++ /dev/null
@@ -1,28 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutSVGRoot {svg} at (0,0) size 800x600 - LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380 - LayoutNGBlockFlow {xhtml:div} at (0,0) size 580x20 - LayoutText {#text} at (0,0) size 78x19 - text run at (0,0) width 78: "This is a test" - LayoutNGBlockFlow (anonymous) at (0,20) size 580x44 - LayoutInline {xhtml:a} at (0,0) size 66x19 [color=#0000EE] - LayoutText {#text} at (0,0) size 66x19 - text run at (0,0) width 66: "and a link." - LayoutBR {xhtml:br} at (66,0) size 0x0 - LayoutButton {xhtml:input} at (0,20) size 16x22 [bgcolor=#C0C0C0] [border: (2px outset #C0C0C0)] - LayoutText {#text} at (0,0) size 0x0 - LayoutSVGRect {rect} at (10,10) size 580x380 [stroke={[type=SOLID] [color=#008000]}] [x=10.00] [y=10.00] [width=580.00] [height=380.00] -layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335 - LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380 - LayoutNGBlockFlow {xhtml:div} at (0,0) size 580x20 - LayoutText {#text} at (0,0) size 78x19 - text run at (0,0) width 78: "This is a test" - LayoutNGBlockFlow (anonymous) at (0,20) size 580x44 - LayoutInline {xhtml:a} at (0,0) size 66x19 [color=#0000EE] - LayoutText {#text} at (0,0) size 66x19 - text run at (0,0) width 66: "and a link." - LayoutBR {xhtml:br} at (66,0) size 0x0 - LayoutButton {xhtml:input} at (0,20) size 16x22 [bgcolor=#C0C0C0] [border: (2px outset #C0C0C0)] - LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/foreignObject/svg-document-in-html-document-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/foreignObject/svg-document-in-html-document-expected.png deleted file mode 100644 index 03edcce3..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/foreignObject/svg-document-in-html-document-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/foreignObject/svg-document-in-html-document-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/foreignObject/svg-document-in-html-document-expected.txt deleted file mode 100644 index 9811ef3..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/foreignObject/svg-document-in-html-document-expected.txt +++ /dev/null
@@ -1,29 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutSVGRoot {svg} at (0,0) size 800x600 - LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100 - LayoutNGBlockFlow {html} at (0,0) size 300x191 - LayoutNGBlockFlow {p} at (0,0) size 300x20 - LayoutText {#text} at (0,0) size 216x19 - text run at (0,0) width 216: "Test from HTML in foreignObject" - LayoutNGBlockFlow (anonymous) at (0,36) size 300x155 - LayoutSVGRoot {svg} at (0,0) size 300x150 - LayoutSVGRect {rect} at (0,0) size 20x20 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=20.00] [height=20.00] - LayoutSVGText {text} at (0,35) size 271x19 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (0,35) size 271x19 - chunk 1 text run 1 at (0.00,50.00) startOffset 0 endOffset 38 width 270.00: "Test from SVG in HTML in foreignObject" - LayoutText {#text} at (0,0) size 0x0 -layer at (0,0) size 300x100 scrollHeight 191 - LayoutSVGForeignObject {foreignObject} at (0,0) size 300x100 - LayoutNGBlockFlow {html} at (0,0) size 300x191 - LayoutNGBlockFlow {p} at (0,0) size 300x20 - LayoutText {#text} at (0,0) size 216x19 - text run at (0,0) width 216: "Test from HTML in foreignObject" - LayoutNGBlockFlow (anonymous) at (0,36) size 300x155 - LayoutSVGRoot {svg} at (0,0) size 300x150 - LayoutSVGRect {rect} at (0,0) size 20x20 [fill={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=20.00] [height=20.00] - LayoutSVGText {text} at (0,35) size 271x19 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (0,35) size 271x19 - chunk 1 text run 1 at (0.00,50.00) startOffset 0 endOffset 38 width 270.00: "Test from SVG in HTML in foreignObject" - LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/zoom/page/zoom-foreignObject-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/zoom/page/zoom-foreignObject-expected.txt deleted file mode 100644 index b2bd65a2..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/zoom/page/zoom-foreignObject-expected.txt +++ /dev/null
@@ -1,61 +0,0 @@ -layer at (0,0) size 800x600 - LayoutView at (0,0) size 800x600 -layer at (0,0) size 800x600 - LayoutSVGRoot {svg} at (0,0) size 800x600 - LayoutSVGForeignObject {foreignObject} at (0,0) size 250x200 - LayoutNGBlockFlow {xhtml:div} at (0,0) size 250x20 - LayoutText {#text} at (0,0) size 80x19 - text run at (0,0) width 80: "This is a text" - LayoutNGBlockFlow (anonymous) at (0,20) size 250x20 - LayoutInline {xhtml:a} at (0,0) size 66x19 [color=#0000EE] - LayoutText {#text} at (0,0) size 66x19 - text run at (0,0) width 66: "and a link." - LayoutBR {xhtml:br} at (66,0) size 0x0 - LayoutNGBlockFlow {xhtml:div} at (0,40) size 250x20 - LayoutText {#text} at (0,0) size 56x19 - text run at (0,0) width 56: "[HTML]" - LayoutSVGRect {rect} at (0,0) size 250x200 [stroke={[type=SOLID] [color=#008000]}] [x=0.00] [y=0.00] [width=250.00] [height=200.00] - LayoutSVGForeignObject {foreignObject} at (260,0) size 250x200 - LayoutSVGRoot {svg} at (0,0) size 250x200 - LayoutSVGContainer {g} at (0,1.77) size 81.38x58.19 [transform={m=((3.00,0.26)(0.26,3.02)) t=(0.00,0.00)}] - LayoutSVGText {text} at (0,1.77) size 81.38x18.19 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (0,1.77) size 81.38x18.19 - chunk 1 text run 1 at (0.00,16.00) startOffset 0 endOffset 14 width 81.05: "This is a text" - LayoutSVGContainer {a} at (0,20.77) size 66.16x18.19 - LayoutSVGText {text} at (0,20.77) size 66.16x18.19 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (0,20.77) size 66.16x18.19 - chunk 1 text run 1 at (0.00,35.00) startOffset 0 endOffset 11 width 66.16: "and a link." - LayoutSVGText {text} at (0,41.77) size 42.67x18.19 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (0,41.77) size 42.67x18.19 - chunk 1 text run 1 at (0.00,56.00) startOffset 0 endOffset 5 width 42.67: "[SVG]" - LayoutText {#text} at (0,0) size 0x0 - LayoutSVGRect {rect} at (260,0) size 250x200 [stroke={[type=SOLID] [color=#008000]}] [x=260.00] [y=0.00] [width=250.00] [height=200.00] - LayoutSVGHiddenContainer {defs} at (0,0) size 0x0 -layer at (0,0) size 250x200 - LayoutSVGForeignObject {foreignObject} at (0,0) size 250x200 - LayoutNGBlockFlow {xhtml:div} at (0,0) size 250x20 - LayoutText {#text} at (0,0) size 80x19 - text run at (0,0) width 80: "This is a text" - LayoutNGBlockFlow (anonymous) at (0,20) size 250x20 - LayoutInline {xhtml:a} at (0,0) size 66x19 [color=#0000EE] - LayoutText {#text} at (0,0) size 66x19 - text run at (0,0) width 66: "and a link." - LayoutBR {xhtml:br} at (66,0) size 0x0 - LayoutNGBlockFlow {xhtml:div} at (0,40) size 250x20 - LayoutText {#text} at (0,0) size 56x19 - text run at (0,0) width 56: "[HTML]" -layer at (260,0) size 250x200 backgroundClip at (374,0) size 360x288 clip at (374,0) size 136x200 scrollHeight 205 - LayoutSVGForeignObject {foreignObject} at (260,0) size 250x200 - LayoutSVGRoot {svg} at (0,0) size 250x200 - LayoutSVGContainer {g} at (0,1.77) size 81.38x58.19 [transform={m=((3.00,0.26)(0.26,3.02)) t=(0.00,0.00)}] - LayoutSVGText {text} at (0,1.77) size 81.38x18.19 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (0,1.77) size 81.38x18.19 - chunk 1 text run 1 at (0.00,16.00) startOffset 0 endOffset 14 width 81.05: "This is a text" - LayoutSVGContainer {a} at (0,20.77) size 66.16x18.19 - LayoutSVGText {text} at (0,20.77) size 66.16x18.19 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (0,20.77) size 66.16x18.19 - chunk 1 text run 1 at (0.00,35.00) startOffset 0 endOffset 11 width 66.16: "and a link." - LayoutSVGText {text} at (0,41.77) size 42.67x18.19 contains 1 chunk(s) - LayoutSVGInlineText {#text} at (0,41.77) size 42.67x18.19 - chunk 1 text run 1 at (0.00,56.00) startOffset 0 endOffset 5 width 42.67: "[SVG]" - LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index b095174..ff7e92f 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -5207,6 +5207,11 @@ getter imageWidth getter redEyeReduction method constructor +interface PictureInPictureControlEvent : Event + attribute @@toStringTag + getter id + method constructor + setter id interface PictureInPictureWindow : EventTarget attribute @@toStringTag getter height
diff --git a/third_party/arcore-android-sdk/OWNERS b/third_party/arcore-android-sdk/OWNERS index d36245b..4fd5be33 100644 --- a/third_party/arcore-android-sdk/OWNERS +++ b/third_party/arcore-android-sdk/OWNERS
@@ -1,4 +1,6 @@ -lincolnfrog@chromium.org +ddorwin@chromium.org vollick@chromium.org -# COMPONENT: Internals>VR +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR>AR +# OS: Android
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn index ab6cf59..87fcdf8 100644 --- a/third_party/blink/public/mojom/BUILD.gn +++ b/third_party/blink/public/mojom/BUILD.gn
@@ -27,6 +27,7 @@ "leak_detector/leak_detector.mojom", "loader/navigation_predictor.mojom", "loader/pause_subresource_loading_handle.mojom", + "loader/previews_resource_loading_hints.mojom", "manifest/display_mode.mojom", "manifest/manifest.mojom", "manifest/manifest_manager.mojom",
diff --git a/third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom b/third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom new file mode 100644 index 0000000..ef7f815 --- /dev/null +++ b/third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom
@@ -0,0 +1,24 @@ +// 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 blink.mojom; + +// Resource loading hints passed by the browser to renderers. Send at most once +// per page load from browser to renderer as part of a preview treatment. The +// hints are provided to the renderer and aid in optimizing the loading of +// resources. +struct PreviewsResourceLoadingHints { + // List of subresources to block. The list contains the URL patterns of + // subresources to block. + // TODO(tbansal): https://crbug.com/856243. Update the mojom message below + // to match the updated resource loading hints proto. + array<string> subresources_to_block; +}; + +// Render process implemented interface that receives hints from the browser +// about how to load resources. +interface PreviewsResourceLoadingHintsReceiver { + // Sends the resource loading hints from the browser to renderers. + SetResourceLoadingHints(PreviewsResourceLoadingHints previews_resource_loading_hints); +};
diff --git a/third_party/blink/public/platform/web_url_request.h b/third_party/blink/public/platform/web_url_request.h index 183480d..cd6d8a0 100644 --- a/third_party/blink/public/platform/web_url_request.h +++ b/third_party/blink/public/platform/web_url_request.h
@@ -140,7 +140,8 @@ kNoScriptOn = 1 << 6, // Request that script be disabled for page load. kResourceLoadingHintsOn = 1 << 7, // Request that resource loading hints be // used during pageload. - kPreviewsStateLast = kResourceLoadingHintsOn + kOfflinePageOn = 1 << 8, + kPreviewsStateLast = kOfflinePageOn }; class ExtraData {
diff --git a/third_party/blink/renderer/controller/blink_initializer.cc b/third_party/blink/renderer/controller/blink_initializer.cc index c7fd152..3c95d67d 100644 --- a/third_party/blink/renderer/controller/blink_initializer.cc +++ b/third_party/blink/renderer/controller/blink_initializer.cc
@@ -168,6 +168,9 @@ &DevToolsFrontendImpl::BindMojoRequest, WrapWeakPersistent(&frame))); frame.GetInterfaceRegistry()->AddInterface(WTF::BindRepeating( &LocalFrame::PauseSubresourceLoading, WrapWeakPersistent(&frame))); + frame.GetInterfaceRegistry()->AddInterface( + WTF::BindRepeating(&LocalFrame::BindPreviewsResourceLoadingHintsRequest, + WrapWeakPersistent(&frame))); ModulesInitializer::InitLocalFrame(frame); }
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index ecf1b82a..4d1f81e 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -349,6 +349,7 @@ "events/mouse_event.idl", "events/mutation_event.idl", "events/page_transition_event.idl", + "events/picture_in_picture_control_event.idl", "events/pointer_event.idl", "events/pop_state_event.idl", "events/progress_event.idl",
diff --git a/third_party/blink/renderer/core/core_export.h b/third_party/blink/renderer/core/core_export.h index c71a878..0563cf0 100644 --- a/third_party/blink/renderer/core/core_export.h +++ b/third_party/blink/renderer/core/core_export.h
@@ -43,30 +43,29 @@ #endif // !defined(COMPONENT_BUILD) // -// CORE_TEMPLATE_CLASS_EXPORT // CORE_EXTERN_TEMPLATE_EXPORT // CORE_TEMPLATE_EXPORT // #if BLINK_CORE_IMPLEMENTATION #if defined(COMPILER_MSVC) -#define CORE_TEMPLATE_CLASS_EXPORT #define CORE_EXTERN_TEMPLATE_EXPORT CORE_EXPORT #define CORE_TEMPLATE_EXPORT CORE_EXPORT #endif #if defined(COMPILER_GCC) -#define CORE_TEMPLATE_CLASS_EXPORT CORE_EXPORT #define CORE_EXTERN_TEMPLATE_EXPORT CORE_EXPORT #define CORE_TEMPLATE_EXPORT #endif #else // BLINK_CORE_IMPLEMENTATION -#define CORE_TEMPLATE_CLASS_EXPORT #define CORE_EXTERN_TEMPLATE_EXPORT CORE_EXPORT #define CORE_TEMPLATE_EXPORT #endif // BLINK_CORE_IMPLEMENTATION +// TODO(thakis): Remove all references to this, https://crbug.com/859989 +#define CORE_TEMPLATE_CLASS_EXPORT + #endif // THIRD_PARTY_BLINK_RENDERER_CORE_CORE_EXPORT_H_
diff --git a/third_party/blink/renderer/core/core_idl_files.gni b/third_party/blink/renderer/core/core_idl_files.gni index 0bc79a4..9dfaee1 100644 --- a/third_party/blink/renderer/core/core_idl_files.gni +++ b/third_party/blink/renderer/core/core_idl_files.gni
@@ -153,6 +153,7 @@ "events/mouse_event.idl", "events/mutation_event.idl", "events/page_transition_event.idl", + "events/picture_in_picture_control_event.idl", "events/pointer_event.idl", "events/pop_state_event.idl", "events/progress_event.idl", @@ -601,6 +602,7 @@ "events/message_event_init.idl", "events/mouse_event_init.idl", "events/page_transition_event_init.idl", + "events/picture_in_picture_control_event_init.idl", "events/pointer_event_init.idl", "events/pop_state_event_init.idl", "events/progress_event_init.idl",
diff --git a/third_party/blink/renderer/core/events/BUILD.gn b/third_party/blink/renderer/core/events/BUILD.gn index f10dfae..b1a771ba 100644 --- a/third_party/blink/renderer/core/events/BUILD.gn +++ b/third_party/blink/renderer/core/events/BUILD.gn
@@ -48,6 +48,8 @@ "navigator_events.h", "page_transition_event.cc", "page_transition_event.h", + "picture_in_picture_control_event.cc", + "picture_in_picture_control_event.h", "pointer_event.cc", "pointer_event.h", "pointer_event_factory.cc",
diff --git a/third_party/blink/renderer/core/events/picture_in_picture_control_event.cc b/third_party/blink/renderer/core/events/picture_in_picture_control_event.cc new file mode 100644 index 0000000..6c37f141 --- /dev/null +++ b/third_party/blink/renderer/core/events/picture_in_picture_control_event.cc
@@ -0,0 +1,38 @@ +// 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. + +#include "third_party/blink/renderer/core/events/picture_in_picture_control_event.h" + +namespace blink { + +PictureInPictureControlEvent* PictureInPictureControlEvent::Create( + const AtomicString& type, + String id) { + return new PictureInPictureControlEvent(type, id); +} + +PictureInPictureControlEvent* PictureInPictureControlEvent::Create( + const AtomicString& type, + const PictureInPictureControlEventInit& initializer) { + return new PictureInPictureControlEvent(type, initializer); +} + +String PictureInPictureControlEvent::id() const { + return id_; +} +void PictureInPictureControlEvent::setId(String id) { + id_ = id; +} + +PictureInPictureControlEvent::PictureInPictureControlEvent( + AtomicString const& type, + String id) + : Event(type, Bubbles::kYes, Cancelable::kNo), id_(id) {} + +PictureInPictureControlEvent::PictureInPictureControlEvent( + AtomicString const& type, + const PictureInPictureControlEventInit& initializer) + : Event(type, initializer), id_(initializer.id()) {} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/events/picture_in_picture_control_event.h b/third_party/blink/renderer/core/events/picture_in_picture_control_event.h new file mode 100644 index 0000000..199c2bbf --- /dev/null +++ b/third_party/blink/renderer/core/events/picture_in_picture_control_event.h
@@ -0,0 +1,40 @@ +// 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. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_PICTURE_IN_PICTURE_CONTROL_EVENT_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_PICTURE_IN_PICTURE_CONTROL_EVENT_H_ + +#include "third_party/blink/renderer/core/dom/events/event.h" +#include "third_party/blink/renderer/core/events/picture_in_picture_control_event_init.h" + +namespace blink { + +// A PictureInPictureControlEvent is a subclass of Event with an additional +// string. This string is used to convey to the browser the name of a custom +// control on a Picture in Picture window. +class CORE_EXPORT PictureInPictureControlEvent final : public Event { + DEFINE_WRAPPERTYPEINFO(); + + public: + static PictureInPictureControlEvent* Create(const AtomicString&, String); + static PictureInPictureControlEvent* Create( + const AtomicString&, + const PictureInPictureControlEventInit&); + + String id() const; + void setId(String id); + + private: + PictureInPictureControlEvent(AtomicString const&, String); + PictureInPictureControlEvent(AtomicString const&, + const PictureInPictureControlEventInit&); + + // id_ holds the id of a PictureIncPictureControlEvent, which is used to + // convey which custom control fired the event by being clicked. + String id_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_EVENTS_PICTURE_IN_PICTURE_CONTROL_EVENT_H_
diff --git a/third_party/blink/renderer/core/events/picture_in_picture_control_event.idl b/third_party/blink/renderer/core/events/picture_in_picture_control_event.idl new file mode 100644 index 0000000..550f1e6 --- /dev/null +++ b/third_party/blink/renderer/core/events/picture_in_picture_control_event.idl
@@ -0,0 +1,11 @@ +// 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. + +[ + RuntimeEnabled=PictureInPictureControl, + Constructor(DOMString type, PictureInPictureControlEventInit eventInitDict) +] +interface PictureInPictureControlEvent : Event { + attribute DOMString id; +}; \ No newline at end of file
diff --git a/third_party/blink/renderer/core/events/picture_in_picture_control_event_init.idl b/third_party/blink/renderer/core/events/picture_in_picture_control_event_init.idl new file mode 100644 index 0000000..a34e0a4 --- /dev/null +++ b/third_party/blink/renderer/core/events/picture_in_picture_control_event_init.idl
@@ -0,0 +1,7 @@ +// 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. + +dictionary PictureInPictureControlEventInit : EventInit { + required DOMString id; +}; \ No newline at end of file
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 9861c23..a0aa62c 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -79,6 +79,7 @@ #include "third_party/blink/renderer/core/loader/frame_load_request.h" #include "third_party/blink/renderer/core/loader/idleness_detector.h" #include "third_party/blink/renderer/core/loader/navigation_scheduler.h" +#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h" #include "third_party/blink/renderer/core/page/drag_controller.h" #include "third_party/blink/renderer/core/page/focus_controller.h" #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h" @@ -485,6 +486,7 @@ GetInputMethodController().DocumentAttached(GetDocument()); GetSpellChecker().DocumentAttached(GetDocument()); GetTextSuggestionController().DocumentAttached(GetDocument()); + previews_resource_loading_hints_receiver_.reset(); } Frame* LocalFrame::FindFrameForNavigation(const AtomicString& name, @@ -1424,4 +1426,12 @@ GetEventHandler().AnimateSnapFling(monotonic_time); } +void LocalFrame::BindPreviewsResourceLoadingHintsRequest( + blink::mojom::blink::PreviewsResourceLoadingHintsReceiverRequest request) { + DCHECK(!previews_resource_loading_hints_receiver_); + previews_resource_loading_hints_receiver_ = + std::make_unique<PreviewsResourceLoadingHintsReceiverImpl>( + std::move(request)); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h index bb0ce4f0..35941ba2 100644 --- a/third_party/blink/renderer/core/frame/local_frame.h +++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -34,6 +34,7 @@ #include "base/macros.h" #include "mojo/public/cpp/bindings/strong_binding_set.h" #include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom-blink.h" +#include "third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom-blink.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/user_gesture_indicator.h" @@ -362,6 +363,9 @@ return client_hints_preferences_; } + void BindPreviewsResourceLoadingHintsRequest( + blink::mojom::blink::PreviewsResourceLoadingHintsReceiverRequest request); + private: friend class FrameNavigationDisabler; @@ -454,6 +458,9 @@ // Per-frame URLLoader factory. std::unique_ptr<WebURLLoaderFactory> url_loader_factory_; + std::unique_ptr<mojom::blink::PreviewsResourceLoadingHintsReceiver> + previews_resource_loading_hints_receiver_; + ClientHintsPreferences client_hints_preferences_; };
diff --git a/third_party/blink/renderer/core/html/parser/text_resource_decoder.cc b/third_party/blink/renderer/core/html/parser/text_resource_decoder.cc index ec99eaeb..03dbb6f 100644 --- a/third_party/blink/renderer/core/html/parser/text_resource_decoder.cc +++ b/third_party/blink/renderer/core/html/parser/text_resource_decoder.cc
@@ -126,7 +126,8 @@ checked_for_css_charset_(false), checked_for_xml_charset_(false), checked_for_meta_charset_(false), - saw_error_(false) { + saw_error_(false), + detection_completed_(false) { // TODO(hiroshige): Move the invariant check to TextResourceDecoderOptions. if (options_.GetEncodingDetectionOption() == TextResourceDecoderOptions::kAlwaysUseUTF8ForText) { @@ -373,7 +374,8 @@ void TextResourceDecoder::AutoDetectEncodingIfAllowed(const char* data, size_t len) { if (options_.GetEncodingDetectionOption() != - TextResourceDecoderOptions::kUseAllAutoDetection) + TextResourceDecoderOptions::kUseAllAutoDetection || + detection_completed_) return; // Just checking hint_encoding_ suffices here because it's only set @@ -386,6 +388,8 @@ if (DetectTextEncoding(data, len, options_.HintEncoding(), options_.HintURL(), options_.HintLanguage(), &detected_encoding)) SetEncoding(detected_encoding, kEncodingFromContentSniffing); + if (detected_encoding != WTF::UnknownEncoding()) + detection_completed_ = true; } String TextResourceDecoder::Decode(const char* data, size_t len) {
diff --git a/third_party/blink/renderer/core/html/parser/text_resource_decoder.h b/third_party/blink/renderer/core/html/parser/text_resource_decoder.h index 4d4b2442..c47a5ee 100644 --- a/third_party/blink/renderer/core/html/parser/text_resource_decoder.h +++ b/third_party/blink/renderer/core/html/parser/text_resource_decoder.h
@@ -95,6 +95,7 @@ bool checked_for_xml_charset_; bool checked_for_meta_charset_; bool saw_error_; + bool detection_completed_; std::unique_ptr<HTMLMetaCharsetParser> charset_parser_;
diff --git a/third_party/blink/renderer/core/html/parser/text_resource_decoder_test.cc b/third_party/blink/renderer/core/html/parser/text_resource_decoder_test.cc index 1e0b9e6..ae1912f 100644 --- a/third_party/blink/renderer/core/html/parser/text_resource_decoder_test.cc +++ b/third_party/blink/renderer/core/html/parser/text_resource_decoder_test.cc
@@ -44,4 +44,26 @@ EXPECT_EQ("foo", decoded); } +TEST(TextResourceDecoderTest, ContentSniffingStopsAfterSuccess) { + std::unique_ptr<TextResourceDecoder> decoder = TextResourceDecoder::Create( + TextResourceDecoderOptions::CreateWithAutoDetection( + TextResourceDecoderOptions::kPlainTextContent, WTF::UTF8Encoding(), + WTF::UTF8Encoding(), KURL(""))); + + std::string utf8_bytes = + "tnegirjji gosa gii beare s\xC3\xA1htt\xC3\xA1 \xC4\x8D\xC3" + "\xA1llit artihkkaliid. Maid don s\xC3\xA1ht\xC3\xA1t dievasmah"; + + std::string eucjp_bytes = + "<TITLE>" + "\xA5\xD1\xA5\xEF\xA1\xBC\xA5\xC1\xA5\xE3\xA1\xBC\xA5\xC8\xA1\xC3\xC5\xEA" + "\xBB\xF1\xBE\xF0\xCA\xF3\xA4\xCE\xA5\xD5\xA5\xA3\xA5\xB9\xA5\xB3</" + "TITLE>"; + + decoder->Decode(utf8_bytes.c_str(), utf8_bytes.length()); + EXPECT_EQ(WTF::UTF8Encoding(), decoder->Encoding()); + decoder->Decode(eucjp_bytes.c_str(), eucjp_bytes.length()); + EXPECT_EQ(WTF::UTF8Encoding(), decoder->Encoding()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc index d671935..a139ca0 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
@@ -160,7 +160,8 @@ const NGPaintFragment& fragment, unsigned offset, TextAffinity affinity) { - if (!fragment.GetNode()) { + // There is no caret position at a pseudo or generated box side. + if (!fragment.GetNode() || fragment.GetNode()->IsPseudoElement()) { // TODO(xiaochengh): This leads to false negatives for, e.g., RUBY, where an // anonymous wrapping inline block is created. return CaretPositionResolution();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc index da232c2..6446ddb3 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc
@@ -276,4 +276,23 @@ fragment_d, kAtTextOffset, base::Optional<unsigned>(wrap_offset)); } +TEST_F(NGCaretPositionTest, InlineBlockBeforeContent) { + SetInlineFormattingContext( + "t", + "<style>span::before{display:inline-block; content:'foo'}</style>" + "<span id=span>bar</span>", + 100); // Line width doesn't matter here. + const Node* text = GetElementById("span")->firstChild(); + const NGPhysicalFragment* text_fragment = FragmentOf(text); + + // Test caret position of "|bar", which shouldn't be affected by ::before + const Position position(text, 0); + const NGOffsetMapping& mapping = *NGOffsetMapping::GetFor(position); + const unsigned text_offset = mapping.GetTextContentOffset(position).value(); + + TEST_CARET(ComputeNGCaretPosition(text_offset, TextAffinity::kDownstream), + text_fragment, kAtTextOffset, + base::Optional<unsigned>(text_offset)); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc index 9e7bace..4ae097b 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
@@ -144,10 +144,8 @@ } UScriptCode NGInlineItem::Script() const { - // UScriptCode is -1 (USCRIPT_INVALID_CODE) to 177 as of ICU 60. - // Convert back the max value of the unsigned bit field to -1. - return script_ != (1 << kScriptBits) - 1 ? static_cast<UScriptCode>(script_) - : USCRIPT_INVALID_CODE; + return script_ != kInvalidScript ? static_cast<UScriptCode>(script_) + : USCRIPT_INVALID_CODE; } FontFallbackPriority NGInlineItem::GetFontFallbackPriority() const { @@ -173,17 +171,16 @@ void NGInlineItem::SetRunSegment(const RunSegmenter::RunSegmenterRange& range) { DCHECK_EQ(Type(), NGInlineItem::kText); - // Ensure the values can fit in the bit fields. - DCHECK(range.script == USCRIPT_INVALID_CODE || - static_cast<unsigned>(range.script) < (1u << kScriptBits)); - DCHECK_LT(static_cast<unsigned>(range.font_fallback_priority), 1u << 2); - // Orientation should be set in a separate pass. See // NGInlineNode::SegmentScriptRuns(). DCHECK_EQ(range.render_orientation, OrientationIterator::kOrientationKeep); script_ = static_cast<unsigned>(range.script); font_fallback_priority_ = static_cast<unsigned>(range.font_fallback_priority); + + // Ensure our bit fields are large enough by reading them back. + DCHECK_EQ(range.script, Script()); + DCHECK_EQ(range.font_fallback_priority, GetFontFallbackPriority()); } void NGInlineItem::SetFontOrientation(
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h index 091d7d6..72708ec 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
@@ -172,7 +172,10 @@ scoped_refptr<const ComputedStyle> style_; LayoutObject* layout_object_; - static constexpr unsigned kScriptBits = 8; // UScriptCode, see Script(). + // UScriptCode is -1 (USCRIPT_INVALID_CODE) to 177 as of ICU 60. + // This can be packed to 8 bits, by handling -1 separately. + static constexpr unsigned kScriptBits = 8; + static constexpr unsigned kInvalidScript = (1 << kScriptBits) - 1; unsigned type_ : 4; unsigned script_ : kScriptBits;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc index dc56e4b3..8ea8963 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -423,9 +423,9 @@ available_width = std::max(LayoutUnit(0), available_width); // Use kStartShouldBeSafe if at the beginning of a line. - unsigned options = 0; - if (offset_ == line_info->StartOffset()) - options |= ShapingLineBreaker::kStartShouldBeSafe; + unsigned options = ShapingLineBreaker::kDefaultOptions; + if (offset_ != line_info->StartOffset()) + options |= ShapingLineBreaker::kDontReshapeStart; // Use kNoResultIfOverflow if 'break-word' and we're trying to break normally // because if this item overflows, we will rewind and break line again. The
diff --git a/third_party/blink/renderer/core/loader/BUILD.gn b/third_party/blink/renderer/core/loader/BUILD.gn index 5638967..49b4ead 100644 --- a/third_party/blink/renderer/core/loader/BUILD.gn +++ b/third_party/blink/renderer/core/loader/BUILD.gn
@@ -81,6 +81,8 @@ "ping_loader.h", "prerenderer_client.cc", "prerenderer_client.h", + "previews_resource_loading_hints_receiver_impl.cc", + "previews_resource_loading_hints_receiver_impl.h", "private/frame_client_hints_preferences_context.cc", "private/frame_client_hints_preferences_context.h", "private/prerender_handle.cc",
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc index 266a140..0a11d94 100644 --- a/third_party/blink/renderer/core/loader/base_fetch_context.cc +++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -39,7 +39,7 @@ case WebURLRequest::kRequestContextXMLHttpRequest: case WebURLRequest::kRequestContextSubresource: case WebURLRequest::kRequestContextPrefetch: - return ""; + return "\"\""; case WebURLRequest::kRequestContextCSPReport: return "report"; case WebURLRequest::kRequestContextAudio: @@ -132,9 +132,9 @@ } } - String value = String::Format( - "destination=\"%s\", target=\"subresource\", site=\"%s\"", - destination_value, site_value); + String value = + String::Format("destination=%s, target=subresource, site=%s", + destination_value, site_value); request.AddHTTPHeaderField("Sec-Metadata", AtomicString(value)); } }
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.cc b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.cc new file mode 100644 index 0000000..6a1a5e4 --- /dev/null +++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.cc
@@ -0,0 +1,28 @@ +// 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. + +#include "third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h" + +#include "base/metrics/histogram_macros.h" + +namespace blink { + +PreviewsResourceLoadingHintsReceiverImpl:: + PreviewsResourceLoadingHintsReceiverImpl( + mojom::blink::PreviewsResourceLoadingHintsReceiverRequest request) + : binding_(this, std::move(request)) {} + +PreviewsResourceLoadingHintsReceiverImpl:: + ~PreviewsResourceLoadingHintsReceiverImpl() {} + +void PreviewsResourceLoadingHintsReceiverImpl::SetResourceLoadingHints( + mojom::blink::PreviewsResourceLoadingHintsPtr resource_loading_hints) { + // TODO(tbansal): https://crbug.com/856247. Block loading of resources based + // on |resource_loading_hints|. + UMA_HISTOGRAM_COUNTS_100( + "ResourceLoadingHints.CountBlockedSubresourcePatterns", + resource_loading_hints->subresources_to_block.size()); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h new file mode 100644 index 0000000..d4a8daf0 --- /dev/null +++ b/third_party/blink/renderer/core/loader/previews_resource_loading_hints_receiver_impl.h
@@ -0,0 +1,35 @@ +// 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. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_RECEIVER_IMPL_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_RECEIVER_IMPL_H_ + +#include "mojo/public/cpp/bindings/binding.h" +#include "third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom-blink.h" + +namespace blink { + +// Created and attached to a LocalFrame when +// PreviewsResourceLoadingHintsReceiverRequest is received by the frame from the +// browser process. +class PreviewsResourceLoadingHintsReceiverImpl + : public mojom::blink::PreviewsResourceLoadingHintsReceiver { + public: + explicit PreviewsResourceLoadingHintsReceiverImpl( + mojom::blink::PreviewsResourceLoadingHintsReceiverRequest request); + ~PreviewsResourceLoadingHintsReceiverImpl() override; + + private: + void SetResourceLoadingHints(mojom::blink::PreviewsResourceLoadingHintsPtr + resource_loading_hints) override; + + // TODO(tbansal): https://crbug.com/800641. Consider using a RevocableBinding. + mojo::Binding<mojom::blink::PreviewsResourceLoadingHintsReceiver> binding_; + + DISALLOW_COPY_AND_ASSIGN(PreviewsResourceLoadingHintsReceiverImpl); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PREVIEWS_RESOURCE_LOADING_HINTS_RECEIVER_IMPL_H_
diff --git a/third_party/blink/renderer/core/mojo/mojo_watcher.cc b/third_party/blink/renderer/core/mojo/mojo_watcher.cc index 855fb03..b62ee14 100644 --- a/third_party/blink/renderer/core/mojo/mojo_watcher.cc +++ b/third_party/blink/renderer/core/mojo/mojo_watcher.cc
@@ -118,20 +118,18 @@ if (!handle_.is_valid()) return MOJO_RESULT_OK; - uint32_t num_ready_contexts = 1; - uintptr_t ready_context; - MojoResult local_ready_result; - MojoHandleSignalsState ready_signals; - MojoResult result = - MojoArmTrap(trap_handle_.get().value(), nullptr, &num_ready_contexts, - &ready_context, &local_ready_result, &ready_signals); + uint32_t num_blocking_events = 1; + MojoTrapEvent blocking_event = {sizeof(blocking_event)}; + MojoResult result = MojoArmTrap(trap_handle_.get().value(), nullptr, + &num_blocking_events, &blocking_event); if (result == MOJO_RESULT_OK) return MOJO_RESULT_OK; if (result == MOJO_RESULT_FAILED_PRECONDITION) { - DCHECK_EQ(1u, num_ready_contexts); - DCHECK_EQ(reinterpret_cast<uintptr_t>(this), ready_context); - *ready_result = local_ready_result; + DCHECK_EQ(1u, num_blocking_events); + DCHECK_EQ(reinterpret_cast<uintptr_t>(this), + blocking_event.trigger_context); + *ready_result = blocking_event.result; return result; }
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc index c5c7739b..8b6e787 100644 --- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc +++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -804,6 +804,12 @@ bool has_clip_path = ClipPathClipper::LocalClipPathBoundingBox(GetLayoutObject()).has_value(); if (UpdateMaskLayer(has_mask || has_clip_path)) { + // TODO(crbug.com/856818): Remove this speculative fix. + // It is speculated that the clip path of an element become valid without + // invalidating its cache, resulting in the associated clip nodes not + // being created, and the newly created mask layer having bad layer state. + GetLayoutObject().InvalidateClipPathCache(); + graphics_layer_->SetMaskLayer(mask_layer_.get()); layer_config_changed = true; }
diff --git a/third_party/blink/renderer/core/svg/svg_foreign_object_element.h b/third_party/blink/renderer/core/svg/svg_foreign_object_element.h index 914185a..481cd95 100644 --- a/third_party/blink/renderer/core/svg/svg_foreign_object_element.h +++ b/third_party/blink/renderer/core/svg/svg_foreign_object_element.h
@@ -50,6 +50,12 @@ LayoutObject* CreateLayoutObject(const ComputedStyle&) override; + // As long as the foreignObject element itself creates a legacy layout object, + // we need to use legacy layout for the entire block formatting context + // established by the foreignObject. For simplicity, just force legacy for the + // entire subtree. + bool ShouldForceLegacyLayout() const override { return true; } + bool SelfHasRelativeLengths() const override; Member<SVGAnimatedLength> x_;
diff --git a/third_party/blink/renderer/modules/modules_export.h b/third_party/blink/renderer/modules/modules_export.h index 0bc87cd8a..4a5a038 100644 --- a/third_party/blink/renderer/modules/modules_export.h +++ b/third_party/blink/renderer/modules/modules_export.h
@@ -43,30 +43,29 @@ #endif // !defined(COMPONENT_BUILD) // -// MODULES_TEMPLATE_CLASS_EXPORT // MODULES_EXTERN_TEMPLATE_EXPORT // MODULES_TEMPLATE_EXPORT // #if BLINK_MODULES_IMPLEMENTATION #if defined(COMPILER_MSVC) -#define MODULES_TEMPLATE_CLASS_EXPORT #define MODULES_EXTERN_TEMPLATE_EXPORT MODULES_EXPORT #define MODULES_TEMPLATE_EXPORT MODULES_EXPORT #endif #if defined(COMPILER_GCC) -#define MODULES_TEMPLATE_CLASS_EXPORT MODULES_EXPORT #define MODULES_EXTERN_TEMPLATE_EXPORT MODULES_EXPORT #define MODULES_TEMPLATE_EXPORT #endif #else // BLINK_MODULES_IMPLEMENTATION -#define MODULES_TEMPLATE_CLASS_EXPORT #define MODULES_EXTERN_TEMPLATE_EXPORT MODULES_EXPORT #define MODULES_TEMPLATE_EXPORT #endif // BLINK_MODULES_IMPLEMENTATION +// TODO(thakis): Remove all references to this, https://crbug.com/859989 +#define MODULES_TEMPLATE_CLASS_EXPORT + #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MODULES_EXPORT_H_
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc index e6d36131..3abee02 100644 --- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc +++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -7,6 +7,7 @@ #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/dom/events/event.h" +#include "third_party/blink/renderer/core/events/picture_in_picture_control_event.h" #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/html/media/html_video_element.h" #include "third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_window.h" @@ -168,9 +169,14 @@ if (!GetSupplementable()->IsActive()) return; - if (picture_in_picture_element_) { + // TODO(crbug/856251): Allow for different strings to be passed in here. + // Current string is a placeholder. + if (RuntimeEnabledFeatures::PictureInPictureControlEnabled() && + picture_in_picture_element_) { picture_in_picture_element_->DispatchEvent( - Event::CreateBubble(EventTypeNames::pictureinpicturecontrolclick)); + PictureInPictureControlEvent::Create( + EventTypeNames::pictureinpicturecontrolclick, + "placeholder_event_name")); } }
diff --git a/third_party/blink/renderer/modules/vr/OWNERS b/third_party/blink/renderer/modules/vr/OWNERS index 4e35d8a..042b46ff 100644 --- a/third_party/blink/renderer/modules/vr/OWNERS +++ b/third_party/blink/renderer/modules/vr/OWNERS
@@ -1,5 +1,5 @@ bajones@chromium.org -kbr@chromium.org klausw@chromium.org -# COMPONENT: Blink>WebVR +# TEAM: xr-dev@chromium.org +# COMPONENT: Blink>WebXR>VR
diff --git a/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc index 0ed8c178c..a5427bff 100644 --- a/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc +++ b/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.cc
@@ -39,17 +39,6 @@ namespace blink { -DefaultAudioDestinationHandler::DefaultAudioDestinationHandler( - AudioNode& node, - const WebAudioLatencyHint& latency_hint) - : AudioDestinationHandler(node), - latency_hint_(latency_hint) { - // Node-specific default mixing rules. - channel_count_ = 2; - SetInternalChannelCountMode(kExplicit); - SetInternalChannelInterpretation(AudioBus::kSpeakers); -} - scoped_refptr<DefaultAudioDestinationHandler> DefaultAudioDestinationHandler::Create( AudioNode& node, @@ -57,6 +46,17 @@ return base::AdoptRef(new DefaultAudioDestinationHandler(node, latency_hint)); } +DefaultAudioDestinationHandler::DefaultAudioDestinationHandler( + AudioNode& node, + const WebAudioLatencyHint& latency_hint) + : AudioDestinationHandler(node), + latency_hint_(latency_hint) { + // Node-specific default channel count and mixing rules. + channel_count_ = 2; + SetInternalChannelCountMode(kExplicit); + SetInternalChannelInterpretation(AudioBus::kSpeakers); +} + DefaultAudioDestinationHandler::~DefaultAudioDestinationHandler() { DCHECK(!IsInitialized()); } @@ -86,29 +86,34 @@ AudioHandler::Uninitialize(); } -void DefaultAudioDestinationHandler::CreateDestination() { - destination_ = AudioDestination::Create(*this, ChannelCount(), latency_hint_); -} +void DefaultAudioDestinationHandler::SetChannelCount( + unsigned long channel_count, + ExceptionState& exception_state) { + DCHECK(IsMainThread()); -void DefaultAudioDestinationHandler::StartDestination() { - DCHECK(!destination_->IsPlaying()); - - AudioWorklet* audio_worklet = Context()->audioWorklet(); - if (audio_worklet && audio_worklet->IsReady()) { - // This task runner is only used to fire the audio render callback, so it - // MUST not be throttled to avoid potential audio glitch. - destination_->StartWithWorkletTaskRunner( - audio_worklet->GetMessagingProxy() - ->GetBackingWorkerThread() - ->GetTaskRunner(TaskType::kInternalMedia)); - } else { - destination_->Start(); + // The channelCount for the input to this node controls the actual number of + // channels we send to the audio hardware. It can only be set if the number + // is less than the number of hardware channels. + if (!MaxChannelCount() || channel_count > MaxChannelCount()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kIndexSizeError, + ExceptionMessages::IndexOutsideRange<unsigned>( + "channel count", channel_count, 1, + ExceptionMessages::kInclusiveBound, MaxChannelCount(), + ExceptionMessages::kInclusiveBound)); + return; } -} -void DefaultAudioDestinationHandler::StopDestination() { - DCHECK(destination_->IsPlaying()); - destination_->Stop(); + unsigned long old_channel_count = this->ChannelCount(); + AudioHandler::SetChannelCount(channel_count, exception_state); + + // Stop, re-create and start the destination to apply the new channel count. + if (!exception_state.HadException() && + this->ChannelCount() != old_channel_count && IsInitialized()) { + StopDestination(); + CreateDestination(); + StartDestination(); + } } void DefaultAudioDestinationHandler::StartRendering() { @@ -138,82 +143,37 @@ return AudioDestination::MaxChannelCount(); } -size_t DefaultAudioDestinationHandler::GetCallbackBufferSize() const { - return destination_->CallbackBufferSize(); -} - -void DefaultAudioDestinationHandler::SetChannelCount( - unsigned long channel_count, - ExceptionState& exception_state) { - // The channelCount for the input to this node controls the actual number of - // channels we send to the audio hardware. It can only be set depending on the - // maximum number of channels supported by the hardware. - - DCHECK(IsMainThread()); - - if (!MaxChannelCount() || channel_count > MaxChannelCount()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kIndexSizeError, - ExceptionMessages::IndexOutsideRange<unsigned>( - "channel count", channel_count, 1, - ExceptionMessages::kInclusiveBound, MaxChannelCount(), - ExceptionMessages::kInclusiveBound)); - return; - } - - unsigned long old_channel_count = this->ChannelCount(); - AudioHandler::SetChannelCount(channel_count, exception_state); - - if (!exception_state.HadException() && - this->ChannelCount() != old_channel_count && IsInitialized()) { - // Recreate/restart destination. - StopDestination(); - CreateDestination(); - StartDestination(); - } -} - double DefaultAudioDestinationHandler::SampleRate() const { return destination_ ? destination_->SampleRate() : 0; } -int DefaultAudioDestinationHandler::GetFramesPerBuffer() const { - return destination_ ? destination_->FramesPerBuffer() : 0; -} - void DefaultAudioDestinationHandler::Render( AudioBus* destination_bus, size_t number_of_frames, const AudioIOPosition& output_position) { TRACE_EVENT0("webaudio", "DefaultAudioDestinationHandler::Render"); - // We don't want denormals slowing down any of the audio processing - // since they can very seriously hurt performance. This will take care of all - // AudioNodes because they all process within this scope. + // Denormals can seriously hurt performance of audio processing. This will + // take care of all AudioNode processes within this scope. DenormalDisabler denormal_disabler; - // Need to check if the context actually alive. Otherwise the subsequent - // steps will fail. If the context is not alive somehow, return immediately - // and do nothing. - // - // TODO(hongchan): because the context can go away while rendering, so this - // check cannot guarantee the safe execution of the following steps. + // A sanity check for the associated context, but this does not guarantee the + // safe execution of the subsequence operations because the hanlder holds + // the context as |UntracedMember| and it can go away anytime. DCHECK(Context()); if (!Context()) return; Context()->GetDeferredTaskHandler().SetAudioThreadToCurrentThread(); - // If the destination node is not initialized, pass the silence to the final - // audio destination (one step before the FIFO). This check is for the case - // where the destination is in the middle of tearing down process. + // If this node is not initialized yet, pass silence to the platform audio + // destination. It is for the case where this node is in the middle of + // tear-down process. if (!IsInitialized()) { destination_bus->Zero(); return; } - // Let the context take care of any business at the start of each render - // quantum. Context()->HandlePreRenderTasks(output_position); DCHECK_GE(NumberOfInputs(), 1u); @@ -221,8 +181,9 @@ destination_bus->Zero(); return; } - // This will cause the node(s) connected to us to process, which in turn will - // pull on their input(s), all the way backwards through the rendering graph. + + // Renders the graph by pulling all the input(s) to this node. This will in + // turn pull on their input(s), all the way backwards through the graph. AudioBus* rendered_bus = Input(0).Pull(destination_bus, number_of_frames); if (!rendered_bus) { @@ -232,23 +193,54 @@ destination_bus->CopyFrom(*rendered_bus); } - // Process nodes which need a little extra help because they are not connected - // to anything, but still need to process. + // Processes "automatic" nodes that are not connected to anything. Context()->GetDeferredTaskHandler().ProcessAutomaticPullNodes( number_of_frames); - // Let the context take care of any business at the end of each render - // quantum. Context()->HandlePostRenderTasks(); - // Advance current sample-frame. + // Advances the current sample-frame. size_t new_sample_frame = current_sample_frame_ + number_of_frames; ReleaseStore(¤t_sample_frame_, new_sample_frame); Context()->UpdateWorkletGlobalScopeOnRenderingThread(); } -// ---------------------------------------------------------------- +size_t DefaultAudioDestinationHandler::GetCallbackBufferSize() const { + return destination_->CallbackBufferSize(); +} + +int DefaultAudioDestinationHandler::GetFramesPerBuffer() const { + return destination_ ? destination_->FramesPerBuffer() : 0; +} + +void DefaultAudioDestinationHandler::CreateDestination() { + destination_ = AudioDestination::Create(*this, ChannelCount(), latency_hint_); +} + +void DefaultAudioDestinationHandler::StartDestination() { + DCHECK(!destination_->IsPlaying()); + + AudioWorklet* audio_worklet = Context()->audioWorklet(); + if (audio_worklet && audio_worklet->IsReady()) { + // This task runner is only used to fire the audio render callback, so it + // MUST not be throttled to avoid potential audio glitch. + destination_->StartWithWorkletTaskRunner( + audio_worklet->GetMessagingProxy() + ->GetBackingWorkerThread() + ->GetTaskRunner(TaskType::kInternalMedia)); + } else { + destination_->Start(); + } +} + +void DefaultAudioDestinationHandler::StopDestination() { + DCHECK(destination_->IsPlaying()); + + destination_->Stop(); +} + +// ----------------------------------------------------------------------------- DefaultAudioDestinationNode::DefaultAudioDestinationNode( BaseAudioContext& context,
diff --git a/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h b/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h index 8eb2802f..65268ab 100644 --- a/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h +++ b/third_party/blink/renderer/modules/webaudio/default_audio_destination_node.h
@@ -46,21 +46,25 @@ const WebAudioLatencyHint&); ~DefaultAudioDestinationHandler() override; - // AudioHandler + // For AudioHandler. void Dispose() override; void Initialize() override; void Uninitialize() override; void SetChannelCount(unsigned long, ExceptionState&) override; + double LatencyTime() const override { return 0; } + double TailTime() const override { return 0; } + bool RequiresTailProcessing() const final { return false; } - // AudioDestinationHandler + // For AudioDestinationHandler. void StartRendering() override; void StopRendering() override; void RestartRendering() override; unsigned long MaxChannelCount() const override; double SampleRate() const override; - // Implements AudioIOCallback: invoked by Platform AudioDestination to get - // the next render quantum into |destination_bus|. + // For AudioIOCallback. This is invoked by the platform audio destination to + // get the next render quantum into |destination_bus| and update + // |output_position|. void Render(AudioBus* destination_bus, size_t number_of_frames, const AudioIOPosition& output_position) final; @@ -71,28 +75,20 @@ // Returns a given frames-per-buffer size from audio infra. int GetFramesPerBuffer() const; - double TailTime() const override { return 0; } - double LatencyTime() const override { return 0; } - bool RequiresTailProcessing() const final { return false; } - private: explicit DefaultAudioDestinationHandler(AudioNode&, const WebAudioLatencyHint&); + void CreateDestination(); - - // Starts platform/AudioDestination. If the runtime flag for AudioWorklet is - // set, uses the AudioWorkletThread's backing thread for the rendering. void StartDestination(); - void StopDestination(); - // Uses |RefPtr| to keep the AudioDestination alive until all the cross-thread - // tasks are completed. - scoped_refptr<AudioDestination> destination_; - const WebAudioLatencyHint latency_hint_; + scoped_refptr<AudioDestination> destination_; }; +// ----------------------------------------------------------------------------- + class DefaultAudioDestinationNode final : public AudioDestinationNode { public: static DefaultAudioDestinationNode* Create(BaseAudioContext*,
diff --git a/third_party/blink/renderer/modules/xr/OWNERS b/third_party/blink/renderer/modules/xr/OWNERS index 26c48a2..c42d16c5 100644 --- a/third_party/blink/renderer/modules/xr/OWNERS +++ b/third_party/blink/renderer/modules/xr/OWNERS
@@ -1,4 +1,5 @@ bajones@chromium.org klausw@chromium.org -# COMPONENT: Blink>WebVR \ No newline at end of file +# TEAM: xr-dev@chromium.org +# COMPONENT: Blink>WebXR
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc b/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc index c3a1b3b..30682659 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc
@@ -243,9 +243,9 @@ unsigned candidate_break = result_->CachedOffsetForPosition(end_position) + range_start; - unsigned first_safe = (options & kStartShouldBeSafe) - ? result_->CachedNextSafeToBreakOffset(start) - : start; + unsigned first_safe = (options & kDontReshapeStart) + ? start + : result_->CachedNextSafeToBreakOffset(start); DCHECK_GE(first_safe, start); if (candidate_break >= range_end) { // The |result_| does not have glyphs to fill the available space,
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h b/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h index 1ea737f1e..ed4944e 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h +++ b/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h
@@ -66,9 +66,10 @@ // Shapes a line of text by finding a valid and appropriate break opportunity // based on the shaping results for the entire paragraph. enum Options { - // Enforce the start to be safe-to-break. Set for the beginning of each - // wrapped line, but not for subsequent ShapeResults. - kStartShouldBeSafe = 1, + kDefaultOptions = 0, + // Disable reshpaing the start edge even if the start offset is not safe- + // to-break. Set if this is not at the start edge of a wrapped line. + kDontReshapeStart = 1, // Returns nullptr if this line overflows. When the word is very long, such // as URL or data, creating ShapeResult is expensive. Set this option to // suppress if ShapeResult is not needed when this line overflows. @@ -81,7 +82,7 @@ scoped_refptr<ShapeResult> ShapeLine(unsigned start_offset, LayoutUnit available_space, Result* result_out) { - return ShapeLine(start_offset, available_space, kStartShouldBeSafe, + return ShapeLine(start_offset, available_space, kDefaultOptions, result_out); }
diff --git a/third_party/blink/renderer/platform/lifecycle_context_test.cc b/third_party/blink/renderer/platform/lifecycle_context_test.cc index 371431c..1ee87524 100644 --- a/third_party/blink/renderer/platform/lifecycle_context_test.cc +++ b/third_party/blink/renderer/platform/lifecycle_context_test.cc
@@ -45,6 +45,9 @@ void Trace(blink::Visitor* visitor) override { LifecycleNotifier<DummyContext, TestingObserver>::Trace(visitor); } + + // Make the protected method public for testing. + using LifecycleNotifier<DummyContext, TestingObserver>::ForEachObserver; }; class TestingObserver final @@ -91,7 +94,7 @@ bool context_destroyed_called_; }; -TEST(LifecycleContextTest, shouldObserveContextDestroyed) { +TEST(LifecycleContextTest, ShouldObserveContextDestroyed) { DummyContext* context = DummyContext::Create(); Persistent<TestingObserver> observer = TestingObserver::Create(context); @@ -104,7 +107,7 @@ EXPECT_TRUE(observer->ContextDestroyedCalled()); } -TEST(LifecycleContextTest, shouldNotObserveContextDestroyedIfUnobserve) { +TEST(LifecycleContextTest, ShouldNotObserveContextDestroyedIfUnobserve) { DummyContext* context = DummyContext::Create(); Persistent<TestingObserver> observer = TestingObserver::Create(context); observer->Unobserve(); @@ -115,7 +118,7 @@ EXPECT_FALSE(observer->ContextDestroyedCalled()); } -TEST(LifecycleContextTest, observerRemovedDuringNotifyDestroyed) { +TEST(LifecycleContextTest, ObserverRemovedDuringNotifyDestroyed) { DummyContext* context = DummyContext::Create(); Persistent<TestingObserver> observer = TestingObserver::Create(context); TestingObserver* inner_observer = TestingObserver::Create(context); @@ -137,7 +140,7 @@ } // This is a regression test for http://crbug.com/854639. -TEST(LifecycleContextTest, shouldNotHitCFICheckOnIncrementalMarking) { +TEST(LifecycleContextTest, ShouldNotHitCFICheckOnIncrementalMarking) { bool was_enabled = RuntimeEnabledFeatures::HeapIncrementalMarkingEnabled(); RuntimeEnabledFeatures::SetHeapIncrementalMarkingEnabled(true); ThreadState* thread_state = ThreadState::Current(); @@ -161,4 +164,24 @@ RuntimeEnabledFeatures::SetHeapIncrementalMarkingEnabled(was_enabled); } +TEST(LifecycleContextTest, ForEachObserver) { + Persistent<DummyContext> context = DummyContext::Create(); + Persistent<TestingObserver> observer = TestingObserver::Create(context); + + HeapVector<Member<TestingObserver>> seen_observers; + context->ForEachObserver( + [&](TestingObserver* observer) { seen_observers.push_back(observer); }); + + ASSERT_EQ(1u, seen_observers.size()); + EXPECT_EQ(observer.Get(), seen_observers[0].Get()); + + seen_observers.clear(); + observer.Clear(); + ThreadState::Current()->CollectAllGarbage(); + + context->ForEachObserver( + [&](TestingObserver* observer) { seen_observers.push_back(observer); }); + ASSERT_EQ(0u, seen_observers.size()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index 9f2cc12..83ba3d4 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -371,6 +371,8 @@ } Resource* ResourceFetcher::CachedResource(const KURL& resource_url) const { + if (resource_url.IsEmpty()) + return nullptr; KURL url = MemoryCache::RemoveFragmentIdentifierIfNeeded(resource_url); const WeakMember<Resource>& resource = cached_resources_map_.at(url); return resource.Get();
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc index 1ced6f8b..635c78ca 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -910,4 +910,20 @@ EXPECT_FALSE(GetMemoryCache()->Contains(resource)); } +TEST_F(ResourceFetcherTest, CachedResourceShouldNotCrashByNullURL) { + ResourceFetcher* fetcher = ResourceFetcher::Create(Context()); + + // Make sure |cached_resources_map_| is not empty, so that HashMap lookup + // won't take a fast path. + KURL url("http://127.0.0.1:8000/foo.html"); + ResourceResponse response(url); + response.SetHTTPStatusCode(200); + RegisterMockedURLLoadWithCustomResponse(url, response); + FetchParameters fetch_params{ResourceRequest(url)}; + MockResource::Fetch(fetch_params, fetcher, nullptr); + ASSERT_NE(fetcher->CachedResource(url), nullptr); + + ASSERT_EQ(fetcher->CachedResource(KURL()), nullptr); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/platform_export.h b/third_party/blink/renderer/platform/platform_export.h index 50043a2b..c6999a2f 100644 --- a/third_party/blink/renderer/platform/platform_export.h +++ b/third_party/blink/renderer/platform/platform_export.h
@@ -33,9 +33,6 @@ // - PLATFORM_EXPORT // Exports non-template symbols. // -// - PLATFORM_TEMPLATE_CLASS_EXPORT -// Exports an entire definition of class template. -// // - PLATFORM_EXTERN_TEMPLATE_EXPORT // Applicable to template declarations (except for definitions). The // corresponding definition must come along with PLATFORM_TEMPLATE_EXPORT. @@ -85,43 +82,29 @@ #endif // !defined(COMPONENT_BUILD) // -// PLATFORM_TEMPLATE_CLASS_EXPORT // PLATFORM_EXTERN_TEMPLATE_EXPORT // PLATFORM_TEMPLATE_EXPORT // #if BLINK_PLATFORM_IMPLEMENTATION #if defined(COMPILER_MSVC) -#define PLATFORM_TEMPLATE_CLASS_EXPORT #define PLATFORM_EXTERN_TEMPLATE_EXPORT PLATFORM_EXPORT #define PLATFORM_TEMPLATE_EXPORT PLATFORM_EXPORT #endif #if defined(COMPILER_GCC) -#define PLATFORM_TEMPLATE_CLASS_EXPORT PLATFORM_EXPORT #define PLATFORM_EXTERN_TEMPLATE_EXPORT PLATFORM_EXPORT #define PLATFORM_TEMPLATE_EXPORT #endif #else // BLINK_PLATFORM_IMPLEMENTATION -#define PLATFORM_TEMPLATE_CLASS_EXPORT #define PLATFORM_EXTERN_TEMPLATE_EXPORT PLATFORM_EXPORT #define PLATFORM_TEMPLATE_EXPORT #endif // BLINK_PLATFORM_IMPLEMENTATION -#if defined(COMPILER_MSVC) -// MSVC Compiler warning C4275: -// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'. -// Note that this is intended to be used only when no access to the base class' -// static data is done through derived classes or inline methods. For more info, -// see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx -// -// This pragma will allow exporting a class that inherits from a non-exported -// base class, anywhere in the Blink platform component. This is only -// a problem when using the MSVC compiler on Windows. -#pragma warning(suppress : 4275) -#endif +// TODO(thakis): Remove all references to this, https://crbug.com/859989 +#define PLATFORM_TEMPLATE_CLASS_EXPORT #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PLATFORM_EXPORT_H_
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.cc index a973915..f0edb270 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.cc
@@ -10,6 +10,7 @@ #include "services/resource_coordinator/public/cpp/resource_coordinator_features.h" #include "third_party/blink/public/platform/scheduler/renderer_process_type.h" #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h" +#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc index 51c315c8..b08cee4 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -34,6 +34,7 @@ #include "third_party/blink/renderer/platform/scheduler/child/process_state.h" #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h" +#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h" #include "third_party/blink/renderer/platform/wtf/text/movable_string.h" @@ -761,8 +762,10 @@ scoped_refptr<MainThreadTaskQueue> task_queue(helper_.NewTaskQueue(params)); std::unique_ptr<TaskQueue::QueueEnabledVoter> voter; - if (params.can_be_deferred || params.can_be_paused || params.can_be_frozen) + if (params.queue_traits.can_be_deferred || + params.queue_traits.can_be_paused || params.queue_traits.can_be_frozen) { voter = task_queue->CreateQueueEnabledVoter(); + } auto insert_result = task_runners_.insert(std::make_pair(task_queue, std::move(voter)));
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc index 673b276..c7f9dffa 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
@@ -102,10 +102,7 @@ queue_type_(params.queue_type), queue_class_(QueueClassForQueueType(params.queue_type)), fixed_priority_(params.fixed_priority), - can_be_deferred_(params.can_be_deferred), - can_be_throttled_(params.can_be_throttled), - can_be_paused_(params.can_be_paused), - can_be_frozen_(params.can_be_frozen), + queue_traits_(params.queue_traits), freeze_when_keep_active_(params.freeze_when_keep_active), main_thread_scheduler_(main_thread_scheduler), frame_scheduler_(params.frame_scheduler) {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h index e4eb004..8d35990 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -7,7 +7,6 @@ #include "base/task/sequence_manager/task_queue.h" #include "base/task/sequence_manager/task_queue_impl.h" -#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" namespace base { @@ -19,6 +18,7 @@ namespace blink { namespace scheduler { +class FrameSchedulerImpl; class MainThreadSchedulerImpl; class PLATFORM_EXPORT MainThreadTaskQueue @@ -79,15 +79,58 @@ static QueueClass QueueClassForQueueType(QueueType type); + // QueueTraits represent the deferrable, throttleable, pausable, and freezable + // properties of a MainThreadTaskQueue. For non-loading task queues, there + // will be at most one task queue with a specific set of QueueTraits, and the + // the QueueTraits determine which queues should be used to run which task + // types. + struct QueueTraits { + QueueTraits() + : can_be_deferred(false), + can_be_throttled(false), + can_be_paused(false), + can_be_frozen(false) {} + + QueueTraits(const QueueTraits&) = default; + + QueueTraits SetCanBeDeferred(bool value) { + can_be_deferred = value; + return *this; + } + + QueueTraits SetCanBeThrottled(bool value) { + can_be_throttled = value; + return *this; + } + + QueueTraits SetCanBePaused(bool value) { + can_be_paused = value; + return *this; + } + + QueueTraits SetCanBeFrozen(bool value) { + can_be_frozen = value; + return *this; + } + + bool operator==(const QueueTraits& other) const { + return can_be_deferred == other.can_be_deferred && + can_be_throttled == other.can_be_throttled && + can_be_paused == other.can_be_paused && + can_be_frozen == other.can_be_frozen; + } + + bool can_be_deferred : 1; + bool can_be_throttled : 1; + bool can_be_paused : 1; + bool can_be_frozen : 1; + }; + struct QueueCreationParams { explicit QueueCreationParams(QueueType queue_type) : queue_type(queue_type), spec(NameForQueueType(queue_type)), frame_scheduler(nullptr), - can_be_deferred(false), - can_be_throttled(false), - can_be_paused(false), - can_be_frozen(false), freeze_when_keep_active(false) {} QueueCreationParams SetFixedPriority( @@ -97,28 +140,30 @@ return *this; } + QueueCreationParams SetFreezeWhenKeepActive(bool value) { + freeze_when_keep_active = value; + return *this; + } + + // Forwarded calls to |queue_traits| + QueueCreationParams SetCanBeDeferred(bool value) { - can_be_deferred = value; + queue_traits = queue_traits.SetCanBeDeferred(value); return *this; } QueueCreationParams SetCanBeThrottled(bool value) { - can_be_throttled = value; + queue_traits = queue_traits.SetCanBeThrottled(value); return *this; } QueueCreationParams SetCanBePaused(bool value) { - can_be_paused = value; + queue_traits = queue_traits.SetCanBePaused(value); return *this; } QueueCreationParams SetCanBeFrozen(bool value) { - can_be_frozen = value; - return *this; - } - - QueueCreationParams SetFreezeWhenKeepActive(bool value) { - freeze_when_keep_active = value; + queue_traits = queue_traits.SetCanBeFrozen(value); return *this; } @@ -149,10 +194,7 @@ base::Optional<base::sequence_manager::TaskQueue::QueuePriority> fixed_priority; FrameSchedulerImpl* frame_scheduler; - bool can_be_deferred; - bool can_be_throttled; - bool can_be_paused; - bool can_be_frozen; + QueueTraits queue_traits; bool freeze_when_keep_active; }; @@ -167,16 +209,18 @@ return fixed_priority_; } - bool CanBeDeferred() const { return can_be_deferred_; } + bool CanBeDeferred() const { return queue_traits_.can_be_deferred; } - bool CanBeThrottled() const { return can_be_throttled_; } + bool CanBeThrottled() const { return queue_traits_.can_be_throttled; } - bool CanBePaused() const { return can_be_paused_; } + bool CanBePaused() const { return queue_traits_.can_be_paused; } - bool CanBeFrozen() const { return can_be_frozen_; } + bool CanBeFrozen() const { return queue_traits_.can_be_frozen; } bool FreezeWhenKeepActive() const { return freeze_when_keep_active_; } + QueueTraits GetQueueTraits() const { return queue_traits_; } + void OnTaskStarted( const base::sequence_manager::TaskQueue::Task& task, const base::sequence_manager::TaskQueue::TaskTiming& task_timing); @@ -215,10 +259,7 @@ const QueueClass queue_class_; const base::Optional<base::sequence_manager::TaskQueue::QueuePriority> fixed_priority_; - const bool can_be_deferred_; - const bool can_be_throttled_; - const bool can_be_paused_; - const bool can_be_frozen_; + const QueueTraits queue_traits_; const bool freeze_when_keep_active_; // Needed to notify renderer scheduler about completed tasks.
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.cc b/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.cc index 164845c..178b869 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/platform/scheduler/main_thread/queueing_time_estimator.h" +#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include <algorithm>
diff --git a/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h b/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h index eff2e3b..4bf9815d 100644 --- a/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h +++ b/third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h
@@ -7,6 +7,7 @@ #include <deque> +#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h"
diff --git a/third_party/blink/renderer/platform/text/text_encoding_detector.cc b/third_party/blink/renderer/platform/text/text_encoding_detector.cc index 16efbc2..e11100f 100644 --- a/third_party/blink/renderer/platform/text/text_encoding_detector.cc +++ b/third_party/blink/renderer/platform/text/text_encoding_detector.cc
@@ -69,6 +69,11 @@ false, // Include 7-bit encodings to detect ISO-2022-JP &consumed_bytes, &is_reliable); + if (encoding == UNKNOWN_ENCODING) + *detected_encoding = WTF::UnknownEncoding(); + else + *detected_encoding = WTF::TextEncoding(MimeEncodingName(encoding)); + // Should return false if the detected encoding is UTF8. This helps prevent // modern web sites from neglecting proper encoding labelling and simply // relying on browser-side encoding detection. Encoding detection is supposed @@ -76,12 +81,8 @@ // be applied to local file resources). // Detection failure leads |TextResourceDecoder| to use its default encoding // determined from system locale or TLD. - if (encoding == UNKNOWN_ENCODING || - (hint_url.Protocol() != "file" && encoding == UTF8)) - return false; - - *detected_encoding = WTF::TextEncoding(MimeEncodingName(encoding)); - return true; + return !(encoding == UNKNOWN_ENCODING || + (hint_url.Protocol() != "file" && encoding == UTF8)); } } // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/text_encoding.cc b/third_party/blink/renderer/platform/wtf/text/text_encoding.cc index ec064090..809eca13 100644 --- a/third_party/blink/renderer/platform/wtf/text/text_encoding.cc +++ b/third_party/blink/renderer/platform/wtf/text/text_encoding.cc
@@ -144,4 +144,10 @@ return global_windows_latin1_encoding; } +const TextEncoding& UnknownEncoding() { + DEFINE_THREAD_SAFE_STATIC_LOCAL(const TextEncoding, global_unknown_encoding, + ("Unknown")); + return global_unknown_encoding; +} + } // namespace WTF
diff --git a/third_party/blink/renderer/platform/wtf/text/text_encoding.h b/third_party/blink/renderer/platform/wtf/text/text_encoding.h index 07dc5941..f89855c 100644 --- a/third_party/blink/renderer/platform/wtf/text/text_encoding.h +++ b/third_party/blink/renderer/platform/wtf/text/text_encoding.h
@@ -74,15 +74,16 @@ WTF_EXPORT const TextEncoding& ASCIIEncoding(); WTF_EXPORT const TextEncoding& Latin1Encoding(); +WTF_EXPORT const TextEncoding& UnknownEncoding(); WTF_EXPORT const TextEncoding& UTF16BigEndianEncoding(); WTF_EXPORT const TextEncoding& UTF16LittleEndianEncoding(); WTF_EXPORT const TextEncoding& UTF8Encoding(); WTF_EXPORT const TextEncoding& WindowsLatin1Encoding(); - } // namespace WTF using WTF::ASCIIEncoding; using WTF::Latin1Encoding; +using WTF::UnknownEncoding; using WTF::UTF16BigEndianEncoding; using WTF::UTF16LittleEndianEncoding; using WTF::UTF8Encoding;
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/README.chromium b/third_party/blink/tools/blinkpy/third_party/wpt/README.chromium index dfa3b1fc..5545c51 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/README.chromium +++ b/third_party/blink/tools/blinkpy/third_party/wpt/README.chromium
@@ -65,7 +65,7 @@ expiration date. 4. Update certs/127.0.0.1.sxg.*. Please refer to - third_party/WebKit/LayoutTests/http/tests/loading/htxg/resources/README.md + third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/README.md 5. git commit 6. git cl upload, etc.
diff --git a/third_party/gvr-android-keyboard/OWNERS b/third_party/gvr-android-keyboard/OWNERS index 7776b19..fc057fe8 100644 --- a/third_party/gvr-android-keyboard/OWNERS +++ b/third_party/gvr-android-keyboard/OWNERS
@@ -1,4 +1,6 @@ -bshe@chromium.org asimjour@chromium.org +vollick@chromium.org +# TEAM: xr-dev@chromium.org # COMPONENT: UI>Browser>VR +# OS: Android
diff --git a/third_party/gvr-android-keyboard/com/google/vr/keyboard/OWNERS b/third_party/gvr-android-keyboard/com/google/vr/keyboard/OWNERS index 8f094e0..7ffa29f 100644 --- a/third_party/gvr-android-keyboard/com/google/vr/keyboard/OWNERS +++ b/third_party/gvr-android-keyboard/com/google/vr/keyboard/OWNERS
@@ -1,2 +1,6 @@ per-file *.aidl=set noparent per-file *.aidl=file://ipc/SECURITY_OWNERS + +# TEAM: xr-dev@chromium.org +# COMPONENT: UI>Browser>VR +# OS: Android
diff --git a/third_party/gvr-android-sdk/OWNERS b/third_party/gvr-android-sdk/OWNERS index 162c34d..b41e0ac 100644 --- a/third_party/gvr-android-sdk/OWNERS +++ b/third_party/gvr-android-sdk/OWNERS
@@ -1,4 +1,7 @@ bajones@chromium.org -bshe@chromium.org +mthiesse@chromium.org +vollick@chromium.org -# COMPONENT: Internals>VR +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR>VR +# OS: Android
diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn index eca6fbb..89491023 100644 --- a/third_party/harfbuzz-ng/BUILD.gn +++ b/third_party/harfbuzz-ng/BUILD.gn
@@ -179,14 +179,6 @@ "HAVE_ICU_BUILTIN", "HAVE_INTEL_ATOMIC_PRIMITIVES", "HB_NO_MMAP", - - # Define HB_VECTOR_SIZE to be 0 to disable compiler assisted - # vectorization. Compiler assisted vectorization is now disabled in - # upstream until posix_memalign() is used to align corresponding types. - # Compare - # https://chromium.googlesource.com/external/github.com/harfbuzz/harfbuzz/+/058708a665cdd9e796581dbcf60a5778d3f5e240%5E%21/#F0 - # TODO(drott): Remove this after rolling past 1ebaa090d80bf0b59308d2c70f5e58dd8da47450 - "HB_VECTOR_SIZE=0", ] if (is_component_build) {
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium index 29f31ce..2df137705 100644 --- a/third_party/harfbuzz-ng/README.chromium +++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,9 +1,9 @@ Name: harfbuzz-ng Short Name: harfbuzz-ng URL: http://harfbuzz.org -Version: 1.8.2 -Date: 20180703 -Revision: 058708a665cdd9e796581dbcf60a5778d3f5e240 +Version: 1.8.3 +Date: 20180711 +Revision: 2b76767bf572364d3d647cdd139f2044a7ad06b2 Security Critical: yes License: MIT License File: src/COPYING
diff --git a/third_party/libovr/OWNERS b/third_party/libovr/OWNERS index 13a31ee..d484bb05 100644 --- a/third_party/libovr/OWNERS +++ b/third_party/libovr/OWNERS
@@ -1,3 +1,6 @@ bajones@chromium.org billorr@chromium.org ddorwin@chromium.org + +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR>VR
diff --git a/third_party/openvr/OWNERS b/third_party/openvr/OWNERS index 13a31ee..d484bb05 100644 --- a/third_party/openvr/OWNERS +++ b/third_party/openvr/OWNERS
@@ -1,3 +1,6 @@ bajones@chromium.org billorr@chromium.org ddorwin@chromium.org + +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR>VR
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath index 37b476e..ceebbc7d 100644 --- a/tools/android/eclipse/.classpath +++ b/tools/android/eclipse/.classpath
@@ -78,7 +78,7 @@ <classpathentry kind="src" path="components/test/android/browsertests_apk/src"/> <classpathentry kind="src" path="components/url_formatter/android/java/src"/> <classpathentry kind="src" path="components/variations/android/java/src"/> - <classpathentry kind="src" path="components/web_contents_delegate_android/java/src"/> + <classpathentry kind="src" path="components/embedder_suppport/android/java/src"/> <classpathentry kind="src" path="components/web_restrictions/browser/java/src"/> <classpathentry kind="src" path="components/web_restrictions/browser/javatests/src"/> <classpathentry kind="src" path="components/web_restrictions/browser/junit/src"/> @@ -275,7 +275,7 @@ <classpathentry kind="lib" path="out/Debug/lib.java/components/service_tab_launcher/service_tab_launcher_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/components/signin/core/browser/android/java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/components/variations/android/variations_java.jar"/> - <classpathentry kind="lib" path="out/Debug/lib.java/components/web_contents_delegate_android/web_contents_delegate_android_java.jar"/> + <classpathentry kind="lib" path="out/Debug/lib.java/components/embedder_suppport/android/web_contents_delegate_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/content/public/android/content_java.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/device/battery/android/battery_monitor_android.jar"/> <classpathentry kind="lib" path="out/Debug/lib.java/device/battery/mojo_bindings_java.jar"/>
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids index 2c9ca8b..15d8fdc 100644 --- a/tools/gritsettings/resource_ids +++ b/tools/gritsettings/resource_ids
@@ -188,7 +188,7 @@ "components/resources/components_scaled_resources.grd": { "structures": [17200], }, - "components/web_contents_delegate_android/web_contents_delegate_android_strings.grd": { + "components/embedder_suppport/android/java/strings/web_contents_delegate_android_strings.grd": { "messages": [17400], }, # END components/ section.
diff --git a/tools/gritsettings/translation_expectations.pyl b/tools/gritsettings/translation_expectations.pyl index cb6e8d2..83ae19b 100644 --- a/tools/gritsettings/translation_expectations.pyl +++ b/tools/gritsettings/translation_expectations.pyl
@@ -63,7 +63,7 @@ "chrome/android/java/strings/android_chrome_strings.grd", "chrome/android/webapk/strings/android_webapk_strings.grd", "components/autofill/android/java/strings/autofill_strings.grd", - "components/web_contents_delegate_android/java/strings/web_contents_delegate_android_strings.grd", + "components/embedder_support/android/java/strings/web_contents_delegate_android_strings.grd", "content/public/android/java/strings/android_content_strings.grd", "ui/android/java/strings/android_ui_strings.grd", ],
diff --git a/tools/metrics/histograms/README.md b/tools/metrics/histograms/README.md index 138fa98..c11f432 100644 --- a/tools/metrics/histograms/README.md +++ b/tools/metrics/histograms/README.md
@@ -264,7 +264,7 @@ codebase along with marking the histogram definition as obsolete. However, if histogram would remain useful, the expiration should be extended accordingly before it becomes expired. If histogram you care about already expired, see -[Expired Histogram Whitelist](###Expired histogram whitelist). +[Expired Histogram Whitelist](#Expired-histogram-whitelist). For all the new histograms the use of expiry attribute will be strongly encouraged and enforced by Chrome metrics team through reviews.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index c11f8f2..e00ff86f 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -27735,6 +27735,7 @@ <int value="-1349896789" label="DelayNavigation:enabled"/> <int value="-1349872906" label="disallow-autofill-sync-credential-for-reauth"/> + <int value="-1349826793" label="ArcInputMethod:disabled"/> <int value="-1349532167" label="enable-wifi-credential-sync"/> <int value="-1346722635" label="gesture-selection"/> <int value="-1344375439" label="ServiceWorkerPaymentApps:disabled"/> @@ -27784,6 +27785,7 @@ <int value="-1255427595" label="HomePageButtonForceEnabled:enabled"/> <int value="-1254070521" label="enable-slimming-paint-invalidation"/> <int value="-1251411236" label="disable-new-md-input-view"/> + <int value="-1250611337" label="ChromeVoxArcSupport:disabled"/> <int value="-1248478422" label="enable-zip-archiver-packer"/> <int value="-1246840031" label="OptInImeMenu:disabled"/> <int value="-1241747717" label="enable-android-password-link"/> @@ -27858,6 +27860,7 @@ <int value="-1096595907" label="disable-new-virtual-keyboard-behavior"/> <int value="-1095947169" label="ModalPermissionDialogView:disabled"/> <int value="-1085492638" label="FetchKeepaliveTimeoutSetting:enabled"/> + <int value="-1084855234" label="UnfilteredBluetoothDevices:disabled"/> <int value="-1084055006" label="disable-web-notification-custom-layouts"/> <int value="-1082302549" label="scan-cards-in-web-payments"/> <int value="-1078093206" label="ash-debug-shortcuts"/> @@ -28150,6 +28153,7 @@ <int value="-471405972" label="ViewsProfileChooser:disabled"/> <int value="-471085510" label="MultiDeviceApi:enabled"/> <int value="-470948890" label="OfflinePagesDescriptivePendingStatus:enabled"/> + <int value="-468697885" label="ArcInputMethod:enabled"/> <int value="-462205750" label="enable-service-worker-sync"/> <int value="-461292699" label="ContentSuggestionsCategoryOrder:enabled"/> <int value="-460313418" label="ProgressBarThrottle:enabled"/> @@ -28245,6 +28249,7 @@ <int value="-270626757" label="log-net-log"/> <int value="-268357961" label="enable-feature-policy"/> <int value="-263150202" label="BundledConnectionHelp:disabled"/> + <int value="-260355779" label="UnfilteredBluetoothDevices:enabled"/> <int value="-254887599" label="google-profile-info"/> <int value="-250822813" label="PwaImprovedSplashScreen:enabled"/> <int value="-250721831" label="AndroidAutofillAccessibility:disabled"/> @@ -28325,6 +28330,7 @@ <int value="-68877684" label="BackgroundVideoTrackOptimization:enabled"/> <int value="-68225452" label="enable-translate-new-ux"/> <int value="-67297229" label="OfflinePagesDescriptivePendingStatus:disabled"/> + <int value="-59530055" label="ChromeVoxArcSupport:enabled"/> <int value="-59401847" label="ContentSuggestionsLargeThumbnail:disabled"/> <int value="-58242474" label="ash-disable-swipe-to-close-in-overview-mode"/> <int value="-57986995" label="DisablePostScriptPrinting:enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 4269468a..5c5d771 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -27278,6 +27278,17 @@ </summary> </histogram> +<histogram name="Extensions.DeclarativeNetRequest.RulesetReindexSuccessful" + enum="BooleanSuccess" expires_after="2019-06-30"> + <owner>karandeepb@chromium.org</owner> + <owner>lazyboy@chromium.org</owner> + <summary> + Indicates whether reindexing of the Declarative Net Request ruleset was + successful. Called whenever the JSON ruleset for an extension is reindexed, + e.g. on ruleset corruption. + </summary> +</histogram> + <histogram name="Extensions.DeclarativeNetRequest.ShouldBlockRequestTime.AllExtensions" units="ms"> @@ -59101,6 +59112,16 @@ </summary> </histogram> +<histogram name="NewTabPage.BackgroundService.Photos.RequestLatency" units="ms" + expires_after="M74"> + <owner>ramyan@chromium.org</owner> + <owner>yyushkina@chromium.org</owner> + <summary> + The time it took until a request from the New Tab Page for Google Photos (in + a specific album) was served. + </summary> +</histogram> + <histogram name="NewTabPage.BookmarkActionAndroid" enum="NewTabPageBookmarkActionAndroid"> <obsolete> @@ -81455,6 +81476,16 @@ </summary> </histogram> +<histogram name="ResourceLoadingHints.CountBlockedSubresourcePatterns" + units="pattern count"> + <owner>tbansal@chromium.org</owner> + <summary> + The count of resource loading blocking patterns received by the renderer. + Recorded every time resource loading hints mojom message is received. + Recorded at most once per triggered navigation. + </summary> +</histogram> + <histogram name="ResourcePrefetchPredictor.CachePattern" enum="HttpCachePattern"> <obsolete>
diff --git a/tools/perf/contrib/vr_benchmarks/OWNERS b/tools/perf/contrib/vr_benchmarks/OWNERS index 20354672..37b7186 100644 --- a/tools/perf/contrib/vr_benchmarks/OWNERS +++ b/tools/perf/contrib/vr_benchmarks/OWNERS
@@ -3,3 +3,6 @@ # These users are familiar with the code, but not actually committers leilei@chromium.org + +# TEAM: xr-dev@chromium.org +# COMPONENT: Internals>XR>VR
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index 0c7793a..ff4b3f2 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -123,6 +123,7 @@ <item id="gcm_unregistration" hash_code="119542033" type="0" content_hash_code="30144127" os_list="linux,windows" file_path="google_apis/gcm/engine/unregistration_request.cc"/> <item id="geo_language_provider" hash_code="52821843" type="1" second_id="96590038" content_hash_code="104675663" os_list="linux,windows" semantics_fields="1" policy_fields="3,4" file_path="components/language/content/browser/geo_language_provider.cc"/> <item id="google_photos_album_names_download" hash_code="65075134" type="0" content_hash_code="124531309" os_list="linux,windows" file_path="chrome/browser/search/background/ntp_background_service.cc"/> + <item id="google_photos_metadata_download" hash_code="93441068" type="0" content_hash_code="48786223" os_list="linux,windows" file_path="chrome/browser/search/background/ntp_background_service.cc"/> <item id="google_url_tracker" hash_code="5492492" type="0" content_hash_code="54474899" os_list="linux,windows" file_path="components/google/core/browser/google_url_tracker.cc"/> <item id="headless_url_request" hash_code="29865866" type="0" deprecated="2018-07-10" content_hash_code="76700151" file_path=""/> <item id="history_notice_utils_notice" hash_code="102595701" type="1" second_id="110307337" content_hash_code="130829410" os_list="linux,windows" semantics_fields="2,3,4" policy_fields="4" file_path="components/browsing_data/core/history_notice_utils.cc"/>
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index 8b86e76..7eab9252 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -6164,6 +6164,12 @@ *old_len = 0; *new_len = 0; + // Do not compute for static text objects, otherwise redundant text change + // announcements will occur in live regions, as the parent hypertext also + // changes. + if (GetData().role == ax::mojom::Role::kStaticText) + return; + const base::string16& old_text = old_hypertext_.hypertext; const base::string16& new_text = hypertext_.hypertext;
diff --git a/ui/android/java/res/values-v17/styles.xml b/ui/android/java/res/values-v17/styles.xml index 2520b68..2216725 100644 --- a/ui/android/java/res/values-v17/styles.xml +++ b/ui/android/java/res/values-v17/styles.xml
@@ -77,15 +77,15 @@ <item name="android:textSize">@dimen/text_size_medium</item> </style> <style name="BlackDisabledText1" tools:ignore="UnusedResources"> - <item name="android:textColor">@color/black_alpha_38</item> + <item name="android:textColor">@color/disabled_text_color</item> <item name="android:textSize">@dimen/text_size_large</item> </style> <style name="BlackDisabledText2" tools:ignore="UnusedResources"> - <item name="android:textColor">@color/black_alpha_38</item> + <item name="android:textColor">@color/disabled_text_color</item> <item name="android:textSize">@dimen/text_size_small</item> </style> <style name="BlackDisabledText3" tools:ignore="UnusedResources"> - <item name="android:textColor">@color/black_alpha_38</item> + <item name="android:textColor">@color/disabled_text_color</item> <item name="android:textSize">@dimen/text_size_medium</item> </style> <style name="BlackBodyDefault" tools:ignore="UnusedResources">
diff --git a/ui/android/java/res/values/colors.xml b/ui/android/java/res/values/colors.xml index 43cba5ad..f6dfe2f8 100644 --- a/ui/android/java/res/values/colors.xml +++ b/ui/android/java/res/values/colors.xml
@@ -17,5 +17,6 @@ <color name="dropdown_divider_color">#E5E5E5</color> <color name="dropdown_dark_divider_color">#C0C0C0</color> + <color name="disabled_text_color">@color/black_alpha_38</color> </resources>
diff --git a/ui/display/manager/display_configurator.cc b/ui/display/manager/display_configurator.cc index 5bae8f7..a780b56 100644 --- a/ui/display/manager/display_configurator.cc +++ b/ui/display/manager/display_configurator.cc
@@ -77,8 +77,7 @@ bool DisplayConfigurator::TestApi::TriggerConfigureTimeout() { if (configurator_->configure_timer_.IsRunning()) { - configurator_->configure_timer_.user_task().Run(); - configurator_->configure_timer_.Stop(); + configurator_->configure_timer_.FireNow(); return true; } else { return false;
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc index f1d70c2..faef2c2 100644 --- a/ui/keyboard/keyboard_controller.cc +++ b/ui/keyboard/keyboard_controller.cc
@@ -224,6 +224,9 @@ // Observe changes to root window bounds. parent_container_->GetRootWindow()->AddObserver(this); + // TODO(https://crbug.com/845780): Investigate whether this does anything. + OnTextInputStateChanged(ui_->GetInputMethod()->GetTextInputClient()); + if (GetKeyboardWindow()) { DCHECK(!GetKeyboardWindow()->parent()); parent_container_->AddChild(GetKeyboardWindow()); @@ -506,12 +509,6 @@ ShowKeyboardInternal(display); } -void KeyboardController::OnWindowHierarchyChanged( - const HierarchyChangeParams& params) { - if (params.new_parent && params.target == GetKeyboardWindow()) - OnTextInputStateChanged(GetTextInputClient()); -} - void KeyboardController::OnWindowAddedToRootWindow(aura::Window* window) { container_behavior_->SetCanonicalBounds(GetKeyboardWindow(), GetRootWindow()->bounds()); @@ -659,19 +656,16 @@ case KeyboardControllerState::WILL_HIDE: ChangeState(KeyboardControllerState::SHOWN); return; - case KeyboardControllerState::HIDDEN: { - // If the container is not animating, makes sure the position and opacity - // are at begin states for animation. - container_behavior_->InitializeShowAnimationStartingState( - keyboard_window); - break; - } default: - NOTREACHED(); + break; } DCHECK_EQ(state_, KeyboardControllerState::HIDDEN); + // If the container is not animating, makes sure the position and opacity + // are at begin states for animation. + container_behavior_->InitializeShowAnimationStartingState(keyboard_window); + keyboard::LogKeyboardControlEvent(keyboard::KEYBOARD_CONTROL_SHOW); RecordUkmKeyboardShown();
diff --git a/ui/keyboard/keyboard_controller.h b/ui/keyboard/keyboard_controller.h index ad3d69c..48dca73 100644 --- a/ui/keyboard/keyboard_controller.h +++ b/ui/keyboard/keyboard_controller.h
@@ -268,7 +268,6 @@ }; // aura::WindowObserver overrides - void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; void OnWindowAddedToRootWindow(aura::Window* window) override; void OnWindowBoundsChanged(aura::Window* window, const gfx::Rect& old_bounds,
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc index 1331dd9a..64d821d3 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.cc +++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -311,9 +311,40 @@ NativeWidgetAura::SetShadowElevationFromInitParams(window(), params); - // Transient parents are connected using the Window created by WindowTreeHost, - // which is owned by the window manager. This way the window manager can - // properly identify and honor transients. + // Widget's |InitParams::parent| has different meanings depending on the + // NativeWidgetPrivate implementation that the Widget creates (each Widget + // creates a NativeWidgetPrivate). When DesktopNativeWidgetAura is used as + // the NativeWidgetPrivate implementation, |InitParams::parent| means the + // entirety of the contents of the new Widget should be stacked above the + // entirety of the contents of the Widget for |InitParams::parent|, and + // the new Widget should be deleted when the Widget for + // |InitParams::parent| is deleted. Aura and mus provide support for + // transient windows, which provides both the stacking and ownership needed to + // support |InitParams::parent|. + // + // DesktopNativeWidgetAura internally creates two aura::Windows (one by + // WindowTreeHost, the other in |DesktopNativeWidgetAura::content_window_|). + // To have the entirety of the contents of the Widget appear on top of the + // entirety of the contents of another Widget, the stacking is done on the + // WindowTreeHost's window. For these reasons, the following code uses the + // Window associated with the WindowTreeHost of the |params.parent|. + // + // Views/Aura provide support for child-modal windows. Child-modal windows + // are windows that are modal to their transient parent. Because this code + // implements |InitParams::parent| in terms of transient parents, it means + // it is not possible to support both |InitParams::parent| as well as a + // child-modal window. This is *only* an issue if a Widget that uses a + // DesktopNativeWidgetAura needs to be child-modal to another window. At + // the current time NativeWidgetAura is always used for child-modal windows, + // so this isn't an issue. + // + // If we end up needing to use DesktopNativeWidgetAura for child-modal + // Widgets then we need something different. Possibilities include: + // . Have mus ignore child-modal windows and instead implement child-modal + // entirely in the client (this is what we do on Windows). To get this + // right likely means we need the ability to disable windows (see + // HWNDMessageHandler::InitModalType() for how Windows OS does this). + // . Implement |InitParams::parent| using a different (new) API. if (params.parent && params.parent->GetHost()) { aura::client::GetTransientWindowClient()->AddTransientChild( params.parent->GetHost()->window(), window()); @@ -733,6 +764,9 @@ } void DesktopWindowTreeHostMus::InitModalType(ui::ModalType modal_type) { + // See comment in Init() related to |InitParams::parent| as to why this DCHECK + // is here. + DCHECK_NE(modal_type, ui::MODAL_TYPE_CHILD); window()->SetProperty(aura::client::kModalKey, modal_type); }
diff --git a/ui/webui/resources/cr_elements/icons.html b/ui/webui/resources/cr_elements/icons.html index 1365bd7..186e3c61 100644 --- a/ui/webui/resources/cr_elements/icons.html +++ b/ui/webui/resources/cr_elements/icons.html
@@ -38,6 +38,7 @@ <g id="clear"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g> <g id="close"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g> <g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></g> + <g id="error"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"></path></g> <g id="error-outline"><path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path></g> <g id="expand-less"><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"></path></g> <g id="expand-more"><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"></path></g> @@ -46,6 +47,7 @@ <g id="folder"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path></g> <g id="fullscreen"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"></path></g> <g id="group"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"></path></g> + <g id="info"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"></path></g> <g id="more-vert"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></g> <g id="open-in-new"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"></path></g> <g id="person"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path></g>
diff --git a/webrunner/BUILD.gn b/webrunner/BUILD.gn index c8c41d3..fa80954 100644 --- a/webrunner/BUILD.gn +++ b/webrunner/BUILD.gn
@@ -47,7 +47,7 @@ group("webrunner") { testonly = true deps = [ - ":service_exe", + ":service_pkg", ":service_unittests", ] } @@ -112,8 +112,12 @@ "common/webrunner_content_client.cc", "common/webrunner_content_client.h", "common/webrunner_export.h", - "service/context_provider/context_provider_impl.cc", - "service/context_provider/context_provider_impl.h", + "service/context_impl.cc", + "service/context_impl.h", + "service/context_provider_impl.cc", + "service/context_provider_impl.h", + "service/frame_impl.cc", + "service/frame_impl.h", "service/switches.cc", "service/switches.h", "service/webrunner_main_delegate.cc", @@ -161,7 +165,7 @@ test("service_unittests") { sources = [ - "service/context_provider/context_provider_impl_unittest.cc", + "service/context_provider_impl_unittest.cc", ] deps = [ ":fidl",
diff --git a/webrunner/service/common.h b/webrunner/service/common.h new file mode 100644 index 0000000..67ec6ed --- /dev/null +++ b/webrunner/service/common.h
@@ -0,0 +1,16 @@ +// 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. + +#ifndef WEBRUNNER_SERVICE_COMMON_H_ +#define WEBRUNNER_SERVICE_COMMON_H_ + +#include <zircon/processargs.h> + +namespace webrunner { + +const uint32_t kContextRequestHandleId = PA_HND(PA_USER0, 0); + +} // namespace webrunner + +#endif // WEBRUNNER_SERVICE_COMMON_H_
diff --git a/webrunner/service/context_impl.cc b/webrunner/service/context_impl.cc new file mode 100644 index 0000000..93ec376 --- /dev/null +++ b/webrunner/service/context_impl.cc
@@ -0,0 +1,26 @@ +// 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. + +#include "webrunner/service/context_impl.h" + +#include <memory> +#include <utility> + +#include "webrunner/service/frame_impl.h" + +namespace webrunner { + +ContextImpl::ContextImpl() = default; + +ContextImpl::~ContextImpl() = default; + +void ContextImpl::CreateFrame( + ::fidl::InterfaceHandle<chromium::web::FrameObserver> observer, + ::fidl::InterfaceRequest<chromium::web::Frame> frame_request) { + std::unique_ptr<chromium::web::Frame> frame = + std::make_unique<FrameImpl>(observer.Bind()); + frame_bindings_.AddBinding(std::move(frame), std::move(frame_request)); +} + +} // namespace webrunner
diff --git a/webrunner/service/context_impl.h b/webrunner/service/context_impl.h new file mode 100644 index 0000000..c13500b --- /dev/null +++ b/webrunner/service/context_impl.h
@@ -0,0 +1,41 @@ +// 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. + +#ifndef WEBRUNNER_SERVICE_CONTEXT_IMPL_H_ +#define WEBRUNNER_SERVICE_CONTEXT_IMPL_H_ + +#include <lib/fidl/cpp/binding_set.h> +#include <memory> + +#include "base/macros.h" +#include "chromium/web/cpp/fidl.h" +#include "webrunner/common/webrunner_export.h" + +namespace webrunner { + +// Implementation of Context from //webrunner/fidl/context.fidl. +// Owns a BrowserContext instance and uses it to create new WebContents/Frames. +// All created Frames are owned by this object. +class WEBRUNNER_EXPORT ContextImpl : public chromium::web::Context { + public: + ContextImpl(); + + // Tears down the Context, destroying any active Frames in the process. + ~ContextImpl() override; + + // chromium::web::Context implementation. + void CreateFrame( + ::fidl::InterfaceHandle<chromium::web::FrameObserver> observer, + ::fidl::InterfaceRequest<chromium::web::Frame> frame) override; + + private: + fidl::BindingSet<chromium::web::Frame, std::unique_ptr<chromium::web::Frame>> + frame_bindings_; + + DISALLOW_COPY_AND_ASSIGN(ContextImpl); +}; + +} // namespace webrunner + +#endif // WEBRUNNER_SERVICE_CONTEXT_IMPL_H_
diff --git a/webrunner/service/context_provider/context_provider_impl.cc b/webrunner/service/context_provider_impl.cc similarity index 94% rename from webrunner/service/context_provider/context_provider_impl.cc rename to webrunner/service/context_provider_impl.cc index 926e1fdb..6cf3216 100644 --- a/webrunner/service/context_provider/context_provider_impl.cc +++ b/webrunner/service/context_provider_impl.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 "webrunner/service/context_provider/context_provider_impl.h" +#include "webrunner/service/context_provider_impl.h" #include <fuchsia/sys/cpp/fidl.h> #include <lib/zx/job.h> @@ -17,6 +17,7 @@ #include "base/fuchsia/fuchsia_logging.h" #include "base/logging.h" #include "base/process/launch.h" +#include "webrunner/service/common.h" #include "webrunner/service/switches.h" namespace webrunner { @@ -58,7 +59,7 @@ base::LaunchOptions launch_options; zx::channel context_handle(context_request.TakeChannel()); launch_options.handles_to_transfer.push_back( - {PA_HND(PA_USER0, 0), context_handle.get()}); + {kContextRequestHandleId, context_handle.get()}); // Isolate the child Context processes by containing them within their own // respective jobs.
diff --git a/webrunner/service/context_provider/context_provider_impl.h b/webrunner/service/context_provider_impl.h similarity index 88% rename from webrunner/service/context_provider/context_provider_impl.h rename to webrunner/service/context_provider_impl.h index 54d97b3a..0305eea9 100644 --- a/webrunner/service/context_provider/context_provider_impl.h +++ b/webrunner/service/context_provider_impl.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 WEBRUNNER_SERVICE_CONTEXT_PROVIDER_CONTEXT_PROVIDER_IMPL_H_ -#define WEBRUNNER_SERVICE_CONTEXT_PROVIDER_CONTEXT_PROVIDER_IMPL_H_ +#ifndef WEBRUNNER_SERVICE_CONTEXT_PROVIDER_IMPL_H_ +#define WEBRUNNER_SERVICE_CONTEXT_PROVIDER_IMPL_H_ #include <lib/fidl/cpp/binding_set.h> @@ -55,4 +55,4 @@ } // namespace webrunner -#endif // WEBRUNNER_SERVICE_CONTEXT_PROVIDER_CONTEXT_PROVIDER_IMPL_H_ +#endif // WEBRUNNER_SERVICE_CONTEXT_PROVIDER_IMPL_H_
diff --git a/webrunner/service/context_provider/context_provider_impl_unittest.cc b/webrunner/service/context_provider_impl_unittest.cc similarity index 62% rename from webrunner/service/context_provider/context_provider_impl_unittest.cc rename to webrunner/service/context_provider_impl_unittest.cc index ce86354..9244d57 100644 --- a/webrunner/service/context_provider/context_provider_impl_unittest.cc +++ b/webrunner/service/context_provider_impl_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 "webrunner/service/context_provider/context_provider_impl.h" +#include "webrunner/service/context_provider_impl.h" #include <lib/fidl/cpp/binding.h> #include <zircon/processargs.h> @@ -12,31 +12,42 @@ #include "base/base_switches.h" #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/command_line.h" #include "base/files/file.h" #include "base/fuchsia/file_utils.h" #include "base/message_loop/message_loop.h" #include "base/test/multiprocess_test.h" -#include "testing/gmock/include/gmock/gmock-actions.h" -#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/multiprocess_func_list.h" +#include "webrunner/service/common.h" namespace webrunner { namespace { -class MockFrameObserver : public chromium::web::FrameObserver { +class TestFrameObserver : public chromium::web::FrameObserver { public: void OnNavigationStateChanged( chromium::web::NavigationStateChangeDetails change, OnNavigationStateChangedCallback callback) override { - OnNavigationStateChanged(); + last_change_ = change; + if (change_callback_) + std::move(change_callback_).Run(); + callback(); } - MOCK_METHOD0(OnNavigationStateChanged, void(void)); -}; + void SetNextChangeCallback(base::OnceClosure callback) { + change_callback_ = std::move(callback); + } -void DoNothing() {} + chromium::web::NavigationStateChangeDetails last_change() { + return last_change_; + } + + private: + chromium::web::NavigationStateChangeDetails last_change_ = {}; + base::OnceClosure change_callback_; +}; class FakeContext : public chromium::web::Context { public: @@ -44,22 +55,27 @@ ::fidl::InterfaceHandle<chromium::web::FrameObserver> observer, ::fidl::InterfaceRequest<chromium::web::Frame> frame) override { chromium::web::NavigationStateChangeDetails details; + details.url_changed = true; details.entry.url = ""; details.entry.title = ""; - observer.Bind()->OnNavigationStateChanged(details, &DoNothing); + observer.Bind()->OnNavigationStateChanged(details, []() {}); } }; MULTIPROCESS_TEST_MAIN(SpawnContextServer) { base::MessageLoopForIO message_loop; FakeContext fake_context; - zx_handle_t context_handle = zx_take_startup_handle(PA_HND(PA_USER0, 0)); - CHECK_NE(ZX_HANDLE_INVALID, context_handle); + zx::channel context_handle{zx_take_startup_handle(kContextRequestHandleId)}; + CHECK(context_handle); fidl::Binding<chromium::web::Context> binding(&fake_context, - zx::channel(context_handle)); + std::move(context_handle)); - // Service the MessageLoop until the child process is torn down. - base::RunLoop().Run(); + base::RunLoop run_loop; + + // Quit the process when the context is destroyed. + binding.set_error_handler([&run_loop]() { run_loop.Quit(); }); + + run_loop.Run(); return 0; } @@ -72,12 +88,10 @@ &ContextProviderImplTest::LaunchProcess, base::Unretained(this))); provider_.Bind(provider_ptr_.NewRequest()); } - ~ContextProviderImplTest() override = default; - void TearDown() override { - for (auto& process : context_processes_) { - process.Terminate(0, true); - } + ~ContextProviderImplTest() override { + provider_ptr_.Unbind(); + base::RunLoop().RunUntilIdle(); } // Start a new child process whose main function is defined in @@ -86,9 +100,8 @@ auto cmdline = base::GetMultiProcessTestChildBaseCommandLine(); cmdline.AppendSwitchASCII(switches::kTestChildProcess, "SpawnContextServer"); - auto context_process = base::LaunchProcess(cmdline, options); + base::Process context_process = base::LaunchProcess(cmdline, options); EXPECT_TRUE(context_process.IsValid()); - context_processes_.push_back(context_process.Duplicate()); return context_process; } @@ -98,59 +111,52 @@ ContextProviderImpl provider_; chromium::web::ContextProviderPtr provider_ptr_; - // The spawned Process object for a Context. - std::vector<base::Process> context_processes_; - private: DISALLOW_COPY_AND_ASSIGN(ContextProviderImplTest); }; TEST_F(ContextProviderImplTest, LaunchContext) { // Connect to a new context process. - auto data_dir = base::fuchsia::GetHandleFromFile(base::File( - base::FilePath("/data"), base::File::FLAG_OPEN | base::File::FLAG_READ)); fidl::InterfacePtr<chromium::web::Context> context; chromium::web::CreateContextParams create_params; provider_ptr_->Create(std::move(create_params), context.NewRequest()); // Call a Context method and wait for it to invoke an observer call. - MockFrameObserver frame_observer; + TestFrameObserver frame_observer; chromium::web::FramePtr frame_ptr; fidl::Binding<chromium::web::FrameObserver> frame_observer_binding( &frame_observer); - base::RunLoop r; - EXPECT_CALL(frame_observer, OnNavigationStateChanged()) - .WillOnce(testing::Invoke(&r, &base::RunLoop::Quit)); + base::RunLoop run_loop; + frame_observer.SetNextChangeCallback(run_loop.QuitClosure()); context->CreateFrame(frame_observer_binding.NewBinding(), frame_ptr.NewRequest()); - r.Run(); + run_loop.Run(); + + EXPECT_TRUE(frame_observer.last_change().url_changed || + frame_observer.last_change().title_changed); } +// Verify that there can be more than one connection to the provider. TEST_F(ContextProviderImplTest, MultipleClients) { - { - chromium::web::ContextProviderPtr provider_2_ptr; - provider_.Bind(provider_2_ptr.NewRequest()); + chromium::web::ContextProviderPtr provider_1_ptr; + provider_.Bind(provider_1_ptr.NewRequest()); - // Allow provider_2_ptr to go out of scope and disconnect. - } - - // Connect with a third client. - chromium::web::ContextProviderPtr provider_3_ptr; - provider_.Bind(provider_3_ptr.NewRequest()); + // Connect a second client. + chromium::web::ContextProviderPtr provider_2_ptr; + provider_.Bind(provider_2_ptr.NewRequest()); fidl::InterfacePtr<chromium::web::Context> context; chromium::web::CreateContextParams create_params; - provider_3_ptr->Create(std::move(create_params), context.NewRequest()); + provider_2_ptr->Create(std::move(create_params), context.NewRequest()); - MockFrameObserver frame_observer; + TestFrameObserver frame_observer; chromium::web::FramePtr frame_ptr; fidl::Binding<chromium::web::FrameObserver> frame_observer_binding( &frame_observer); - base::RunLoop r; - EXPECT_CALL(frame_observer, OnNavigationStateChanged()) - .WillOnce(testing::Invoke(&r, &base::RunLoop::Quit)); + base::RunLoop run_loop; + frame_observer.SetNextChangeCallback(run_loop.QuitClosure()); context->CreateFrame(frame_observer_binding.NewBinding(), frame_ptr.NewRequest()); - r.Run(); + run_loop.Run(); } } // namespace webrunner
diff --git a/webrunner/service/frame_impl.cc b/webrunner/service/frame_impl.cc new file mode 100644 index 0000000..ad8874a --- /dev/null +++ b/webrunner/service/frame_impl.cc
@@ -0,0 +1,54 @@ +// 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. + +#include "webrunner/service/frame_impl.h" + +#include "base/logging.h" + +namespace webrunner { + +FrameImpl::FrameImpl(chromium::web::FrameObserverPtr observer) + : observer_(std::move(observer)) {} + +FrameImpl::~FrameImpl() = default; + +void FrameImpl::CreateView( + ::fidl::InterfaceRequest<fuchsia::ui::views_v1_token::ViewOwner> view_owner, + ::fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> services) { + NOTIMPLEMENTED(); +} + +void FrameImpl::GetNavigationController( + ::fidl::InterfaceRequest<chromium::web::NavigationController> controller) { + controller_bindings_.AddBinding(this, std::move(controller)); +} + +void FrameImpl::LoadUrl( + ::fidl::StringPtr url, + ::std::unique_ptr<chromium::web::LoadUrlParams> params) { + NOTIMPLEMENTED() << "Loading URL " << *url; +} + +void FrameImpl::GoBack() { + NOTIMPLEMENTED(); +} + +void FrameImpl::GoForward() { + NOTIMPLEMENTED(); +} + +void FrameImpl::Stop() { + NOTIMPLEMENTED(); +} + +void FrameImpl::Reload() { + NOTIMPLEMENTED(); +} + +void FrameImpl::GetVisibleEntry(GetVisibleEntryCallback callback) { + NOTIMPLEMENTED(); + callback(nullptr); +} + +} // namespace webrunner
diff --git a/webrunner/service/frame_impl.h b/webrunner/service/frame_impl.h new file mode 100644 index 0000000..45e867c --- /dev/null +++ b/webrunner/service/frame_impl.h
@@ -0,0 +1,53 @@ +// 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. + +#ifndef WEBRUNNER_SERVICE_FRAME_IMPL_H_ +#define WEBRUNNER_SERVICE_FRAME_IMPL_H_ + +#include <lib/fidl/cpp/binding_set.h> +#include <memory> +#include <utility> + +#include "base/macros.h" +#include "chromium/web/cpp/fidl.h" + +namespace webrunner { + +// Implementation of Frame from //webrunner/fidl/frame.fidl. +// Implements a Frame service, which is a wrapper for a WebContents instance. +class FrameImpl : public chromium::web::Frame, + public chromium::web::NavigationController { + public: + explicit FrameImpl(chromium::web::FrameObserverPtr observer); + ~FrameImpl() override; + + // chromium::web::Frame implementation. + void CreateView( + ::fidl::InterfaceRequest<fuchsia::ui::views_v1_token::ViewOwner> + view_owner, + ::fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> services) + override; + void GetNavigationController( + ::fidl::InterfaceRequest<chromium::web::NavigationController> controller) + override; + + // chromium::web::NavigationController implementation. + void LoadUrl(::fidl::StringPtr url, + ::std::unique_ptr<chromium::web::LoadUrlParams> params) override; + void GoBack() override; + void GoForward() override; + void Stop() override; + void Reload() override; + void GetVisibleEntry(GetVisibleEntryCallback callback) override; + + private: + chromium::web::FrameObserverPtr observer_; + fidl::BindingSet<chromium::web::NavigationController> controller_bindings_; + + DISALLOW_COPY_AND_ASSIGN(FrameImpl); +}; + +} // namespace webrunner + +#endif // WEBRUNNER_SERVICE_FRAME_IMPL_H_