diff --git a/DEPS b/DEPS index 5a1b8b2..05634da0 100644 --- a/DEPS +++ b/DEPS
@@ -142,11 +142,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': '4e6a4416e5df9dd16d2d39172511a6d45cc86e35', + 'skia_revision': 'f6da14697e15a91e68c49571385bcc5d3bea8db3', # 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': 'e545aee43105b9d8278377f25c4b23a62a1282c5', + 'v8_revision': '2206e55ad023327a744c06084a594944486d0ef8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -154,15 +154,15 @@ # 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': '8db211bc8d28156af958549c0d8a2669db87936a', + 'angle_revision': '60e2f11eb584a80bcdd7e672e00cf7d1c594c5ee', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '28ae0a4b2810b9f72547382333f32e0a46d87709', + 'swiftshader_revision': '4cd9767e65651b636034aee688e502a8fbe6e559', # 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': '9231ac5e1c6884555571fa2541fcbc10ff97a180', + 'pdfium_revision': '3ec47b651aaa7d2d45640280e4625824a643e669', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -205,7 +205,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '3efcccc6e77a54776a37f796183aa92c575060b5', + 'catapult_revision': '14d669b045c865befc9b4e8bcf1295b78522a7aa', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -806,7 +806,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '9ec162df61d3ff15a3913c5f616d5de538b82369', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '992dcfc16c3ca68a57d0fda3ca3838199898f468', 'condition': 'checkout_linux', }, @@ -900,7 +900,7 @@ }, 'src/third_party/glslang/src': - Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'c538b5d796fb24dd418fdd650c7f76e56bcc3dd8', + Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '71892a5eda90fd7d3d6ccc12745f066d0ca5dc5f', 'src/third_party/google_toolbox_for_mac/src': { 'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), @@ -1057,7 +1057,7 @@ }, 'src/third_party/libjpeg_turbo': - Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '76aabbd351eea8a5988a5672526eda0677f2048d', + Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '14eba7addfdcf0699970fcbac225499858a167f2', 'src/third_party/liblouis/src': { 'url': Var('chromium_git') + '/external/liblouis-github.git' + '@' + '97ce1c67fccbd3668291b7e63c06161c095d49f2', @@ -1191,7 +1191,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '67a281286c52bd9eb4158d0d66c33acb162e67d9', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'da391939c5248fde66b3c2c76345a7d671e4fb10', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1359,7 +1359,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '91350f8ecf9ab2922ee062c114e4a759f24bd8d0', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'ca160215c9d1f3fdb26cef072c01f12cd8b02fe6', + Var('webrtc_git') + '/src.git' + '@' + '0f0668e328995a62f2b7749150a67a6efa373d2e', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1400,7 +1400,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3bf592f177c2a2dc1b7629b1853a7a04f7d06516', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@360b8d795ccb20b62f22004ac105932c73231f51', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/gfx/surfaces_instance.cc b/android_webview/browser/gfx/surfaces_instance.cc index 8e61bba0..636d902 100644 --- a/android_webview/browser/gfx/surfaces_instance.cc +++ b/android_webview/browser/gfx/surfaces_instance.cc
@@ -25,7 +25,6 @@ #include "components/viz/service/display/display_scheduler.h" #include "components/viz/service/display_embedder/skia_output_surface_dependency.h" #include "components/viz/service/display_embedder/skia_output_surface_impl.h" -#include "components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "gpu/command_buffer/service/sequence_id.h" @@ -258,11 +257,7 @@ nullptr /* gr_shader_cache */); } if (settings.use_skia_renderer_non_ddl) { - output_surface = std::make_unique<viz::SkiaOutputSurfaceImplNonDDL>( - gl_surface_, shared_context_state_, task_executor->mailbox_manager(), - task_executor->shared_image_manager(), - task_executor->sync_point_manager(), - false /* need_swapbuffers_ack */); + NOTIMPLEMENTED(); } else { output_surface = std::make_unique<viz::SkiaOutputSurfaceImpl>( std::make_unique<SkiaOutputSurfaceDependencyWebView>(
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java index ef3dc7c..bd3904a 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
@@ -392,11 +392,35 @@ @Override public boolean onConsoleMessage(AwConsoleMessage consoleMessage) { - if (TRACE) Log.i(TAG, "onConsoleMessage " + consoleMessage); + // Log unconditionally, because JavaScript errors also generate ConsoleMessages (and + // developers generally expect logcat to show such errors). + logConsoleMessage(consoleMessage); mAddMessageToConsoleHelper.notifyCalled(consoleMessage); return false; } + private void logConsoleMessage(AwConsoleMessage consoleMessage) { + String formattedMessage = "[" + consoleMessage.sourceId() + ":" + + consoleMessage.lineNumber() + "] " + consoleMessage.message(); + switch (consoleMessage.messageLevel()) { + case AwConsoleMessage.MESSAGE_LEVEL_TIP: + case AwConsoleMessage.MESSAGE_LEVEL_LOG: + Log.i(TAG, "onConsoleMessage " + formattedMessage); + break; + case AwConsoleMessage.MESSAGE_LEVEL_WARNING: + Log.w(TAG, "onConsoleMessage " + formattedMessage); + break; + case AwConsoleMessage.MESSAGE_LEVEL_ERROR: + Log.e(TAG, "onConsoleMessage " + formattedMessage); + break; + default: + // Should not be reached, but fall-through anyway. + case AwConsoleMessage.MESSAGE_LEVEL_DEBUG: + Log.d(TAG, "onConsoleMessage " + formattedMessage); + break; + } + } + /** * Callback helper for AddMessageToConsole. */
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 11baf96..9f5a8699 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -494,6 +494,8 @@ "multi_user/user_switch_animator.h", "policy/policy_recommendation_restorer.cc", "policy/policy_recommendation_restorer.h", + "power/gatt_battery_percentage_fetcher.cc", + "power/gatt_battery_percentage_fetcher.h", "root_window_controller.cc", "root_window_settings.cc", "root_window_settings.h", @@ -531,8 +533,6 @@ "shelf/home_button.h", "shelf/home_button_controller.cc", "shelf/home_button_controller.h", - "shelf/kiosk_next_shelf_view.cc", - "shelf/kiosk_next_shelf_view.h", "shelf/login_shelf_view.cc", "shelf/login_shelf_view.h", "shelf/overflow_bubble.cc", @@ -785,8 +785,6 @@ "system/night_light/night_light_controller_impl.h", "system/night_light/night_light_feature_pod_controller.cc", "system/night_light/night_light_feature_pod_controller.h", - "system/night_light/night_light_toggle_button.cc", - "system/night_light/night_light_toggle_button.h", "system/night_light/time_of_day.cc", "system/night_light/time_of_day.h", "system/overview/overview_button_tray.cc", @@ -847,8 +845,6 @@ "system/power/power_prefs.h", "system/power/power_status.cc", "system/power/power_status.h", - "system/power/power_status_view.cc", - "system/power/power_status_view.h", "system/power/scoped_backlights_forced_off.cc", "system/power/scoped_backlights_forced_off.h", "system/power/tray_power.cc", @@ -1697,6 +1693,7 @@ "metrics/user_metrics_recorder_unittest.cc", "multi_device_setup/multi_device_notification_presenter_unittest.cc", "policy/policy_recommendation_restorer_unittest.cc", + "power/gatt_battery_percentage_fetcher_unittest.cc", "root_window_controller_unittest.cc", "rotator/screen_rotation_animation_unittest.cc", "rotator/screen_rotation_animator_unittest.cc", @@ -1768,7 +1765,6 @@ "system/power/power_notification_controller_unittest.cc", "system/power/power_prefs_unittest.cc", "system/power/power_status_unittest.cc", - "system/power/power_status_view_unittest.cc", "system/power/video_activity_notifier_unittest.cc", "system/rotation/rotation_lock_feature_pod_controller_unittest.cc", "system/screen_layout_observer_unittest.cc",
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc index 5d721beb..89ec2df 100644 --- a/ash/accelerators/accelerator_controller_impl.cc +++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -26,7 +26,6 @@ #include "ash/ime/ime_controller.h" #include "ash/ime/ime_switch_type.h" #include "ash/keyboard/ui/keyboard_ui_controller.h" -#include "ash/kiosk_next/kiosk_next_shell_controller_impl.h" #include "ash/magnifier/docked_magnifier_controller_impl.h" #include "ash/magnifier/magnification_controller.h" #include "ash/media/media_controller_impl.h" @@ -1441,10 +1440,6 @@ actions_allowed_in_pinned_mode_.insert( kActionsAllowedInAppModeOrPinnedMode[i]); } - for (size_t i = 0; i < kActionsAllowedForKioskNextShellLength; i++) { - actions_allowed_for_kiosk_next_shell_.insert( - kActionsAllowedForKioskNextShell[i]); - } for (size_t i = 0; i < kActionsAllowedInPinnedModeLength; ++i) actions_allowed_in_pinned_mode_.insert(kActionsAllowedInPinnedMode[i]); for (size_t i = 0; i < kActionsNeedingWindowLength; ++i) @@ -2016,10 +2011,6 @@ AcceleratorControllerImpl::AcceleratorProcessingRestriction AcceleratorControllerImpl::GetAcceleratorProcessingRestriction( int action) const { - if (Shell::Get()->kiosk_next_shell_controller()->IsEnabled() && - actions_allowed_for_kiosk_next_shell_.count(action) == 0) { - return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION; - } if (Shell::Get()->screen_pinning_controller()->IsPinned() && actions_allowed_in_pinned_mode_.find(action) == actions_allowed_in_pinned_mode_.end()) {
diff --git a/ash/accelerators/accelerator_controller_impl.h b/ash/accelerators/accelerator_controller_impl.h index 4807125..d2c36991 100644 --- a/ash/accelerators/accelerator_controller_impl.h +++ b/ash/accelerators/accelerator_controller_impl.h
@@ -304,8 +304,6 @@ std::set<int> actions_allowed_in_app_mode_; // Actions allowed in pinned mode. std::set<int> actions_allowed_in_pinned_mode_; - // Actions allowed when Kiosk Next Shell is enabled. - std::set<int> actions_allowed_for_kiosk_next_shell_; // Actions disallowed if there are no windows. std::set<int> actions_needing_window_; // Actions that can be performed without closing the menu (if one is present).
diff --git a/ash/accelerators/accelerator_table.cc b/ash/accelerators/accelerator_table.cc index d47adc8..011e8260 100644 --- a/ash/accelerators/accelerator_table.cc +++ b/ash/accelerators/accelerator_table.cc
@@ -375,34 +375,4 @@ const size_t kActionsKeepingMenuOpenLength = base::size(kActionsKeepingMenuOpen); -const AcceleratorAction kActionsAllowedForKioskNextShell[] = { - BRIGHTNESS_DOWN, - BRIGHTNESS_UP, - DEBUG_TOGGLE_SHOW_DEBUG_BORDERS, - DEBUG_TOGGLE_SHOW_FPS_COUNTER, - DEBUG_TOGGLE_SHOW_PAINT_RECTS, - KEYBOARD_BRIGHTNESS_DOWN, - KEYBOARD_BRIGHTNESS_UP, - MEDIA_NEXT_TRACK, - MEDIA_PLAY_PAUSE, - MEDIA_PREV_TRACK, - POWER_PRESSED, - POWER_RELEASED, - TAKE_PARTIAL_SCREENSHOT, - TAKE_SCREENSHOT, - TAKE_WINDOW_SCREENSHOT, - TOGGLE_CAPS_LOCK, - TOGGLE_DICTATION, - TOGGLE_DOCKED_MAGNIFIER, - TOGGLE_FULLSCREEN_MAGNIFIER, - TOGGLE_HIGH_CONTRAST, - TOGGLE_SPOKEN_FEEDBACK, - VOLUME_DOWN, - VOLUME_MUTE, - VOLUME_UP, -}; - -const size_t kActionsAllowedForKioskNextShellLength = - base::size(kActionsAllowedForKioskNextShell); - } // namespace ash
diff --git a/ash/accelerators/accelerator_table.h b/ash/accelerators/accelerator_table.h index 6586c52..82278e1c 100644 --- a/ash/accelerators/accelerator_table.h +++ b/ash/accelerators/accelerator_table.h
@@ -155,10 +155,6 @@ ASH_EXPORT extern const AcceleratorAction kActionsKeepingMenuOpen[]; ASH_EXPORT extern const size_t kActionsKeepingMenuOpenLength; -// Actions that can be performed when the Kiosk Next Shell is enabled. -ASH_EXPORT extern const AcceleratorAction kActionsAllowedForKioskNextShell[]; -ASH_EXPORT extern const size_t kActionsAllowedForKioskNextShellLength; - } // namespace ash #endif // ASH_ACCELERATORS_ACCELERATOR_TABLE_H_
diff --git a/ash/accelerators/pre_target_accelerator_handler.cc b/ash/accelerators/pre_target_accelerator_handler.cc index 4b35dd1..55f2ca8 100644 --- a/ash/accelerators/pre_target_accelerator_handler.cc +++ b/ash/accelerators/pre_target_accelerator_handler.cc
@@ -8,7 +8,6 @@ #include "ash/shell.h" #include "ash/wm/window_state.h" #include "base/feature_list.h" -#include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "media/base/media_switches.h" #include "ui/aura/window.h" @@ -56,7 +55,6 @@ aura::Window* target = static_cast<aura::Window*>(key_event.target()); // Callers should never supply null. DCHECK(target); - RecordSearchKeyStats(accelerator); // Special hardware keys like brightness and volume are handled in // special way. However, some windows can override this behavior // (e.g. Chrome v1 apps by default and Chrome v2 apps with @@ -73,26 +71,6 @@ return Shell::Get()->accelerator_controller()->Process(accelerator); } -void PreTargetAcceleratorHandler::RecordSearchKeyStats( - const ui::Accelerator& accelerator) { - if (accelerator.IsCmdDown()) { - if (search_key_state_ == RELEASED) { - search_key_state_ = PRESSED; - search_key_pressed_timestamp_ = base::TimeTicks::Now(); - } - - if (accelerator.key_code() != ui::KeyboardCode::VKEY_COMMAND && - search_key_state_ == PRESSED) { - search_key_state_ = RECORDED; - UMA_HISTOGRAM_TIMES( - "Keyboard.Shortcuts.CrosSearchKeyDelay", - base::TimeTicks::Now() - search_key_pressed_timestamp_); - } - } else { - search_key_state_ = RELEASED; - } -} - bool PreTargetAcceleratorHandler::CanConsumeSystemKeys( aura::Window* target, const ui::KeyEvent& event) {
diff --git a/ash/accelerators/pre_target_accelerator_handler.h b/ash/accelerators/pre_target_accelerator_handler.h index 8640067..daebb82b 100644 --- a/ash/accelerators/pre_target_accelerator_handler.h +++ b/ash/accelerators/pre_target_accelerator_handler.h
@@ -7,7 +7,6 @@ #include "ash/ash_export.h" #include "base/macros.h" -#include "base/time/time.h" #include "ui/wm/core/accelerator_delegate.h" namespace aura { @@ -46,14 +45,6 @@ const ui::KeyEvent& event, const ui::Accelerator& accelerator); - // Records a histogram on how long the "Search" key is held when a user - // presses an accelerator that involes the "Search" key. - void RecordSearchKeyStats(const ui::Accelerator& accelerator); - - enum SearchKeyState { RELEASED = 0, PRESSED, RECORDED }; - SearchKeyState search_key_state_ = RELEASED; - base::TimeTicks search_key_pressed_timestamp_; - DISALLOW_COPY_AND_ASSIGN(PreTargetAcceleratorHandler); };
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index b8e4b19..aa54d781 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -228,9 +228,6 @@ <message name="IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_SETTINGS_TOOLTIP" desc="The tooltip text used for the button in the status tray to show the Night Light feature (which controls the color temperature of the screen) settings."> Show Night Light settings </message> - <message name="IDS_ASH_STATUS_TRAY_NIGHT_LIGHT" desc="The label used for the button in the status tray to toggle the Night Light feature (which controls the color temperature of the screen) on or off."> - Night Light: <ph name="NIGHT_LIGHT_STATUS">$1<ex>On</ex></ph> - </message> <message name="IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_OFF_STATE" desc="The label for the Off state of the Night Light feature."> Off </message>
diff --git a/ash/power/DEPS b/ash/power/DEPS new file mode 100644 index 0000000..b299852d --- /dev/null +++ b/ash/power/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+components/device_event_log/device_event_log.h", +]
diff --git a/ash/power/gatt_battery_percentage_fetcher.cc b/ash/power/gatt_battery_percentage_fetcher.cc new file mode 100644 index 0000000..a651ab8 --- /dev/null +++ b/ash/power/gatt_battery_percentage_fetcher.cc
@@ -0,0 +1,266 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/power/gatt_battery_percentage_fetcher.h" + +#include "base/bind.h" +#include "base/memory/ptr_util.h" +#include "components/device_event_log/device_event_log.h" +#include "device/bluetooth/bluetooth_gatt_connection.h" +#include "device/bluetooth/bluetooth_remote_gatt_characteristic.h" +#include "device/bluetooth/bluetooth_remote_gatt_service.h" +#include "device/bluetooth/public/cpp/bluetooth_uuid.h" + +using device::BluetoothDevice; +using device::BluetoothGattService; + +namespace ash { + +namespace { + +// UUIDs for the standardized Battery Service and Characteristic, defined by the +// Bluetooth GATT Specification. +// https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Services/org.bluetooth.service.battery_service.xml +constexpr char kBatteryServiceUUID[] = "180F"; +constexpr char kBatteryLevelUUID[] = "2A19"; + +GattBatteryPercentageFetcher::Factory* g_test_factory_instance_ = nullptr; + +const device::BluetoothUUID& GetBatteryServiceUUID() { + static const device::BluetoothUUID battery_service_uuid(kBatteryServiceUUID); + return battery_service_uuid; +} +const device::BluetoothUUID& GetBatteryLevelUUID() { + static const device::BluetoothUUID battery_level_uuid(kBatteryLevelUUID); + return battery_level_uuid; +} + +const char* BluetoothDeviceErrorCodeToString( + BluetoothDevice::ConnectErrorCode error_code) { + switch (error_code) { + case BluetoothDevice::ERROR_AUTH_CANCELED: + return "ERROR_AUTH_CANCELED"; + case BluetoothDevice::ERROR_AUTH_FAILED: + return "ERROR_AUTH_FAILED"; + case BluetoothDevice::ERROR_AUTH_REJECTED: + return "ERROR_AUTH_REJECTED"; + case BluetoothDevice::ERROR_AUTH_TIMEOUT: + return "ERROR_AUTH_TIMEOUT"; + case BluetoothDevice::ERROR_FAILED: + return "ERROR_FAILED"; + case BluetoothDevice::ERROR_INPROGRESS: + return "ERROR_INPROGRESS"; + case BluetoothDevice::ERROR_UNKNOWN: + return "ERROR_UNKNOWN"; + case BluetoothDevice::ERROR_UNSUPPORTED_DEVICE: + return "ERROR_UNSUPPORTED_DEVICE"; + case BluetoothDevice::NUM_CONNECT_ERROR_CODES: + NOTREACHED(); + return ""; + } +} + +const char* GattErrorCodeToString( + BluetoothGattService::GattErrorCode error_code) { + switch (error_code) { + case BluetoothGattService::GATT_ERROR_UNKNOWN: + return "GATT_ERROR_UNKNOWN"; + case BluetoothGattService::GATT_ERROR_FAILED: + return "GATT_ERROR_FAILED"; + case BluetoothGattService::GATT_ERROR_IN_PROGRESS: + return "GATT_ERROR_IN_PROGRESS"; + case BluetoothGattService::GATT_ERROR_INVALID_LENGTH: + return "GATT_ERROR_INVALID_LENGTH"; + case BluetoothGattService::GATT_ERROR_NOT_PERMITTED: + return "GATT_ERROR_NOT_PERMITTED"; + case BluetoothGattService::GATT_ERROR_NOT_AUTHORIZED: + return "GATT_ERROR_NOT_AUTHORIZED"; + case BluetoothGattService::GATT_ERROR_NOT_PAIRED: + return "GATT_ERROR_NOT_PAIRED"; + case BluetoothGattService::GATT_ERROR_NOT_SUPPORTED: + return "GATT_ERROR_NOT_SUPPORTED"; + } +} + +device::BluetoothRemoteGattService* GetGattBatteryService( + BluetoothDevice* device) { + for (device::BluetoothRemoteGattService* service : + device->GetGattServices()) { + if (service->GetUUID() == GetBatteryServiceUUID()) + return service; + } + return nullptr; +} + +} // namespace + +// static +std::unique_ptr<GattBatteryPercentageFetcher> +GattBatteryPercentageFetcher::Factory::NewInstance( + scoped_refptr<device::BluetoothAdapter> adapter, + const std::string& device_address, + BatteryPercentageCallback callback) { + if (g_test_factory_instance_) { + return g_test_factory_instance_->BuildInstance(adapter, device_address, + std::move(callback)); + } + auto instance = base::WrapUnique( + new GattBatteryPercentageFetcher(device_address, std::move(callback))); + instance->SetAdapterAndStartFetching(adapter); + return instance; +} + +// static +void GattBatteryPercentageFetcher::Factory::SetFactoryForTesting( + Factory* factory) { + g_test_factory_instance_ = factory; +} + +GattBatteryPercentageFetcher::GattBatteryPercentageFetcher( + const std::string& device_address, + BatteryPercentageCallback callback) + : device_address_(device_address), callback_(std::move(callback)) {} + +GattBatteryPercentageFetcher::~GattBatteryPercentageFetcher() { + if (adapter_) + adapter_->RemoveObserver(this); +} + +void GattBatteryPercentageFetcher::SetAdapterAndStartFetching( + scoped_refptr<device::BluetoothAdapter> adapter) { + DCHECK(adapter); + adapter_ = adapter; + adapter_->AddObserver(this); + + // Create Gatt Connection. + BluetoothDevice* device = adapter_->GetDevice(device_address()); + if (!device) { + BLUETOOTH_LOG(ERROR) + << "GattBatteryPercentageFetcher error for device: " << device_address() + << ". Unable to get device from adapter on CreateGattConnection."; + InvokeCallbackWithFailedFetch(); + return; + } + DCHECK(!connection_); + device->CreateGattConnection( + base::Bind(&GattBatteryPercentageFetcher::OnGattConnected, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&GattBatteryPercentageFetcher::OnGattConnectError, + weak_ptr_factory_.GetWeakPtr())); +} + +void GattBatteryPercentageFetcher::OnGattConnected( + std::unique_ptr<device::BluetoothGattConnection> connection) { + DCHECK_EQ(connection->GetDeviceAddress(), this->device_address()); + BluetoothDevice* device = adapter_->GetDevice(device_address()); + if (!device) { + BLUETOOTH_LOG(ERROR) + << "GattBatteryPercentageFetcher error for device: " << device_address() + << ". Unable to get device from adapter on OnGattConnected."; + InvokeCallbackWithFailedFetch(); + return; + } + connection_ = std::move(connection); + + // If Gatt Services Discovery is not complete yet, wait until + // GattServicesDiscovered() is called to continue fetching the battery level. + if (device->IsGattServicesDiscoveryComplete()) + AttemptToReadBatteryCharacteristic(); +} + +void GattBatteryPercentageFetcher::OnGattConnectError( + BluetoothDevice::ConnectErrorCode error_code) { + BLUETOOTH_LOG(ERROR) << "GattBatteryPercentageFetcher error for device: " + << device_address() << ". OnGattConnectError" + << BluetoothDeviceErrorCodeToString(error_code); + InvokeCallbackWithFailedFetch(); +} + +void GattBatteryPercentageFetcher::GattServicesDiscovered( + device::BluetoothAdapter* adapter, + BluetoothDevice* device) { + if (device->GetAddress() == device_address()) + AttemptToReadBatteryCharacteristic(); +} + +void GattBatteryPercentageFetcher::AttemptToReadBatteryCharacteristic() { + // This function should only be called once with an active GATT connection. + if (!connection_ || attempted_to_read_the_battery_characteristic_) + return; + + attempted_to_read_the_battery_characteristic_ = true; + BluetoothDevice* device = adapter_->GetDevice(device_address()); + if (!device) { + BLUETOOTH_LOG(ERROR) << "GattBatteryPercentageFetcher error for device: " + << device_address() + << ". Unable to get device from adapter on " + "AttemptToReadBatteryCharacteristic."; + InvokeCallbackWithFailedFetch(); + return; + } + + device::BluetoothRemoteGattService* service = GetGattBatteryService(device); + if (!service) { + BLUETOOTH_LOG(ERROR) << "GattBatteryPercentageFetcher error for device: " + << device_address() << ". No battery service."; + InvokeCallbackWithFailedFetch(); + return; + } + + std::vector<device::BluetoothRemoteGattCharacteristic*> characteristics = + service->GetCharacteristicsByUUID(GetBatteryLevelUUID()); + + // If no battery characteristic exists, the value cannot be retrieved. + if (characteristics.empty()) { + BLUETOOTH_LOG(ERROR) << "GattBatteryPercentageFetcher error for device: " + << device_address() + << ". Bad format for battery level characteristic."; + InvokeCallbackWithFailedFetch(); + return; + } + + // Only one characteristic is expected to exist according to the GATT Battery + // Service standard. If multiple characteristics are present, arbitrarily + // choose the first one. + characteristics[0]->ReadRemoteCharacteristic( + base::Bind(&GattBatteryPercentageFetcher::OnReadBatteryLevel, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&GattBatteryPercentageFetcher::OnReadBatteryLevelError, + weak_ptr_factory_.GetWeakPtr())); +} + +void GattBatteryPercentageFetcher::OnReadBatteryLevel( + const std::vector<uint8_t>& value) { + if (value.size() != 1 || value[0] > 100) { + BLUETOOTH_LOG(ERROR) << "GattBatteryPercentageFetcher error for device: " + << device_address() + << ". Wrong format for battery level."; + InvokeCallbackWithFailedFetch(); + return; + } + InvokeCallbackWithSuccessfulFetch(value[0]); +} + +void GattBatteryPercentageFetcher::OnReadBatteryLevelError( + BluetoothGattService::GattErrorCode error_code) { + BLUETOOTH_LOG(ERROR) << "GattBatteryPercentageFetcher error for device: " + << device_address() << ". OnReadBatteryLevelError - " + << GattErrorCodeToString(error_code); + InvokeCallbackWithFailedFetch(); +} + +void GattBatteryPercentageFetcher::InvokeCallbackWithSuccessfulFetch( + uint8_t battery_percentage) { + connection_.reset(); + DCHECK(callback_); + std::move(callback_).Run(battery_percentage); +} + +void GattBatteryPercentageFetcher::InvokeCallbackWithFailedFetch() { + connection_.reset(); + DCHECK(callback_); + std::move(callback_).Run(base::nullopt); +} + +} // namespace ash
diff --git a/ash/power/gatt_battery_percentage_fetcher.h b/ash/power/gatt_battery_percentage_fetcher.h new file mode 100644 index 0000000..18483693 --- /dev/null +++ b/ash/power/gatt_battery_percentage_fetcher.h
@@ -0,0 +1,110 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_POWER_GATT_BATTERY_PERCENTAGE_FETCHER_H_ +#define ASH_POWER_GATT_BATTERY_PERCENTAGE_FETCHER_H_ + +#include <string> + +#include "ash/ash_export.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/optional.h" +#include "device/bluetooth/bluetooth_adapter.h" +#include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/bluetooth_gatt_service.h" + +namespace device { +class BluetoothGattConnection; +} // namespace device + +namespace ash { + +// Using the GATT Battery Service (BAS), returns the battery percentage (or +// nullopt in case of error) via the |callback_| for a Bluetooth device with the +// provided |device_address_|. An instance of this class should be created every +// time such a value is needed and destroyed after the callback is called. +class ASH_EXPORT GattBatteryPercentageFetcher + : public device::BluetoothAdapter::Observer { + public: + // Passes null if the battery percentage cannot be fetched. + using BatteryPercentageCallback = + base::OnceCallback<void(base::Optional<uint8_t>)>; + + class Factory { + public: + virtual ~Factory() = default; + + static void SetFactoryForTesting(Factory* factory); + + static std::unique_ptr<GattBatteryPercentageFetcher> NewInstance( + scoped_refptr<device::BluetoothAdapter> adapter, + const std::string& device_address, + BatteryPercentageCallback callback); + + virtual std::unique_ptr<GattBatteryPercentageFetcher> BuildInstance( + scoped_refptr<device::BluetoothAdapter> adapter, + const std::string& device_address, + BatteryPercentageCallback callback) = 0; + }; + + ~GattBatteryPercentageFetcher() override; + + const std::string& device_address() const { return device_address_; } + + protected: + GattBatteryPercentageFetcher(const std::string& device_address, + BatteryPercentageCallback callback); + + // Close |connection_| and return the fetched value through the callback. + void InvokeCallbackWithSuccessfulFetch(uint8_t battery_percentage); + void InvokeCallbackWithFailedFetch(); + + private: + friend class GattBatteryPercentageFetcherTest; + + // device::BluetoothAdapter::Observer: + void GattServicesDiscovered(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) override; + + // Calling this function starts the fetching process. This allows tests to + // to create instances of this class without running the whole mechanism. + void SetAdapterAndStartFetching( + scoped_refptr<device::BluetoothAdapter> adapter); + + // Checks if the GATT Services are discovered to gather the battery value, + // otherwise sets a flag to wait for them to complete. + void OnGattConnected( + std::unique_ptr<device::BluetoothGattConnection> connection); + void OnGattConnectError(device::BluetoothDevice::ConnectErrorCode error_code); + + // Searches for the GATT Battery Service and Characteristic and requests to + // read its value. + void AttemptToReadBatteryCharacteristic(); + + // Callback when reading the battery percentage succeeds. Will return such + // value via |callback_|. + void OnReadBatteryLevel(const std::vector<uint8_t>& value); + void OnReadBatteryLevelError( + device::BluetoothGattService::GattErrorCode error_code); + + const std::string device_address_; + BatteryPercentageCallback callback_; + + // May be null in tests. + scoped_refptr<device::BluetoothAdapter> adapter_; + std::unique_ptr<device::BluetoothGattConnection> connection_; + + // Flag to avoid fetching the battery level multiple times in case + // GattServicesDiscovered() is called more than once. + bool attempted_to_read_the_battery_characteristic_ = false; + + base::WeakPtrFactory<GattBatteryPercentageFetcher> weak_ptr_factory_{this}; + + DISALLOW_COPY_AND_ASSIGN(GattBatteryPercentageFetcher); +}; + +} // namespace ash + +#endif // ASH_POWER_GATT_BATTERY_PERCENTAGE_FETCHER_H_
diff --git a/ash/power/gatt_battery_percentage_fetcher_unittest.cc b/ash/power/gatt_battery_percentage_fetcher_unittest.cc new file mode 100644 index 0000000..ff64040 --- /dev/null +++ b/ash/power/gatt_battery_percentage_fetcher_unittest.cc
@@ -0,0 +1,258 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/power/gatt_battery_percentage_fetcher.h" + +#include "base/bind.h" +#include "base/macros.h" +#include "device/bluetooth/bluetooth_adapter_factory.h" +#include "device/bluetooth/test/mock_bluetooth_adapter.h" +#include "device/bluetooth/test/mock_bluetooth_device.h" +#include "device/bluetooth/test/mock_bluetooth_gatt_characteristic.h" +#include "device/bluetooth/test/mock_bluetooth_gatt_connection.h" +#include "testing/gtest/include/gtest/gtest.h" + +using device::BluetoothDevice; +using device::BluetoothRemoteGattCharacteristic; +using testing::_; +using testing::DoAll; +using testing::NiceMock; +using testing::Return; +using testing::SaveArg; + +namespace { + +constexpr char kServiceID[] = "service id"; +constexpr char kCharacteristicID[] = "characteristic id"; +constexpr char kDeviceAddress[] = "AA:BB:CC:DD:EE:FF"; +constexpr char kBatteryServiceUUID[] = "180F"; +constexpr char kBatteryLevelUUID[] = "2A19"; +const uint8_t kBatteryPercentage = 100; + +ACTION_TEMPLATE(MoveArg, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(pointer)) { + *pointer = std::move(::std::get<k>(args)); +} + +const device::BluetoothUUID& GetBatteryServiceUUID() { + static const device::BluetoothUUID battery_service_uuid(kBatteryServiceUUID); + return battery_service_uuid; +} + +const device::BluetoothUUID& GetBatteryLevelUUID() { + static const device::BluetoothUUID battery_level_uuid(kBatteryLevelUUID); + return battery_level_uuid; +} + +} // namespace + +namespace ash { + +class GattBatteryPercentageFetcherTest : public testing::Test { + protected: + GattBatteryPercentageFetcherTest() = default; + + ~GattBatteryPercentageFetcherTest() override = default; + + void SetUp() override { + mock_adapter_ = + base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>(); + + // By default, |mock_device_| is paired, connected, with Gatt Services + // Discovery completed and returns |mock_service_| when requested for + // for available services. These behaviors can be overridden in tests. + mock_device_ = std::make_unique<NiceMock<device::MockBluetoothDevice>>( + mock_adapter_.get(), 0 /* bluetooth_class */, "device_name", + kDeviceAddress, true /* paired */, true /* connected */); + ON_CALL(*mock_adapter_, GetDevice(kDeviceAddress)) + .WillByDefault(Return(mock_device_.get())); + ON_CALL(*mock_device_, IsGattServicesDiscoveryComplete()) + .WillByDefault(Return(true)); + ASSERT_FALSE(mock_device_->battery_percentage()); + + // By default, |mock_service_| returns a vector containing + // |mock_characteristic_| when requested for the battery level + // characteristic. This behavior can be overridden in tests. + mock_service_ = + std::make_unique<NiceMock<device::MockBluetoothGattService>>( + mock_device_.get(), kServiceID, GetBatteryServiceUUID(), + true /* is_primary */, false /* is_local */); + std::vector<device::BluetoothRemoteGattService*> services = { + mock_service_.get()}; + ON_CALL(*mock_device_, GetGattServices()).WillByDefault(Return(services)); + + mock_characteristic_ = + std::make_unique<NiceMock<device::MockBluetoothGattCharacteristic>>( + mock_service_.get(), kCharacteristicID, GetBatteryLevelUUID(), + false /* is_local */, + BluetoothRemoteGattCharacteristic::PROPERTY_READ, + BluetoothRemoteGattCharacteristic::PERMISSION_READ); + std::vector<BluetoothRemoteGattCharacteristic*> characteristics = { + mock_characteristic_.get()}; + ON_CALL(*mock_service_, GetCharacteristicsByUUID(GetBatteryLevelUUID())) + .WillByDefault(Return(characteristics)); + + device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_); + + // Create a GattBatteryPercentageFetcher. + ExpectGattConnection(); + fetcher_ = GattBatteryPercentageFetcher::Factory::NewInstance( + mock_adapter_, kDeviceAddress, + base::BindOnce( + &GattBatteryPercentageFetcherTest::OnBatteryPercentageFetched, + base::Unretained(this))); + } + + void ExpectGattConnection() { + EXPECT_CALL(*mock_device_, CreateGattConnection(_, _)) + .WillOnce(DoAll(SaveArg<0>(&create_gatt_connection_success_callback_), + SaveArg<1>(&create_gatt_connection_error_callback_))); + } + + void ExpectReadCharacteristic() { + EXPECT_CALL(*mock_characteristic_, ReadRemoteCharacteristic_(_, _)) + .WillOnce( + DoAll(MoveArg<0>(&read_remote_characteristic_callback_), + MoveArg<1>(&read_remote_characteristic_error_callback_))); + } + + void OnBatteryPercentageFetched(base::Optional<uint8_t> battery_percentage) { + battery_percentage_ = battery_percentage; + battery_percentage_callback_called_ = true; + } + + void VerifyFetchResult(base::Optional<uint8_t> expected_result) { + EXPECT_TRUE(battery_percentage_callback_called_); + EXPECT_EQ(expected_result, battery_percentage_); + } + + std::unique_ptr<GattBatteryPercentageFetcher> fetcher_; + + base::Optional<uint8_t> battery_percentage_; + bool battery_percentage_callback_called_ = false; + + scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_adapter_; + std::unique_ptr<device::MockBluetoothDevice> mock_device_; + + std::unique_ptr<device::MockBluetoothGattService> mock_service_; + std::unique_ptr<device::MockBluetoothGattCharacteristic> mock_characteristic_; + + BluetoothDevice::GattConnectionCallback + create_gatt_connection_success_callback_; + BluetoothDevice::ConnectErrorCallback create_gatt_connection_error_callback_; + BluetoothRemoteGattCharacteristic::ValueCallback + read_remote_characteristic_callback_; + BluetoothRemoteGattCharacteristic::ErrorCallback + read_remote_characteristic_error_callback_; + + private: + DISALLOW_COPY_AND_ASSIGN(GattBatteryPercentageFetcherTest); +}; + +TEST_F(GattBatteryPercentageFetcherTest, + ReadBattery_GattServicesDiscoveredOnGattConnection) { + ExpectReadCharacteristic(); + create_gatt_connection_success_callback_.Run( + std::make_unique<NiceMock<device::MockBluetoothGattConnection>>( + mock_adapter_, kDeviceAddress)); + + std::move(read_remote_characteristic_callback_).Run({kBatteryPercentage}); + VerifyFetchResult(kBatteryPercentage); +} + +TEST_F(GattBatteryPercentageFetcherTest, + ReadBattery_GattServicesDiscoveredAfterGattConnection) { + ExpectReadCharacteristic(); + ON_CALL(*mock_device_, IsGattServicesDiscoveryComplete()) + .WillByDefault(Return(false)); + + // GattServicesDiscoveryComplete() should not have run yet. + EXPECT_TRUE(read_remote_characteristic_error_callback_.is_null()); + EXPECT_TRUE(read_remote_characteristic_callback_.is_null()); + + create_gatt_connection_success_callback_.Run( + std::make_unique<NiceMock<device::MockBluetoothGattConnection>>( + mock_adapter_, kDeviceAddress)); + + mock_adapter_->NotifyGattServicesDiscovered(mock_device_.get()); + + // GattServicesDiscoveryComplete() should have run. + std::move(read_remote_characteristic_callback_).Run({kBatteryPercentage}); + VerifyFetchResult(kBatteryPercentage); +} + +TEST_F(GattBatteryPercentageFetcherTest, + IgnoreGattServicesDiscoveredBeforeGattConnection) { + // Case where the GATT connection has not been established yet, but the + // services are done with discovery. Should not try reading the battery level. + EXPECT_CALL(*mock_characteristic_, ReadRemoteCharacteristic_(_, _)).Times(0); + mock_adapter_->NotifyGattServicesDiscovered(mock_device_.get()); +} + +TEST_F(GattBatteryPercentageFetcherTest, ErrorOpeningGattConnection) { + create_gatt_connection_error_callback_.Run( + BluetoothDevice::ERROR_AUTH_TIMEOUT); + VerifyFetchResult(base::nullopt /* expected_result */); +} + +TEST_F(GattBatteryPercentageFetcherTest, BatteryServiceUnavailable) { + ON_CALL(*mock_device_, GetGattServices()) + .WillByDefault( + Return(std::vector<device::BluetoothRemoteGattService*>())); + + create_gatt_connection_success_callback_.Run( + std::make_unique<NiceMock<device::MockBluetoothGattConnection>>( + mock_adapter_, kDeviceAddress)); + VerifyFetchResult(base::nullopt /* expected_result */); +} + +TEST_F(GattBatteryPercentageFetcherTest, MissingBatteryLevelCharacteristic) { + ON_CALL(*mock_service_, GetCharacteristicsByUUID(GetBatteryLevelUUID())) + .WillByDefault(Return(std::vector<BluetoothRemoteGattCharacteristic*>())); + EXPECT_CALL(*mock_characteristic_, ReadRemoteCharacteristic_(_, _)).Times(0); + + create_gatt_connection_success_callback_.Run( + std::make_unique<NiceMock<device::MockBluetoothGattConnection>>( + mock_adapter_, kDeviceAddress)); + VerifyFetchResult(base::nullopt /* expected_result */); +} + +TEST_F(GattBatteryPercentageFetcherTest, ErrorReadingRemoteCharacteristic) { + ExpectReadCharacteristic(); + create_gatt_connection_success_callback_.Run( + std::make_unique<NiceMock<device::MockBluetoothGattConnection>>( + mock_adapter_, kDeviceAddress)); + + std::move(read_remote_characteristic_error_callback_) + .Run(device::BluetoothGattService::GATT_ERROR_UNKNOWN); + VerifyFetchResult(base::nullopt /* expected_result */); +} + +TEST_F(GattBatteryPercentageFetcherTest, + BadFormatForBatteryLevelValue_MadeOfMultipleBytes) { + ExpectReadCharacteristic(); + create_gatt_connection_success_callback_.Run( + std::make_unique<NiceMock<device::MockBluetoothGattConnection>>( + mock_adapter_, kDeviceAddress)); + + // Battery value made of a multibyte vector. + std::move(read_remote_characteristic_callback_) + .Run({kBatteryPercentage, kBatteryPercentage}); + VerifyFetchResult(base::nullopt /* expected_result */); +} + +TEST_F(GattBatteryPercentageFetcherTest, + BadFormatForBatteryLevelValue_ValueAbove100Percent) { + ExpectReadCharacteristic(); + create_gatt_connection_success_callback_.Run( + std::make_unique<NiceMock<device::MockBluetoothGattConnection>>( + mock_adapter_, kDeviceAddress)); + + uint8_t new_battery_percentage = 101; + std::move(read_remote_characteristic_callback_).Run({new_battery_percentage}); + VerifyFetchResult(base::nullopt /* expected_result */); +} + +} // namespace ash
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index d732c831..8150a751 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -189,8 +189,6 @@ "system_menu_tracing.icon", "system_menu_timer.icon", "system_menu_new_user.icon", - "system_menu_night_light_off.icon", - "system_menu_night_light_on.icon", "system_menu_usb.icon", "system_menu_videocam.icon", "system_menu_volume_high.icon", @@ -207,7 +205,6 @@ "system_tray_do_not_disturb.icon", "system_tray_family_link.icon", "system_tray_managed.icon", - "system_tray_night_light.icon", "system_tray_notification_counter_plus.icon", "system_tray_recording.icon", "system_tray_rotation_lock_auto.icon",
diff --git a/ash/resources/vector_icons/system_menu_night_light_off.icon b/ash/resources/vector_icons/system_menu_night_light_off.icon deleted file mode 100644 index cb618cec..0000000 --- a/ash/resources/vector_icons/system_menu_night_light_off.icon +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -CANVAS_DIMENSIONS, 40, -MOVE_TO, 34.3f, 27.18f, -LINE_TO, 18.38f, 11.26f, -CUBIC_TO, 19.89f, 9.6f, 21.82f, 8.33f, 24, 7.63f, -CUBIC_TO, 22.74f, 7.22f, 21.4f, 7, 20, 7, -R_CUBIC_TO, -1.74f, 0, -3.4f, 0.34f, -4.92f, 0.96f, -LINE_TO, 12.82f, 5.7f, -CUBIC_TO, 14.98f, 4.61f, 17.42f, 4, 20, 4, -R_CUBIC_TO, 8.83f, 0, 16, 7.17f, 16, 16, -R_CUBIC_TO, 0, 2.58f, -0.61f, 5.02f, -1.7f, 7.18f, -CLOSE, -R_MOVE_TO, -3.56f, 4.68f, -CUBIC_TO, 27.9f, 34.43f, 24.13f, 36, 20, 36, -R_CUBIC_TO, -8.83f, 0, -16, -7.17f, -16, -16, -R_CUBIC_TO, 0, -4.13f, 1.57f, -7.9f, 4.14f, -10.74f, -R_LINE_TO, 2.12f, 2.12f, -CUBIC_TO, 8.23f, 13.68f, 7, 16.7f, 7, 20, -R_CUBIC_TO, 0, 7.18f, 5.82f, 13, 13, 13, -R_CUBIC_TO, 1.4f, 0, 2.74f, -0.22f, 4, -0.63f, -R_CUBIC_TO, -5.22f, -1.69f, -9, -6.59f, -9, -12.37f, -R_CUBIC_TO, 0, -1.18f, 0.16f, -2.33f, 0.46f, -3.42f, -LINE_TO, 30.74f, 31.86f, -CLOSE, -MOVE_TO, 5, 6.12f, -LINE_TO, 7.12f, 4, -R_LINE_TO, 28.63f, 28.63f, -R_LINE_TO, -2.12f, 2.12f, -LINE_TO, 5, 6.12f, -CLOSE - -CANVAS_DIMENSIONS, 20, -MOVE_TO, 17.15f, 13.59f, -LINE_TO, 9.44f, 5.88f, -R_CUBIC_TO, 0.7f, -0.72f, 1.57f, -1.27f, 2.56f, -1.59f, -R_CUBIC_TO, -0.59f, -0.19f, -1.23f, -0.29f, -1.88f, -0.29f, -R_CUBIC_TO, -0.76f, 0, -1.49f, 0.14f, -2.17f, 0.39f, -LINE_TO, 6.41f, 2.85f, -CUBIC_TO, 7.49f, 2.31f, 8.71f, 2, 10, 2, -R_CUBIC_TO, 4.42f, 0, 8, 3.58f, 8, 8, -R_CUBIC_TO, 0, 1.29f, -0.31f, 2.51f, -0.85f, 3.59f, -CLOSE, -R_MOVE_TO, -1.78f, 2.34f, -CUBIC_TO, 13.95f, 17.22f, 12.06f, 18, 10, 18, -R_CUBIC_TO, -4.42f, 0, -8, -3.58f, -8, -8, -R_CUBIC_TO, 0, -2.06f, 0.78f, -3.95f, 2.07f, -5.37f, -R_LINE_TO, 1.43f, 1.43f, -CUBIC_TO, 4.57f, 7.12f, 4, 8.49f, 4, 10, -R_CUBIC_TO, 0, 3.31f, 2.74f, 6, 6.12f, 6, -R_CUBIC_TO, 0.66f, 0, 1.29f, -0.1f, 1.88f, -0.29f, -R_CUBIC_TO, -2.46f, -0.78f, -4.24f, -3.04f, -4.24f, -5.71f, -R_CUBIC_TO, 0, -0.51f, 0.07f, -1.01f, 0.19f, -1.49f, -R_LINE_TO, 7.41f, 7.42f, -CLOSE, -MOVE_TO, 2.5f, 3.06f, -LINE_TO, 3.56f, 2, -R_LINE_TO, 14.31f, 14.31f, -R_LINE_TO, -1.06f, 1.06f, -LINE_TO, 2.5f, 3.06f, -CLOSE
diff --git a/ash/resources/vector_icons/system_menu_night_light_on.icon b/ash/resources/vector_icons/system_menu_night_light_on.icon deleted file mode 100644 index 442834d..0000000 --- a/ash/resources/vector_icons/system_menu_night_light_on.icon +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -CANVAS_DIMENSIONS, 40, -MOVE_TO, 20, 4, -R_CUBIC_TO, 8.83f, 0, 16, 7.17f, 16, 16, -R_CUBIC_TO, 0, 8.83f, -7.17f, 16, -16, 16, -CUBIC_TO_SHORTHAND, 4, 28.83f, 4, 20, -CUBIC_TO_SHORTHAND, 11.17f, 4, 20, 4, -CLOSE, -R_MOVE_TO, 4, 3.63f, -CUBIC_TO, 22.74f, 7.22f, 21.4f, 7, 20, 7, -CUBIC_TO, 12.82f, 7, 7, 12.82f, 7, 20, -R_CUBIC_TO, 0, 7.18f, 5.82f, 13, 13, 13, -R_CUBIC_TO, 1.4f, 0, 2.74f, -0.22f, 4, -0.63f, -R_CUBIC_TO, -5.22f, -1.69f, -9, -6.59f, -9, -12.37f, -R_CUBIC_TO, 0, -5.78f, 3.78f, -10.69f, 9, -12.37f, -CLOSE - -CANVAS_DIMENSIONS, 20, -MOVE_TO, 10, 2, -R_CUBIC_TO, 4.42f, 0, 8, 3.58f, 8, 8, -R_CUBIC_TO, 0, 4.42f, -3.58f, 8, -8, 8, -R_CUBIC_TO, -4.42f, 0, -8, -3.58f, -8, -8, -R_CUBIC_TO, 0, -4.42f, 3.58f, -8, 8, -8, -CLOSE, -R_MOVE_TO, -0.65f, 2, -CUBIC_TO, 6.4f, 4, 4, 6.69f, 4, 10, -R_CUBIC_TO, 0, 3.31f, 2.4f, 6, 5.35f, 6, -R_CUBIC_TO, 0.57f, 0, 1.13f, -0.1f, 1.65f, -0.29f, -CUBIC_TO, 8.85f, 14.93f, 7.29f, 12.67f, 7.29f, 10, -R_CUBIC_TO, 0, -2.67f, 1.56f, -4.93f, 3.71f, -5.71f, -CUBIC_TO, 10.48f, 4.1f, 9.93f, 4, 9.35f, 4, -CLOSE
diff --git a/ash/resources/vector_icons/system_tray_night_light.icon b/ash/resources/vector_icons/system_tray_night_light.icon deleted file mode 100644 index 236d22a..0000000 --- a/ash/resources/vector_icons/system_tray_night_light.icon +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -CANVAS_DIMENSIONS, 32, -MOVE_TO, 16, 3, -R_CUBIC_TO, 7.18f, 0, 13, 5.82f, 13, 13, -R_CUBIC_TO, 0, 7.18f, -5.82f, 13, -13, 13, -CUBIC_TO_SHORTHAND, 3, 23.18f, 3, 16, -CUBIC_TO_SHORTHAND, 8.82f, 3, 16, 3, -CLOSE, -R_MOVE_TO, 3, 2.53f, -CUBIC_TO, 17.96f, 5.19f, 16.86f, 5, 15.71f, 5, -CUBIC_TO, 9.79f, 5, 5, 9.93f, 5, 16, -R_CUBIC_TO, 0, 6.07f, 4.79f, 11, 10.71f, 11, -R_CUBIC_TO, 1.15f, 0, 2.26f, -0.19f, 3.29f, -0.53f, -R_CUBIC_TO, -4.3f, -1.43f, -7.41f, -5.58f, -7.41f, -10.47f, -R_CUBIC_TO, 0, -4.89f, 3.11f, -9.04f, 7.41f, -10.47f, -CLOSE - -CANVAS_DIMENSIONS, 16, -MOVE_TO, 7, 0, -CUBIC_TO, 10.86f, 0, 14, 3.14f, 14, 7, -CUBIC_TO, 14, 10.86f, 10.86f, 14, 7, 14, -CUBIC_TO, 3.14f, 14, 0, 10.86f, 0, 7, -CUBIC_TO, 0, 3.14f, 3.14f, 0, 7, 0, -CLOSE, -MOVE_TO, 9, 1.29f, -CUBIC_TO, 8.41f, 1.1f, 7.77f, 1, 7.12f, 1, -CUBIC_TO, 3.74f, 1, 1, 3.69f, 1, 7, -CUBIC_TO, 1, 10.31f, 3.74f, 13, 7.12f, 13, -CUBIC_TO, 7.77f, 13, 8.41f, 12.9f, 9, 12.71f, -CUBIC_TO, 6.54f, 11.93f, 4.76f, 9.67f, 4.76f, 7, -CUBIC_TO, 4.76f, 4.33f, 6.54f, 2.07f, 9, 1.29f, -LINE_TO, 9, 1.29f, -CLOSE
diff --git a/ash/shelf/kiosk_next_shelf_view.cc b/ash/shelf/kiosk_next_shelf_view.cc deleted file mode 100644 index 46f25af..0000000 --- a/ash/shelf/kiosk_next_shelf_view.cc +++ /dev/null
@@ -1,166 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/kiosk_next_shelf_view.h" - -#include <memory> - -#include "ash/display/screen_orientation_controller.h" -#include "ash/home_screen/home_screen_controller.h" -#include "ash/public/cpp/shelf_model.h" -#include "ash/shelf/back_button.h" -#include "ash/shelf/home_button.h" -#include "ash/shelf/overflow_button.h" -#include "ash/shelf/shelf.h" -#include "ash/shelf/shelf_button_delegate.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shell.h" -#include "ash/system/status_area_widget.h" -#include "ash/wm/tablet_mode/tablet_mode_controller.h" -#include "base/logging.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/insets_f.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" -#include "ui/views/animation/flood_fill_ink_drop_ripple.h" -#include "ui/views/animation/ink_drop_mask.h" -#include "ui/views/animation/ink_drop_ripple.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -namespace { - -// Kiosk Next back button with permanent round rectangle background. -class KioskNextBackButton : public BackButton { - public: - explicit KioskNextBackButton(ShelfButtonDelegate* shelf_button_delegate) - : BackButton(shelf_button_delegate) {} - ~KioskNextBackButton() override = default; - - private: - // views::BackButton: - void PaintButtonContents(gfx::Canvas* canvas) override { - PaintBackground(canvas, GetContentsBounds()); - BackButton::PaintButtonContents(canvas); - } - - std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override { - return std::make_unique<views::RoundRectInkDropMask>( - size(), gfx::InsetsF(), kKioskNextShelfControlWidthDp / 2); - } - - std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override { - return std::make_unique<views::FloodFillInkDropRipple>( - size(), gfx::Insets(), GetInkDropCenterBasedOnLastEvent(), - GetInkDropBaseColor(), ink_drop_visible_opacity()); - } - - DISALLOW_COPY_AND_ASSIGN(KioskNextBackButton); -}; - -// Kiosk Next home button with permanent round rectangle background. -class KioskNextHomeButton : public HomeButton { - public: - explicit KioskNextHomeButton(ShelfButtonDelegate* shelf_button_delegate) - : HomeButton(shelf_button_delegate) {} - ~KioskNextHomeButton() override = default; - - private: - // views::HomeButton: - void PaintButtonContents(gfx::Canvas* canvas) override { - PaintBackground(canvas, GetContentsBounds()); - HomeButton::PaintButtonContents(canvas); - } - - std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override { - return std::make_unique<views::RoundRectInkDropMask>( - size(), gfx::InsetsF(), kKioskNextShelfControlWidthDp / 2); - } - - std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override { - return std::make_unique<views::FloodFillInkDropRipple>( - size(), gfx::Insets(), GetInkDropCenterBasedOnLastEvent(), - GetInkDropBaseColor(), ink_drop_visible_opacity()); - } - - void OnPressed(app_list::AppListShowSource show_source, - base::TimeTicks time_stamp) override { - Shell::Get()->home_screen_controller()->GoHome(GetDisplayId()); - } - - DISALLOW_COPY_AND_ASSIGN(KioskNextHomeButton); -}; - -bool IsTabletModeEnabled() { - // This check is needed, because tablet mode controller is destroyed before - // shelf widget. See https://crbug.com/967149 for more details. - return Shell::Get()->tablet_mode_controller() && - Shell::Get()->tablet_mode_controller()->InTabletMode(); -} - -} // namespace - -KioskNextShelfView::KioskNextShelfView(ShelfModel* model, - Shelf* shelf, - ShelfWidget* shelf_widget) - : ShelfView(model, shelf, shelf_widget) { - // Kiosk next shelf has 2 navigation buttons (back and home), no app items - // in its shelf model, and it is expected to be used in tablet mode with - // bottom shelf alignment. It can be adapted to different requirements, but - // they should be explicitly verified first. - DCHECK(IsTabletModeEnabled()); - DCHECK(shelf->IsHorizontalAlignment()); - DCHECK_EQ(0, model->item_count()); -} - -KioskNextShelfView::~KioskNextShelfView() = default; - -void KioskNextShelfView::Init() { - ShelfView::Init(); - - // Needs to be called after base class call that creates below objects. - // TODO(agawronska): Separator and overflow button are not needed in Kiosk - // Next shelf. They should be moved to DefaultShelfView subclass and the below - // code should be removed. - DCHECK(overflow_button()); - overflow_button()->SetVisible(false); -} - -void KioskNextShelfView::CalculateIdealBounds() { - DCHECK(shelf()->IsHorizontalAlignment()); - DCHECK_EQ(0, model()->item_count()); - DCHECK_GE(ShelfConstants::shelf_size(), kKioskNextShelfControlHeightDp); - - // TODO(https://crbug.com/965690): Button spacing might be relative to shelf - // width. Reevaluate this piece once visual spec is available. - const int control_buttons_spacing = - IsCurrentScreenOrientationLandscape() - ? kKioskNextShelfControlSpacingLandscapeDp - : kKioskNextShelfControlSpacingPortraitDp; - const int total_shelf_width = - shelf_widget()->GetWindowBoundsInScreen().width(); - int x = total_shelf_width / 2 - kKioskNextShelfControlWidthDp - - control_buttons_spacing / 2; - int y = (ShelfConstants::shelf_size() - kKioskNextShelfControlHeightDp) / 2; - - GetBackButton()->set_ideal_bounds(gfx::Rect( - x, y, kKioskNextShelfControlWidthDp, kKioskNextShelfControlHeightDp)); - x += (kKioskNextShelfControlWidthDp + control_buttons_spacing); - GetHomeButton()->set_ideal_bounds(gfx::Rect( - x, y, kKioskNextShelfControlWidthDp, kKioskNextShelfControlHeightDp)); -} - -std::unique_ptr<BackButton> KioskNextShelfView::CreateBackButton() { - return std::make_unique<KioskNextBackButton>(this); -} - -std::unique_ptr<HomeButton> KioskNextShelfView::CreateHomeButton() { - return std::make_unique<KioskNextHomeButton>(this); -} - -} // namespace ash
diff --git a/ash/shelf/kiosk_next_shelf_view.h b/ash/shelf/kiosk_next_shelf_view.h deleted file mode 100644 index 31e9394..0000000 --- a/ash/shelf/kiosk_next_shelf_view.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_KIOSK_NEXT_SHELF_VIEW_H_ -#define ASH_SHELF_KIOSK_NEXT_SHELF_VIEW_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/shelf/shelf_view.h" -#include "base/macros.h" - -namespace ash { - -class Shelf; -class ShelfModel; -class ShelfWidget; - -// Shelf view used in Kiosk Next mode. -// This shelf view is much simpler than the default shelf view. It is always -// bottom aligned. It shows centered control buttons (back and home). It does -// not display apps' buttons. Because of this alignment overflow mode is not -// needed. This shelf view is using ShelfModel, but it could be removed in the -// future. -class ASH_EXPORT KioskNextShelfView : public ShelfView { - public: - KioskNextShelfView(ShelfModel* model, - Shelf* shelf, - ShelfWidget* shelf_widget); - ~KioskNextShelfView() override; - - // All ShelfView overrides are public to keep them together. - // ShelfView: - void Init() override; - void CalculateIdealBounds() override; - std::unique_ptr<BackButton> CreateBackButton() override; - std::unique_ptr<HomeButton> CreateHomeButton() override; - - private: - DISALLOW_COPY_AND_ASSIGN(KioskNextShelfView); -}; - -} // namespace ash - -#endif // ASH_SHELF_KIOSK_NEXT_SHELF_VIEW_H_
diff --git a/ash/shelf/shelf_constants.h b/ash/shelf/shelf_constants.h index ac3847cf..107dd4be 100644 --- a/ash/shelf/shelf_constants.h +++ b/ash/shelf/shelf_constants.h
@@ -89,18 +89,6 @@ constexpr float kShelfTooltipPreviewMaxRatio = 1.5; // = 3/2 constexpr float kShelfTooltipPreviewMinRatio = 0.666; // = 2/3 -// Kiosk Next shelf constants. -// TODO(agawronska): Make it a part of theme. - -// Size of the space between control buttons on the shelf. Changes within -// orientation. -constexpr int kKioskNextShelfControlSpacingPortraitDp = 96; -constexpr int kKioskNextShelfControlSpacingLandscapeDp = 122; - -// Size of the shelf control buttons (back and home). -constexpr int kKioskNextShelfControlWidthDp = 64; -constexpr int kKioskNextShelfControlHeightDp = 40; - class ShelfConstants { public: // Size of the shelf when visible (height when the shelf is horizontal and
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index 6bf23e5..ead6f15 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -15,10 +15,6 @@ #include "ash/display/screen_orientation_controller_test_api.h" #include "ash/focus_cycler.h" #include "ash/ime/ime_controller.h" -#include "ash/kiosk_next/kiosk_next_shell_controller_impl.h" -#include "ash/kiosk_next/kiosk_next_shell_test_util.h" -#include "ash/kiosk_next/mock_kiosk_next_shell_client.h" -#include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/shelf_item_delegate.h" #include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shelf_prefs.h" @@ -3894,124 +3890,4 @@ // This should have brought focus to the first element on the shelf. EXPECT_TRUE(shelf_view_->GetHomeButton()->HasFocus()); } - -class KioskNextShelfViewTest : public ShelfViewTest { - public: - KioskNextShelfViewTest() { - scoped_feature_list_.InitAndEnableFeature(features::kKioskNextShell); - } - - void SetUp() override { - set_start_session(false); - ShelfViewTest::SetUp(); - client_ = std::make_unique<MockKioskNextShellClient>(); - } - - void TearDown() override { - client_.reset(); - ShelfViewTest::TearDown(); - } - - protected: - void LogInKioskNextUserInternal() { - LogInKioskNextUser(GetSessionControllerClient()); - - // The shelf_view_ in ShelfWidget will be replaced. Therefore, we need - // to update |shelf_view_|. - shelf_view_ = GetPrimaryShelf()->GetShelfViewForTesting(); - ASSERT_GE(shelf_view_->width(), 500); - - test_api_.reset(new ShelfViewTestAPI(shelf_view_)); - test_api_->SetAnimationDuration(1); // Speeds up animation for test. - } - - private: - base::test::ScopedFeatureList scoped_feature_list_; - std::unique_ptr<MockKioskNextShellClient> client_; - - DISALLOW_COPY_AND_ASSIGN(KioskNextShelfViewTest); -}; - -TEST_F(KioskNextShelfViewTest, AppButtonHidden) { - // When a KioskNextUser is not logged in, the shelf model is not hosted - // in KioskNextSellController. - EXPECT_FALSE(shelf_view_->model() == - Shell::Get()->kiosk_next_shell_controller()->shelf_model()); - - LogInKioskNextUserInternal(); - - // When a KiosknextUser is logged in, the shelf model for the shelf view - // is hosted in KioskNextShellController. - EXPECT_TRUE(shelf_view_->model() == - Shell::Get()->kiosk_next_shell_controller()->shelf_model()); - - // The home and back buttons are always visible. - EXPECT_TRUE(shelf_view_->GetHomeButton()->GetVisible()); - EXPECT_TRUE(shelf_view_->GetBackButton()->GetVisible()); - - ASSERT_FALSE(shelf_view_->GetOverflowButton()->GetVisible()); - EXPECT_EQ(-1, shelf_view_->last_visible_index()); -} - -// Tests that control buttons (back/home) are positioned correctly in Kiosk Next -// mode. They should be centered, but exact position depends on the screen -// orientation. -TEST_F(KioskNextShelfViewTest, ControlButtonsCentered) { - // Setup internal display, otherwise setting display rotation will not take - // any effect. - const int64_t display_id = - display::Screen::GetScreen()->GetPrimaryDisplay().id(); - display::DisplayManager* display_manager = Shell::Get()->display_manager(); - display::test::ScopedSetInternalDisplayId internal_display(display_manager, - display_id); - - ScreenOrientationControllerTestApi screen_orientation_test_api( - Shell::Get()->screen_orientation_controller()); - - LogInKioskNextUserInternal(); - - auto test_controls_bounds = [&](display::Display::Rotation rotation, - bool is_landscape) { - SCOPED_TRACE(base::StringPrintf("Rotation: %d", rotation)); - - screen_orientation_test_api.SetDisplayRotation( - rotation, display::Display::RotationSource::ACTIVE); - - // Get shelf bounds from the widget - buttons should be centered - // relatively to the whole shelf area (consisting of shelf view and - // status area). - const gfx::Rect shelf_bounds = GetPrimaryShelf() - ->GetShelfViewForTesting() - ->GetWidget() - ->GetWindowBoundsInScreen(); - - // Switch to local shelf coordinates - buttons bounds are checked in - // relation to shelf. - gfx::Rect expected_button_area_bounds = gfx::Rect(shelf_bounds.size()); - const gfx::Size expected_button_area_size = - gfx::Size(2 * kKioskNextShelfControlWidthDp + - (is_landscape ? kKioskNextShelfControlSpacingLandscapeDp - : kKioskNextShelfControlSpacingPortraitDp), - ShelfConstants::shelf_size()); - expected_button_area_bounds.ClampToCenteredSize(expected_button_area_size); - - const gfx::Rect back_button_bounds = - shelf_view_->GetBackButton()->ideal_bounds(); - EXPECT_FALSE(back_button_bounds.IsEmpty()); - EXPECT_TRUE(expected_button_area_bounds.Contains(back_button_bounds)); - - const gfx::Rect home_button_bounds = - shelf_view_->GetHomeButton()->ideal_bounds(); - EXPECT_FALSE(home_button_bounds.IsEmpty()); - EXPECT_TRUE(expected_button_area_bounds.Contains(home_button_bounds)); - - EXPECT_FALSE(back_button_bounds.Intersects(home_button_bounds)); - }; - - test_controls_bounds(display::Display::ROTATE_0, true /*is_landscape*/); - test_controls_bounds(display::Display::ROTATE_90, false /*is_landscape*/); - test_controls_bounds(display::Display::ROTATE_180, true /*is_landscape*/); - test_controls_bounds(display::Display::ROTATE_270, false /*is_landscape*/); -} - } // namespace ash
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc index 644dfae..47e3e27 100644 --- a/ash/shelf/shelf_widget.cc +++ b/ash/shelf/shelf_widget.cc
@@ -9,7 +9,6 @@ #include "ash/animation/animation_change_type.h" #include "ash/focus_cycler.h" #include "ash/keyboard/ui/keyboard_ui_controller.h" -#include "ash/kiosk_next/kiosk_next_shell_controller_impl.h" #include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/shelf_model.h" @@ -18,7 +17,6 @@ #include "ash/session/session_controller_impl.h" #include "ash/shelf/default_shelf_view.h" #include "ash/shelf/home_button.h" -#include "ash/shelf/kiosk_next_shelf_view.h" #include "ash/shelf/login_shelf_view.h" #include "ash/shelf/overflow_bubble.h" #include "ash/shelf/overflow_bubble_view.h" @@ -345,14 +343,6 @@ background_animator_.AddObserver(delegate_view_); shelf_->AddObserver(this); - - // KioskNextShell controller may have already notified its observers that - // it has been enabled by the time this ShelfWidget is being created. - if (Shell::Get()->kiosk_next_shell_controller()->IsEnabled()) { - OnKioskNextEnabled(); - } else { - Shell::Get()->kiosk_next_shell_controller()->AddObserver(this); - } } ShelfWidget::~ShelfWidget() { @@ -380,9 +370,6 @@ background_animator_.RemoveObserver(delegate_view_); shelf_->RemoveObserver(this); - if (Shell::Get()->kiosk_next_shell_controller()) - Shell::Get()->kiosk_next_shell_controller()->RemoveObserver(this); - // Don't need to observe focus/activation during shutdown. Shell::Get()->focus_cycler()->RemoveWidget(this); SetFocusCycler(nullptr); @@ -577,18 +564,6 @@ login_shelf_view_->UpdateAfterSessionChange(); } -void ShelfWidget::OnKioskNextEnabled() { - // Hide the shelf view and delete/remove it. - shelf_view_->SetVisible(false); - delete shelf_view_; - - shelf_view_ = new KioskNextShelfView( - Shell::Get()->kiosk_next_shell_controller()->shelf_model(), shelf_, this); - shelf_view_->Init(); - GetContentsView()->AddChildView(shelf_view_); - shelf_view_->SetVisible(true); -} - SkColor ShelfWidget::GetShelfBackgroundColor() const { return delegate_view_->GetShelfBackgroundColor(); }
diff --git a/ash/shelf/shelf_widget.h b/ash/shelf/shelf_widget.h index fd0ab4b..4ae412e2 100644 --- a/ash/shelf/shelf_widget.h +++ b/ash/shelf/shelf_widget.h
@@ -8,7 +8,6 @@ #include <memory> #include "ash/ash_export.h" -#include "ash/kiosk_next/kiosk_next_shell_observer.h" #include "ash/public/cpp/shelf_types.h" #include "ash/session/session_observer.h" #include "ash/shelf/shelf_background_animator.h" @@ -38,8 +37,7 @@ class ASH_EXPORT ShelfWidget : public views::Widget, public ShelfLayoutManagerObserver, public ShelfObserver, - public SessionObserver, - public KioskNextShellObserver { + public SessionObserver { public: ShelfWidget(aura::Window* shelf_container, Shelf* shelf); ~ShelfWidget() override; @@ -120,9 +118,6 @@ void OnSessionStateChanged(session_manager::SessionState state) override; void OnUserSessionAdded(const AccountId& account_id) override; - // KioskNextShellObserver: - void OnKioskNextEnabled() override; - SkColor GetShelfBackgroundColor() const; bool GetHitTestRects(aura::Window* target, gfx::Rect* hit_test_rect_mouse,
diff --git a/ash/style/ash_color_provider.cc b/ash/style/ash_color_provider.cc index f207157..2f7dbae 100644 --- a/ash/style/ash_color_provider.cc +++ b/ash/style/ash_color_provider.cc
@@ -75,11 +75,11 @@ SkColor light_color, dark_color; switch (type) { case BaseLayerType::kTransparentWithBlur: - light_color = SkColorSetA(SK_ColorWHITE, 0xC7); - dark_color = SkColorSetA(gfx::kGoogleGrey900, 0xC7); + light_color = SkColorSetA(SK_ColorWHITE, 0xBC); // 74% + dark_color = SkColorSetA(gfx::kGoogleGrey900, 0xBC); break; case BaseLayerType::kTransparentWithoutBlur: - light_color = SkColorSetA(SK_ColorWHITE, 0xE6); + light_color = SkColorSetA(SK_ColorWHITE, 0xE6); // 90% dark_color = SkColorSetA(gfx::kGoogleGrey900, 0xE6); break; case BaseLayerType::kOpaque: @@ -94,16 +94,16 @@ SkColor light_color, dark_color; switch (type) { case PlusOneLayerType::kHairLine: - light_color = SkColorSetA(SK_ColorBLACK, 0x24); + light_color = SkColorSetA(SK_ColorBLACK, 0x24); // 14% dark_color = SkColorSetA(SK_ColorWHITE, 0x24); break; case PlusOneLayerType::kSeparator: - light_color = SkColorSetA(SK_ColorBLACK, 0x24); + light_color = SkColorSetA(SK_ColorBLACK, 0x24); // 14% dark_color = SkColorSetA(SK_ColorWHITE, 0x24); break; case PlusOneLayerType::kInActive: - light_color = SkColorSetA(SK_ColorBLACK, 0x0D); - dark_color = SkColorSetA(SK_ColorWHITE, 0x1A); + light_color = SkColorSetA(SK_ColorBLACK, 0x0D); // 5% + dark_color = SkColorSetA(SK_ColorWHITE, 0x1A); // 10% break; case PlusOneLayerType::kActive: light_color = gfx::kGoogleBlue600;
diff --git a/ash/system/night_light/night_light_toggle_button.cc b/ash/system/night_light/night_light_toggle_button.cc deleted file mode 100644 index 2679fc4d..0000000 --- a/ash/system/night_light/night_light_toggle_button.cc +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/night_light/night_light_toggle_button.h" - -#include "ash/shell.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/night_light/night_light_controller_impl.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ui/accessibility/ax_enums.mojom.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icon_types.h" - -namespace ash { - -namespace { - -gfx::ImageSkia GetNightLightNormalStateIcon(bool night_light_enabled) { - if (night_light_enabled) - return gfx::CreateVectorIcon(kSystemMenuNightLightOnIcon, kMenuIconColor); - - // Use the same icon theme used for inactive items in the tray when - // NightLight is not active. - return gfx::CreateVectorIcon(kSystemMenuNightLightOffIcon, - TrayPopupItemStyle::GetIconColor( - TrayPopupItemStyle::ColorStyle::INACTIVE)); -} - -gfx::ImageSkia GetNightLightDisabledStateIcon(bool night_light_enabled) { - return gfx::CreateVectorIcon(night_light_enabled - ? kSystemMenuNightLightOnIcon - : kSystemMenuNightLightOffIcon, - kMenuIconColorDisabled); -} - -base::string16 GetNightLightTooltipText(bool night_light_enabled) { - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_NIGHT_LIGHT, - l10n_util::GetStringUTF16( - night_light_enabled ? IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_ON_STATE - : IDS_ASH_STATUS_TRAY_NIGHT_LIGHT_OFF_STATE)); -} - -} // namespace - -NightLightToggleButton::NightLightToggleButton(views::ButtonListener* listener) - : SystemMenuButton(listener, - kSystemMenuNightLightOffIcon, - IDS_ASH_STATUS_TRAY_NIGHT_LIGHT) { - Update(); -} - -void NightLightToggleButton::Toggle() { - Shell::Get()->night_light_controller()->Toggle(); - Update(); - NotifyAccessibilityEvent(ax::mojom::Event::kAriaAttributeChanged, true); -} - -const char* NightLightToggleButton::GetClassName() const { - return "NightLightToggleButton"; -} - -void NightLightToggleButton::Update() { - const bool night_light_enabled = - Shell::Get()->night_light_controller()->GetEnabled(); - - SetTooltipText(GetNightLightTooltipText(night_light_enabled)); - SetImage(views::Button::STATE_NORMAL, - GetNightLightNormalStateIcon(night_light_enabled)); - SetImage(views::Button::STATE_DISABLED, - GetNightLightDisabledStateIcon(night_light_enabled)); -} - -void NightLightToggleButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { - const bool is_enabled = Shell::Get()->night_light_controller()->GetEnabled(); - node_data->SetName(GetNightLightTooltipText(is_enabled)); - node_data->role = ax::mojom::Role::kToggleButton; - node_data->SetCheckedState(is_enabled ? ax::mojom::CheckedState::kTrue - : ax::mojom::CheckedState::kFalse); -} - -} // namespace ash
diff --git a/ash/system/night_light/night_light_toggle_button.h b/ash/system/night_light/night_light_toggle_button.h deleted file mode 100644 index 696e40c..0000000 --- a/ash/system/night_light/night_light_toggle_button.h +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NIGHT_LIGHT_NIGHT_LIGHT_TOGGLE_BUTTON_H_ -#define ASH_SYSTEM_NIGHT_LIGHT_NIGHT_LIGHT_TOGGLE_BUTTON_H_ - -#include "ash/system/tray/system_menu_button.h" -#include "base/macros.h" - -namespace ash { - -// The NightLight toggle button in the system tray. -class NightLightToggleButton : public SystemMenuButton { - public: - explicit NightLightToggleButton(views::ButtonListener* listener); - ~NightLightToggleButton() override = default; - - // Toggles the status of NightLight. - void Toggle(); - - // views::View: - const char* GetClassName() const override; - - private: - // Updates the icon and its style based on the status of NightLight. - void Update(); - - // views::View: - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - - DISALLOW_COPY_AND_ASSIGN(NightLightToggleButton); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NIGHT_LIGHT_NIGHT_LIGHT_TOGGLE_BUTTON_H_
diff --git a/ash/system/power/power_status_view.cc b/ash/system/power/power_status_view.cc deleted file mode 100644 index 0907825c..0000000 --- a/ash/system/power/power_status_view.cc +++ /dev/null
@@ -1,101 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/power_status_view.h" - -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/power/tray_power.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/native_theme/native_theme.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/grid_layout.h" - -namespace ash { - -PowerStatusView::PowerStatusView() - : percentage_label_(new views::Label), - separator_label_(new views::Label), - time_status_label_(new views::Label) { - SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); - - percentage_label_->SetEnabledColor(kHeaderTextColorNormal); - separator_label_->SetEnabledColor(kHeaderTextColorNormal); - separator_label_->SetText(base::ASCIIToUTF16(" - ")); - - SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal, gfx::Insets(0, 12), - kTrayPopupPaddingBetweenItems)); - - AddChildView(percentage_label_); - AddChildView(separator_label_); - AddChildView(time_status_label_); - - PowerStatus::Get()->AddObserver(this); - OnPowerStatusChanged(); -} - -PowerStatusView::~PowerStatusView() { - PowerStatus::Get()->RemoveObserver(this); -} - -void PowerStatusView::OnPowerStatusChanged() { - UpdateText(); -} - -void PowerStatusView::UpdateText() { - base::string16 battery_percentage; - base::string16 battery_time_status; - - std::tie(battery_percentage, battery_time_status) = - PowerStatus::Get()->GetStatusStrings(); - - percentage_label_->SetVisible(!battery_percentage.empty()); - percentage_label_->SetText(battery_percentage); - separator_label_->SetVisible(!battery_percentage.empty() && - !battery_time_status.empty()); - time_status_label_->SetVisible(!battery_time_status.empty()); - time_status_label_->SetText(battery_time_status); - - accessible_name_ = PowerStatus::Get()->GetAccessibleNameString(true); - - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SYSTEM_INFO); - style.SetupLabel(percentage_label_); - style.SetupLabel(separator_label_); - style.SetupLabel(time_status_label_); -} - -void PowerStatusView::ChildPreferredSizeChanged(views::View* child) { - PreferredSizeChanged(); -} - -void PowerStatusView::Layout() { - views::View::Layout(); - - // Move the time_status_label_, separator_label_, and percentage_label_ - // closer to each other. - if (percentage_label_ && separator_label_ && time_status_label_ && - percentage_label_->GetVisible() && time_status_label_->GetVisible()) { - separator_label_->SetX(percentage_label_->bounds().right() + 1); - time_status_label_->SetX(separator_label_->bounds().right() + 1); - } -} - -void PowerStatusView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ax::mojom::Role::kLabelText; - node_data->SetName(accessible_name_); -} - -const char* PowerStatusView::GetClassName() const { - return "PowerStatusView"; -} - -} // namespace ash
diff --git a/ash/system/power/power_status_view.h b/ash/system/power/power_status_view.h deleted file mode 100644 index c603576..0000000 --- a/ash/system/power/power_status_view.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_POWER_POWER_STATUS_VIEW_H_ -#define ASH_SYSTEM_POWER_POWER_STATUS_VIEW_H_ - -#include "ash/ash_export.h" -#include "ash/system/power/power_status.h" -#include "base/macros.h" -#include "base/strings/string16.h" -#include "ui/views/view.h" - -namespace views { -class Label; -} - -namespace ash { - -class ASH_EXPORT PowerStatusView : public views::View, - public PowerStatus::Observer { - public: - PowerStatusView(); - ~PowerStatusView() override; - - // views::View: - void Layout() override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - const char* GetClassName() const override; - - // PowerStatus::Observer: - void OnPowerStatusChanged() override; - - private: - friend class PowerStatusViewTest; - - void UpdateText(); - - // views::View: - void ChildPreferredSizeChanged(views::View* child) override; - - views::Label* percentage_label_; - views::Label* separator_label_; - views::Label* time_status_label_; - - base::string16 accessible_name_; - - DISALLOW_COPY_AND_ASSIGN(PowerStatusView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_POWER_POWER_STATUS_VIEW_H_
diff --git a/ash/system/power/power_status_view_unittest.cc b/ash/system/power/power_status_view_unittest.cc deleted file mode 100644 index c17889f9..0000000 --- a/ash/system/power/power_status_view_unittest.cc +++ /dev/null
@@ -1,115 +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. - -#include "ash/system/power/power_status_view.h" - -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/power/power_status.h" -#include "ash/test/ash_test_base.h" -#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/time_format.h" -#include "ui/views/controls/label.h" - -using power_manager::PowerSupplyProperties; - -namespace ash { - -class PowerStatusViewTest : public AshTestBase { - public: - PowerStatusViewTest() = default; - ~PowerStatusViewTest() override = default; - - // Overridden from testing::Test: - void SetUp() override { - AshTestBase::SetUp(); - view_.reset(new PowerStatusView()); - } - - void TearDown() override { - view_.reset(); - AshTestBase::TearDown(); - } - - protected: - void UpdatePowerStatus(const power_manager::PowerSupplyProperties& proto) { - PowerStatus::Get()->SetProtoForTesting(proto); - view_->OnPowerStatusChanged(); - } - - bool IsPercentageVisible() const { - return view_->percentage_label_->GetVisible(); - } - - bool IsTimeStatusVisible() const { - return view_->time_status_label_->GetVisible(); - } - - base::string16 RemainingTimeInView() const { - return view_->time_status_label_->GetText(); - } - - private: - std::unique_ptr<PowerStatusView> view_; - - DISALLOW_COPY_AND_ASSIGN(PowerStatusViewTest); -}; - -TEST_F(PowerStatusViewTest, Basic) { - EXPECT_FALSE(IsPercentageVisible()); - EXPECT_TRUE(IsTimeStatusVisible()); - - // Disconnect the power. - PowerSupplyProperties prop; - prop.set_external_power(PowerSupplyProperties::DISCONNECTED); - prop.set_battery_state(PowerSupplyProperties::DISCHARGING); - prop.set_battery_percent(99.0); - prop.set_battery_time_to_empty_sec(120); - prop.set_is_calculating_battery_time(true); - UpdatePowerStatus(prop); - - EXPECT_TRUE(IsPercentageVisible()); - EXPECT_TRUE(IsTimeStatusVisible()); - EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING), - RemainingTimeInView()); - - prop.set_is_calculating_battery_time(false); - UpdatePowerStatus(prop); - EXPECT_NE(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING), - RemainingTimeInView()); - EXPECT_NE(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE), - RemainingTimeInView()); - - prop.set_external_power(PowerSupplyProperties::AC); - prop.set_battery_state(PowerSupplyProperties::CHARGING); - prop.set_battery_time_to_full_sec(120); - UpdatePowerStatus(prop); - EXPECT_TRUE(IsPercentageVisible()); - EXPECT_TRUE(IsTimeStatusVisible()); - EXPECT_NE(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING), - RemainingTimeInView()); - EXPECT_NE(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE), - RemainingTimeInView()); - - prop.set_external_power(PowerSupplyProperties::USB); - UpdatePowerStatus(prop); - EXPECT_TRUE(IsPercentageVisible()); - EXPECT_TRUE(IsTimeStatusVisible()); - EXPECT_EQ(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE), - RemainingTimeInView()); - - // Tricky -- connected to non-USB but still discharging. Not likely happening - // on production though. - prop.set_external_power(PowerSupplyProperties::AC); - prop.set_battery_state(PowerSupplyProperties::DISCHARGING); - prop.set_battery_time_to_full_sec(120); - UpdatePowerStatus(prop); - EXPECT_TRUE(IsPercentageVisible()); - EXPECT_FALSE(IsTimeStatusVisible()); -} - -} // namespace ash
diff --git a/ash/system/tray/tray_constants.cc b/ash/system/tray/tray_constants.cc index 7fc1444..36fadb71 100644 --- a/ash/system/tray/tray_constants.cc +++ b/ash/system/tray/tray_constants.cc
@@ -27,7 +27,6 @@ const int kTrayPopupAutoCloseDelayInSeconds = 2; const int kTrayPopupPaddingHorizontal = 18; -const int kTrayPopupPaddingBetweenItems = 10; const int kTrayPopupButtonEndMargin = 10; const int kTrayPopupLabelHorizontalPadding = 4; const int kTrayPopupSliderHorizontalPadding = 16; @@ -49,8 +48,6 @@ const SkColor kHeaderBackgroundColor = SkColorSetRGB(0xf5, 0xf5, 0xf5); -const SkColor kHeaderTextColorNormal = SkColorSetARGB(0x7f, 0, 0, 0); - const SkColor kMobileNotConnectedXIconColor = SkColorSetRGB(0xb2, 0xb2, 0xb2); const SkColor kTrayIconColor = gfx::kGoogleGrey200;
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h index e42301a61..ad5e228 100644 --- a/ash/system/tray/tray_constants.h +++ b/ash/system/tray/tray_constants.h
@@ -34,7 +34,6 @@ extern const int kTrayPopupAutoCloseDelayInSeconds; extern const int kTrayPopupPaddingHorizontal; -extern const int kTrayPopupPaddingBetweenItems; extern const int kTrayPopupButtonEndMargin; // The padding used on the left and right of labels. This applies to all labels @@ -72,8 +71,6 @@ extern const SkColor kHeaderBackgroundColor; -extern const SkColor kHeaderTextColorNormal; - // Constants for the title row. constexpr int kTitleRowVerticalPadding = 4; constexpr int kTitleRowProgressBarHeight = 2;
diff --git a/ash/system/tray/tray_popup_utils.cc b/ash/system/tray/tray_popup_utils.cc index fc9fa38..8377a911 100644 --- a/ash/system/tray/tray_popup_utils.cc +++ b/ash/system/tray/tray_popup_utils.cc
@@ -221,21 +221,6 @@ view->layer()->SetFillsBoundsOpaquely(false); } -void TrayPopupUtils::ShowStickyHeaderSeparator(views::View* view, - bool show_separator) { - if (show_separator) { - view->SetBorder(views::CreatePaddedBorder( - views::CreateSolidSidedBorder(0, 0, kTraySeparatorWidth, 0, - kMenuSeparatorColor), - gfx::Insets(kMenuSeparatorVerticalPadding, 0, - kMenuSeparatorVerticalPadding - kTraySeparatorWidth, 0))); - } else { - view->SetBorder(views::CreateEmptyBorder( - gfx::Insets(kMenuSeparatorVerticalPadding, 0))); - } - view->SchedulePaint(); -} - void TrayPopupUtils::ConfigureContainer(TriView::Container container, views::View* container_view) { container_view->SetLayoutManager(CreateDefaultLayoutManager(container)); @@ -348,14 +333,6 @@ return separator; } -views::Separator* TrayPopupUtils::CreateListSubHeaderSeparator() { - views::Separator* separator = new views::Separator(); - separator->SetColor(kMenuSeparatorColor); - separator->SetBorder(views::CreateEmptyBorder( - kMenuSeparatorVerticalPadding - views::Separator::kThickness, 0, 0, 0)); - return separator; -} - bool TrayPopupUtils::CanOpenWebUISettings() { return Shell::Get()->session_controller()->ShouldEnableSettings(); }
diff --git a/ash/system/tray/tray_popup_utils.h b/ash/system/tray/tray_popup_utils.h index 548f0d2..f422be6 100644 --- a/ash/system/tray/tray_popup_utils.h +++ b/ash/system/tray/tray_popup_utils.h
@@ -125,9 +125,6 @@ // Sets up |view| to be a sticky header in a tray detail scroll view. static void ConfigureAsStickyHeader(views::View* view); - // Configures a |view| to have a visible separator below. - static void ShowStickyHeaderSeparator(views::View* view, bool show_separator); - // Configures |container_view| just like CreateDefaultRowView() would // configure |container| on its returned TriView. To be used when mutliple // targetable areas are required within a single row. @@ -188,11 +185,6 @@ // ownership of the returned separator. static views::Separator* CreateListItemSeparator(bool left_inset); - // Creates and returns a horizontal separator line to be drawn between rows - // in a detailed view above the sub-header rows. Caller assumes ownership of - // the returned separator. - static views::Separator* CreateListSubHeaderSeparator(); - // Returns true if it is possible to open WebUI settings in a browser window, // i.e. the user is logged in, not on the lock screen, not adding a secondary // user, and not in the supervised user creation flow.
diff --git a/ash/wm/overview/overview_controller.cc b/ash/wm/overview/overview_controller.cc index b33aade..d7ccaa5 100644 --- a/ash/wm/overview/overview_controller.cc +++ b/ash/wm/overview/overview_controller.cc
@@ -541,6 +541,10 @@ // can accept text input and it resizes correctly with the a11y keyboard. keyboard::KeyboardUIController::Get()->HideKeyboardImplicitlyByUser(); + // Prevent toggling overview during the split view divider snap animation. + if (Shell::Get()->split_view_controller()->IsDividerAnimating()) + return true; + auto windows = Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk);
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc index 03595dd2..3691ce3 100644 --- a/ash/wm/splitview/split_view_controller.cc +++ b/ash/wm/splitview/split_view_controller.cc
@@ -555,6 +555,10 @@ return (work_area_bounds_in_screen.height() - divider_size.height()) * 0.5f; } +bool SplitViewController::IsDividerAnimating() { + return divider_snap_animation_ && divider_snap_animation_->is_animating(); +} + void SplitViewController::StartResize(const gfx::Point& location_in_screen) { DCHECK(InSplitViewMode()); @@ -1442,10 +1446,6 @@ return fix_position; } -bool SplitViewController::IsDividerAnimating() { - return divider_snap_animation_ && divider_snap_animation_->is_animating(); -} - void SplitViewController::StopAndShoveAnimatedDivider() { DCHECK(IsDividerAnimating());
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h index 67bb129..a35e2fe 100644 --- a/ash/wm/splitview/split_view_controller.h +++ b/ash/wm/splitview/split_view_controller.h
@@ -136,6 +136,9 @@ // Gets the default value of |divider_position_|. int GetDefaultDividerPosition(aura::Window* window) const; + // Returns true during the divider snap animation. + bool IsDividerAnimating(); + void StartResize(const gfx::Point& location_in_screen); void Resize(const gfx::Point& location_in_screen); void EndResize(const gfx::Point& location_in_screen); @@ -269,9 +272,6 @@ // Returns the closest fix location for |divider_position_|. int GetClosestFixedDividerPosition(); - // Returns true during the divider snap animation. - bool IsDividerAnimating(); - // While the divider is animating to somewhere, stop it and shove it there. void StopAndShoveAnimatedDivider();
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc index dea8fe5..dd70645 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -8,7 +8,6 @@ #include <string> #include <utility> -#include "ash/kiosk_next/kiosk_next_shell_controller_impl.h" #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/fps_counter.h" #include "ash/public/cpp/shell_window_ids.h" @@ -303,8 +302,6 @@ base::Unretained(this))); } - Shell::Get()->kiosk_next_shell_controller()->AddObserver(this); - chromeos::PowerManagerClient* power_manager_client = chromeos::PowerManagerClient::Get(); power_manager_client->AddObserver(this); @@ -332,7 +329,6 @@ tab_drag_in_splitview_count_); Shell::Get()->RemoveShellObserver(this); - Shell::Get()->kiosk_next_shell_controller()->RemoveObserver(this); if (ShouldInitTabletModeController()) { Shell::Get()->window_tree_host_manager()->RemoveObserver(this); @@ -618,11 +614,6 @@ HandlePointingDeviceAddedOrRemoved(); } -void TabletModeController::OnKioskNextEnabled() { - tablet_mode_behavior_ = kLockInCurrentMode; - AttemptEnterTabletMode(); -} - void TabletModeController::OnLayerAnimationStarted( ui::LayerAnimationSequence* sequence) {}
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.h b/ash/wm/tablet_mode/tablet_mode_controller.h index 4c25a3c1..ebd32aef 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller.h +++ b/ash/wm/tablet_mode/tablet_mode_controller.h
@@ -12,7 +12,6 @@ #include "ash/ash_export.h" #include "ash/bluetooth_devices_observer.h" #include "ash/display/window_tree_host_manager.h" -#include "ash/kiosk_next/kiosk_next_shell_observer.h" #include "ash/public/cpp/tablet_mode.h" #include "ash/session/session_observer.h" #include "ash/shell_observer.h" @@ -71,7 +70,6 @@ public WindowTreeHostManager::Observer, public SessionObserver, public ui::InputDeviceEventObserver, - public KioskNextShellObserver, public ui::LayerAnimationObserver { public: // Enable or disable using a screenshot for testing as it makes the @@ -149,9 +147,6 @@ void OnInputDeviceConfigurationChanged(uint8_t input_device_types) override; void OnDeviceListsComplete() override; - // KioskNextShellObserver: - void OnKioskNextEnabled() override; - // ui::LayerAnimationObserver: void OnLayerAnimationStarted(ui::LayerAnimationSequence* sequence) override; void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override;
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc index 4a95c375..51ce305 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -1483,35 +1483,6 @@ EXPECT_TRUE(Shell::Get()->overview_controller()->StartOverview()); } -// Test that when OnKioskNextEnabled() is called the UI mode changes into -// TabletMode. Ensure that UI mode keeps staying in Tablet Mode. -TEST_F(TabletModeControllerTest, TestKioskNextModeUI) { - ui::DeviceDataManagerTestApi().SetMouseDevices({}); - ui::DeviceDataManagerTestApi().SetTouchpadDevices({}); - ui::DeviceDataManagerTestApi().SetKeyboardDevices({}); - - tablet_mode_controller()->OnKioskNextEnabled(); - EXPECT_TRUE(IsTabletModeStarted()); - - // Attach a mouse. Check that we are still in Tablet Mode. - ui::DeviceDataManagerTestApi().SetMouseDevices( - {ui::InputDevice(0, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")}); - EXPECT_TRUE(IsTabletModeStarted()); - ui::DeviceDataManagerTestApi().SetMouseDevices({}); - - // Attach Touchpad - ui::DeviceDataManagerTestApi().SetTouchpadDevices( - {ui::InputDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "touchpad")}); - EXPECT_TRUE(IsTabletModeStarted()); - ui::DeviceDataManagerTestApi().SetTouchpadDevices({}); - - // Attach Keyboard - ui::DeviceDataManagerTestApi().SetKeyboardDevices( - {ui::InputDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")}); - EXPECT_TRUE(IsTabletModeStarted()); - ui::DeviceDataManagerTestApi().SetKeyboardDevices({}); -} - // Test that tablet mode controller does not respond to the input device changes // during its suspend. TEST_F(TabletModeControllerTest, DoNotObserverInputDeviceChangeDuringSuspend) {
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java index af2b5600..c3388192 100644 --- a/base/android/java/src/org/chromium/base/library_loader/Linker.java +++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -269,7 +269,7 @@ assertLinkerTestsAreEnabled(); synchronized (sLock) { - sSingleton.mTestRunnerClassName = testRunnerClassName; + Linker.getInstance().mTestRunnerClassName = testRunnerClassName; } }
diff --git a/base/android/jni_generator/jni_refactorer.py b/base/android/jni_generator/jni_refactorer.py index de0da86..8502207 100755 --- a/base/android/jni_generator/jni_refactorer.py +++ b/base/android/jni_generator/jni_refactorer.py
@@ -138,7 +138,7 @@ else: import_insert = match.end() + 1 - return "%s%s\n%s" % (contents[:import_insert], JCALLER_IMPORT_STRING, + return "%s%s\n%s" % (contents[:import_insert], import_string, contents[import_insert:]) @@ -370,6 +370,10 @@ ' instead of converting static methods to new jni.') arg_parser.add_argument( '--verbose', default=False, action='store_true', help='') + arg_parser.add_argument( + '--ignored-paths', + action='append', + help='Paths to ignore during conversion.') args = arg_parser.parse_args() @@ -383,29 +387,21 @@ java_file_paths = pickle.load(file) print('Found %s java paths.' % len(java_file_paths)) elif args.recursive: - ignored_paths = [ - 'third_party', 'src/out', 'out/Debug', 'library_loader', '.cipd', - 'jni_generator', 'media', 'accessibility', '/vr', 'website', - 'gcm_driver', 'preferences' - ] - - for root, dirs, files in os.walk(os.path.abspath('.')): - - def getPaths(): - for ignored_path in ignored_paths: - if ignored_path in root: - return - - java_file_paths.extend( - ['%s/%s' % (root, f) for f in files if f.endswith('.java')]) - - getPaths() + for root, _, files in os.walk(os.path.abspath('.')): + java_file_paths.extend( + ['%s/%s' % (root, f) for f in files if f.endswith('.java')]) else: # Get all java files in current dir. java_file_paths = filter(lambda x: x.endswith('.java'), map(os.path.abspath, os.listdir('.'))) + if args.ignored_paths: + java_file_paths = [ + path for path in java_file_paths + if all(p not in path for p in args.ignored_paths) + ] + if args.cache: with open(PICKLE_LOCATION, 'w') as file: pickle.dump(filter_files_with_natives(java_file_paths), file)
diff --git a/base/mac/mach_port_rendezvous.cc b/base/mac/mach_port_rendezvous.cc index 5e71440..43e5806 100644 --- a/base/mac/mach_port_rendezvous.cc +++ b/base/mac/mach_port_rendezvous.cc
@@ -258,11 +258,15 @@ // static MachPortRendezvousClient* MachPortRendezvousClient::GetInstance() { - static MachPortRendezvousClient* client = new MachPortRendezvousClient(); - if (!client->did_acquire_ports()) { - bool ok = client->AcquirePorts(); - DCHECK(ok); + static MachPortRendezvousClient* client = []() -> auto* { + auto* client = new MachPortRendezvousClient(); + if (!client->AcquirePorts()) { + delete client; + client = nullptr; + } + return client; } + (); return client; } @@ -296,8 +300,6 @@ bool MachPortRendezvousClient::AcquirePorts() { AutoLock lock(lock_); - did_acquire_ports_ = true; - mac::ScopedMachSendRight server_port; std::string bootstrap_name = GetBootstrapName(); kern_return_t kr = bootstrap_look_up(
diff --git a/base/mac/mach_port_rendezvous.h b/base/mac/mach_port_rendezvous.h index 422b2df30..5fd9d08 100644 --- a/base/mac/mach_port_rendezvous.h +++ b/base/mac/mach_port_rendezvous.h
@@ -82,7 +82,9 @@ public: // Returns the instance of the server. Upon the first call to this method, // the server is created, which registers an endpoint in the Mach bootstrap - // namespace. + // namespace. If the rendezvous fails, which can happen if the server is not + // available, this returns null. Acquiring zero ports from the exchange is + // not considered a failure. static MachPortRendezvousServer* GetInstance(); // Registers a collection of Mach ports |ports| to be acquirable by the @@ -202,13 +204,8 @@ // MachRendezvousPort with MACH_PORT_NULL is returned. MachRendezvousPort PortForKey(MachPortsForRendezvous::key_type key); - bool did_acquire_ports() { return did_acquire_ports_; } - // Lock for the below data members. Lock lock_; - // Flag for if the client has attempted to acquire ports. If the client - // experienced an error in doing so, this will still be true. - bool did_acquire_ports_ = false; // The collection of ports that was acquired. MachPortsForRendezvous ports_;
diff --git a/base/mac/mach_port_rendezvous_unittest.cc b/base/mac/mach_port_rendezvous_unittest.cc index 5af2a86..a66c1cef 100644 --- a/base/mac/mach_port_rendezvous_unittest.cc +++ b/base/mac/mach_port_rendezvous_unittest.cc
@@ -9,6 +9,7 @@ #include <utility> #include "base/at_exit.h" +#include "base/mac/foundation_util.h" #include "base/mac/mach_logging.h" #include "base/strings/stringprintf.h" #include "base/test/multiprocess_test.h" @@ -206,4 +207,25 @@ } } +MULTIPROCESS_TEST_MAIN(FailToRendezvous) { + // The rendezvous system uses the BaseBundleID to construct the bootstrap + // server name, so changing it will result in a failure to look it up. + base::mac::SetBaseBundleID("org.chromium.totallyfake"); + CHECK_EQ(nullptr, base::MachPortRendezvousClient::GetInstance()); + return 0; +} + +TEST_F(MachPortRendezvousServerTest, FailToRendezvous) { + auto* server = MachPortRendezvousServer::GetInstance(); + ASSERT_TRUE(server); + + Process child = SpawnChild("FailToRendezvous"); + + int exit_code; + ASSERT_TRUE(WaitForMultiprocessTestChildExit( + child, TestTimeouts::action_timeout(), &exit_code)); + + EXPECT_EQ(0, exit_code); +} + } // namespace base
diff --git a/base/memory/shared_memory.h b/base/memory/shared_memory.h index bd97f11b..f095516c 100644 --- a/base/memory/shared_memory.h +++ b/base/memory/shared_memory.h
@@ -98,9 +98,6 @@ // Closes a shared memory handle. static void CloseHandle(const SharedMemoryHandle& handle); - // Returns the maximum number of handles that can be open at once per process. - static size_t GetHandleLimit(); - // Duplicates The underlying OS primitive. Returns an invalid handle on // failure. The caller is responsible for destroying the duplicated OS // primitive.
diff --git a/base/memory/shared_memory_fuchsia.cc b/base/memory/shared_memory_fuchsia.cc index a386913a..878906a 100644 --- a/base/memory/shared_memory_fuchsia.cc +++ b/base/memory/shared_memory_fuchsia.cc
@@ -38,13 +38,6 @@ handle.Close(); } -// static -size_t SharedMemory::GetHandleLimit() { - // Duplicated from the internal Magenta kernel constant kMaxHandleCount - // (kernel/lib/zircon/zircon.cpp). - return 256 * 1024u; -} - bool SharedMemory::CreateAndMapAnonymous(size_t size) { return CreateAnonymous(size) && Map(size); }
diff --git a/base/memory/shared_memory_mac.cc b/base/memory/shared_memory_mac.cc index fc1af800..82dfeae0 100644 --- a/base/memory/shared_memory_mac.cc +++ b/base/memory/shared_memory_mac.cc
@@ -99,11 +99,6 @@ } // static -size_t SharedMemory::GetHandleLimit() { - return GetMaxFds(); -} - -// static SharedMemoryHandle SharedMemory::DuplicateHandle( const SharedMemoryHandle& handle) { return handle.Duplicate();
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc index 0988b5ad..f92a916 100644 --- a/base/memory/shared_memory_posix.cc +++ b/base/memory/shared_memory_posix.cc
@@ -60,11 +60,6 @@ } // static -size_t SharedMemory::GetHandleLimit() { - return GetMaxFds(); -} - -// static SharedMemoryHandle SharedMemory::DuplicateHandle( const SharedMemoryHandle& handle) { return handle.Duplicate();
diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc index 88e3cbbc..b0adabe 100644 --- a/base/memory/shared_memory_win.cc +++ b/base/memory/shared_memory_win.cc
@@ -163,13 +163,6 @@ } // static -size_t SharedMemory::GetHandleLimit() { - // Rounded down from value reported here: - // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx - return static_cast<size_t>(1 << 23); -} - -// static SharedMemoryHandle SharedMemory::DuplicateHandle( const SharedMemoryHandle& handle) { return handle.Duplicate();
diff --git a/base/message_loop/message_pump_fuchsia.cc b/base/message_loop/message_pump_fuchsia.cc index 25b255dd..948785d 100644 --- a/base/message_loop/message_pump_fuchsia.cc +++ b/base/message_loop/message_pump_fuchsia.cc
@@ -92,14 +92,6 @@ controller->handler = nullptr; - // |signal| can include other spurious things, in particular, that an fd - // is writable, when we only asked to know when it was readable. In that - // case, we don't want to call both the CanWrite and CanRead callback, - // when the caller asked for only, for example, readable callbacks. So, - // mask with the events that we actually wanted to know about. - zx_signals_t signals = signal->trigger & signal->observed; - DCHECK_NE(0u, signals); - // In the case of a persistent Watch, the Watch may be stopped and // potentially deleted by the caller within the callback, in which case // |controller| should not be accessed again, and we mustn't continue the @@ -108,7 +100,7 @@ bool was_stopped = false; controller->was_stopped_ = &was_stopped; - controller->watcher_->OnZxHandleSignalled(wait->object, signals); + controller->watcher_->OnZxHandleSignalled(wait->object, signal->observed); if (was_stopped) return; @@ -125,6 +117,14 @@ uint32_t events; fdio_unsafe_wait_end(io_, signals, &events); + // |events| can include other spurious things, in particular, that an fd + // is writable, when we only asked to know when it was readable. In that + // case, we don't want to call both the CanWrite and CanRead callback, + // when the caller asked for only, for example, readable callbacks. So, + // mask with the events that we actually wanted to know about. + events &= desired_events_; + DCHECK_NE(0u, events); + // Each |watcher_| callback we invoke may stop or delete |this|. The pump has // set |was_stopped_| to point to a safe location on the calling stack, so we // can use that to detect being stopped mid-callback and avoid doing further
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index b2335a7..09eb38fb 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc
@@ -1217,6 +1217,8 @@ win::ScopedHandle scoped_handle(handle); #elif defined(OS_MACOSX) && !defined(OS_IOS) auto* rendezvous = MachPortRendezvousClient::GetInstance(); + if (!rendezvous) + return ReadOnlySharedMemoryRegion(); mac::ScopedMachSendRight scoped_handle = rendezvous->TakeSendRight(field_trial_handle); if (!scoped_handle.is_valid())
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h index f445125..2599109 100644 --- a/base/process/process_metrics.h +++ b/base/process/process_metrics.h
@@ -254,6 +254,9 @@ // at once. If the number is unavailable, a conservative best guess is returned. BASE_EXPORT size_t GetMaxFds(); +// Returns the maximum number of handles that can be open at once per process. +BASE_EXPORT size_t GetHandleLimit(); + #if defined(OS_POSIX) // Increases the file descriptor soft limit to |max_descriptors| or the OS hard // limit, whichever is lower. If the limit is already higher than
diff --git a/base/process/process_metrics_fuchsia.cc b/base/process/process_metrics_fuchsia.cc index ddfa9c6..3c7d14c 100644 --- a/base/process/process_metrics_fuchsia.cc +++ b/base/process/process_metrics_fuchsia.cc
@@ -12,6 +12,12 @@ return FDIO_MAX_FD; } +size_t GetHandleLimit() { + // Duplicated from the internal Magenta kernel constant kMaxHandleCount + // (zircon/kernel/object/handle.cc). + return 256 * 1024u; +} + size_t GetSystemCommitCharge() { // TODO(https://crbug.com/926581): Fuchsia does not support this. return 0;
diff --git a/base/process/process_metrics_posix.cc b/base/process/process_metrics_posix.cc index a09bbf2..5763432 100644 --- a/base/process/process_metrics_posix.cc +++ b/base/process/process_metrics_posix.cc
@@ -71,6 +71,15 @@ return static_cast<size_t>(max_fds); } +size_t GetHandleLimit() { +#if defined(OS_MACOSX) + // Taken from a small test that allocated ports in a loop. + return static_cast<size_t>(1 << 18); +#else + return GetMaxFds(); +#endif +} + void IncreaseFdLimitTo(unsigned int max_descriptors) { struct rlimit limits; if (getrlimit(RLIMIT_NOFILE, &limits) == 0) {
diff --git a/base/process/process_metrics_win.cc b/base/process/process_metrics_win.cc index fcf69acc..5cf0943 100644 --- a/base/process/process_metrics_win.cc +++ b/base/process/process_metrics_win.cc
@@ -129,6 +129,12 @@ return std::numeric_limits<size_t>::max(); } +size_t GetHandleLimit() { + // Rounded down from value reported here: + // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx + return static_cast<size_t>(1 << 23); +} + // static std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( ProcessHandle process) {
diff --git a/base/task/promise/dependent_list.cc b/base/task/promise/dependent_list.cc index 81cc763..6cbbf345 100644 --- a/base/task/promise/dependent_list.cc +++ b/base/task/promise/dependent_list.cc
@@ -47,7 +47,7 @@ DependentList::Node::Node() = default; -DependentList::Node::Node(Node&& other) { +DependentList::Node::Node(Node&& other) noexcept { prerequisite_ = other.prerequisite_.load(std::memory_order_relaxed); other.prerequisite_ = 0; dependent_ = std::move(other.dependent_);
diff --git a/base/task/promise/finally_executor.cc b/base/task/promise/finally_executor.cc index 27cc023bf..52da5678 100644 --- a/base/task/promise/finally_executor.cc +++ b/base/task/promise/finally_executor.cc
@@ -7,7 +7,8 @@ namespace base { namespace internal { -FinallyExecutorCommon::FinallyExecutorCommon(internal::CallbackBase&& callback) +FinallyExecutorCommon::FinallyExecutorCommon( + internal::CallbackBase&& callback) noexcept : callback_(std::move(callback)) {} FinallyExecutorCommon::~FinallyExecutorCommon() = default;
diff --git a/base/task/promise/helpers.cc b/base/task/promise/helpers.cc index 5008363..35dc37d 100644 --- a/base/task/promise/helpers.cc +++ b/base/task/promise/helpers.cc
@@ -40,7 +40,7 @@ const scoped_refptr<TaskRunner>& task_runner, const Location& from_here, AbstractPromise* prerequsite, - internal::PromiseExecutor::Data&& executor_data) { + internal::PromiseExecutor::Data&& executor_data) noexcept { return internal::AbstractPromise::Create( task_runner, from_here, std::make_unique<AbstractPromise::AdjacencyList>(prerequsite),
diff --git a/base/task/sequence_manager/task_queue.cc b/base/task/sequence_manager/task_queue.cc index a69f9d30..35ff9d7 100644 --- a/base/task/sequence_manager/task_queue.cc +++ b/base/task/sequence_manager/task_queue.cc
@@ -329,6 +329,10 @@ impl_->SetObserver(observer); } +void TaskQueue::SetShouldReportPostedTasksWhenDisabled(bool should_report) { + impl_->SetShouldReportPostedTasksWhenDisabled(should_report); +} + bool TaskQueue::IsOnMainThread() const { return associated_thread_->IsBoundToCurrentThread(); }
diff --git a/base/task/sequence_manager/task_queue.h b/base/task/sequence_manager/task_queue.h index f57b4a1..d863308 100644 --- a/base/task/sequence_manager/task_queue.h +++ b/base/task/sequence_manager/task_queue.h
@@ -325,6 +325,12 @@ void SetObserver(Observer* observer); + // Controls whether or not the queue will emit traces events when tasks are + // posted to it while disabled. This only applies for the current or next + // period during which the queue is disabled. When the queue is re-enabled + // this will revert back to the default value of false. + void SetShouldReportPostedTasksWhenDisabled(bool should_report); + // Create a task runner for this TaskQueue which will annotate all // posted tasks with the given task type. // May be called on any thread.
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc index 0ad98e8..a46b72de 100644 --- a/base/task/sequence_manager/task_queue_impl.cc +++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -136,6 +136,9 @@ TaskQueueImpl::AnyThread::~AnyThread() = default; +TaskQueueImpl::AnyThread::TracingOnly::TracingOnly() = default; +TaskQueueImpl::AnyThread::TracingOnly::~TracingOnly() = default; + TaskQueueImpl::MainThreadOnly::MainThreadOnly(TaskQueueImpl* task_queue, TimeDomain* time_domain) : time_domain(time_domain), @@ -143,10 +146,7 @@ new WorkQueue(task_queue, "delayed", WorkQueue::QueueType::kDelayed)), immediate_work_queue(new WorkQueue(task_queue, "immediate", - WorkQueue::QueueType::kImmediate)), - is_enabled(true), - blame_context(nullptr), - is_enabled_for_test(true) {} + WorkQueue::QueueType::kImmediate)) {} TaskQueueImpl::MainThreadOnly::~MainThreadOnly() = default; @@ -290,6 +290,8 @@ sequence_manager_->WillQueueTask( &any_thread_.immediate_incoming_queue.back(), name_); + MaybeReportIpcTaskQueuedFromAnyThreadLocked( + &any_thread_.immediate_incoming_queue.back(), name_); // If this queue was completely empty, then the SequenceManager needs to be // informed so it can reload the work queue and add us to the @@ -386,8 +388,10 @@ pending_task.cross_thread_ = false; #endif - if (notify_task_annotator) + if (notify_task_annotator) { sequence_manager_->WillQueueTask(&pending_task, name_); + MaybeReportIpcTaskQueuedFromMainThread(&pending_task, name_); + } main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); LazyNow lazy_now(now); @@ -398,6 +402,7 @@ void TaskQueueImpl::PushOntoDelayedIncomingQueue(Task pending_task) { sequence_manager_->WillQueueTask(&pending_task, name_); + MaybeReportIpcTaskQueuedFromAnyThreadUnlocked(&pending_task, name_); #if DCHECK_IS_ON() pending_task.cross_thread_ = true; @@ -880,29 +885,45 @@ } void TaskQueueImpl::SetQueueEnabled(bool enabled) { - if (main_thread_only().is_enabled != enabled) { - main_thread_only().is_enabled = enabled; - EnableOrDisableWithSelector(enabled); - } -} - -void TaskQueueImpl::EnableOrDisableWithSelector(bool enable) { - // |sequence_manager_| can be null in tests. - if (!sequence_manager_) + if (main_thread_only().is_enabled == enabled) return; + // Update the |main_thread_only_| struct. + main_thread_only().is_enabled = enabled; + main_thread_only().disabled_time = nullopt; + if (!enabled) { + bool tracing_enabled = false; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("lifecycles"), + &tracing_enabled); + main_thread_only().disabled_time = main_thread_only().time_domain->Now(); + } else { + // Override reporting if the queue is becoming enabled again. + main_thread_only().should_report_posted_tasks_when_disabled = false; + } + LazyNow lazy_now = main_thread_only().time_domain->CreateLazyNow(); UpdateDelayedWakeUp(&lazy_now); - bool has_pending_immediate_work; + bool has_pending_immediate_work = false; { base::internal::CheckedAutoLock lock(any_thread_lock_); UpdateCrossThreadQueueStateLocked(); has_pending_immediate_work = HasPendingImmediateWorkLocked(); + + // Copy over the task-reporting related state. + any_thread_.tracing_only.is_enabled = enabled; + any_thread_.tracing_only.disabled_time = main_thread_only().disabled_time; + any_thread_.tracing_only.should_report_posted_tasks_when_disabled = + main_thread_only().should_report_posted_tasks_when_disabled; } - if (enable) { + // |sequence_manager_| can be null in tests. + if (!sequence_manager_) + return; + + // Finally, enable or disable the queue with the selector. + if (enabled) { if (has_pending_immediate_work && main_thread_only().task_queue_observer) { // Delayed work notification will be issued via time domain. main_thread_only().task_queue_observer->OnQueueNextWakeUpChanged( @@ -917,6 +938,30 @@ } } +void TaskQueueImpl::SetShouldReportPostedTasksWhenDisabled(bool should_report) { + if (main_thread_only().should_report_posted_tasks_when_disabled == + should_report) + return; + + // Only observe transitions turning the reporting on if tracing is enabled. + if (should_report) { + bool tracing_enabled = false; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("lifecycles"), + &tracing_enabled); + if (!tracing_enabled) + return; + } + + main_thread_only().should_report_posted_tasks_when_disabled = should_report; + + // Mirror the state to the AnyThread struct as well. + { + base::internal::CheckedAutoLock lock(any_thread_lock_); + any_thread_.tracing_only.should_report_posted_tasks_when_disabled = + should_report; + } +} + void TaskQueueImpl::UpdateCrossThreadQueueStateLocked() { any_thread_.immediate_work_queue_empty = main_thread_only().immediate_work_queue->Empty(); @@ -1139,6 +1184,107 @@ return false; } +void TaskQueueImpl::MaybeReportIpcTaskQueuedFromMainThread( + Task* pending_task, + const char* task_queue_name) { + if (!pending_task->ipc_hash) + return; + + // It's possible that tracing was just enabled and no disabled time has been + // stored. In that case, skip emitting the event. + if (!main_thread_only().disabled_time) + return; + + bool tracing_enabled = false; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("lifecycles"), + &tracing_enabled); + if (!tracing_enabled) + return; + + if (main_thread_only().is_enabled || + !main_thread_only().should_report_posted_tasks_when_disabled) { + return; + } + + base::TimeDelta time_since_disabled = + main_thread_only().time_domain->Now() - + main_thread_only().disabled_time.value(); + + ReportIpcTaskQueued(pending_task, task_queue_name, time_since_disabled); +} + +bool TaskQueueImpl::ShouldReportIpcTaskQueuedFromAnyThreadLocked( + base::TimeDelta* time_since_disabled) { + // It's possible that tracing was just enabled and no disabled time has been + // stored. In that case, skip emitting the event. + if (!any_thread_.tracing_only.disabled_time) + return false; + + if (any_thread_.tracing_only.is_enabled || + any_thread_.tracing_only.should_report_posted_tasks_when_disabled) { + return false; + } + + *time_since_disabled = any_thread_.time_domain->Now() - + any_thread_.tracing_only.disabled_time.value(); + return true; +} + +void TaskQueueImpl::MaybeReportIpcTaskQueuedFromAnyThreadLocked( + Task* pending_task, + const char* task_queue_name) { + if (!pending_task->ipc_hash) + return; + + bool tracing_enabled = false; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("lifecycles"), + &tracing_enabled); + if (!tracing_enabled) + return; + + base::TimeDelta time_since_disabled; + if (ShouldReportIpcTaskQueuedFromAnyThreadLocked(&time_since_disabled)) + ReportIpcTaskQueued(pending_task, task_queue_name, time_since_disabled); +} + +void TaskQueueImpl::MaybeReportIpcTaskQueuedFromAnyThreadUnlocked( + Task* pending_task, + const char* task_queue_name) { + if (!pending_task->ipc_hash) + return; + + bool tracing_enabled = false; + TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("lifecycles"), + &tracing_enabled); + if (!tracing_enabled) + return; + + base::TimeDelta time_since_disabled; + bool should_report = false; + { + base::internal::CheckedAutoLock lock(any_thread_lock_); + should_report = + ShouldReportIpcTaskQueuedFromAnyThreadLocked(&time_since_disabled); + } + + ReportIpcTaskQueued(pending_task, task_queue_name, time_since_disabled); +} + +void TaskQueueImpl::ReportIpcTaskQueued( + Task* pending_task, + const char* task_queue_name, + const base::TimeDelta& time_since_disabled) { + // Use a begin/end event pair so we can get 4 fields in the event. + TRACE_EVENT_BEGIN2(TRACE_DISABLED_BY_DEFAULT("lifecycles"), + "task_posted_to_disabled_queue", "task_queue_name", + task_queue_name, "time_since_disabled_ms", + time_since_disabled.InMilliseconds()); + TRACE_EVENT_END2(TRACE_DISABLED_BY_DEFAULT("lifecycles"), + "task_posted_to_disabled_queue", "ipc_hash", + pending_task->ipc_hash, "location", + pending_task->posted_from.program_counter()); +} + TaskQueueImpl::DelayedIncomingQueue::DelayedIncomingQueue() = default; TaskQueueImpl::DelayedIncomingQueue::~DelayedIncomingQueue() = default;
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h index d5a4ea6..ed5489dd 100644 --- a/base/task/sequence_manager/task_queue_impl.h +++ b/base/task/sequence_manager/task_queue_impl.h
@@ -102,6 +102,7 @@ const char* GetName() const; bool IsQueueEnabled() const; void SetQueueEnabled(bool enabled); + void SetShouldReportPostedTasksWhenDisabled(bool should_report); bool IsEmpty() const; size_t GetNumberOfPendingTasks() const; bool HasTaskToRunImmediately() const; @@ -340,8 +341,8 @@ DelayedIncomingQueue delayed_incoming_queue; ObserverList<TaskObserver>::Unchecked task_observers; base::internal::HeapHandle heap_handle; - bool is_enabled; - trace_event::BlameContext* blame_context; // Not owned. + bool is_enabled = true; + trace_event::BlameContext* blame_context = nullptr; // Not owned. EnqueueOrder current_fence; Optional<TimeTicks> delayed_fence; OnTaskStartedHandler on_task_started_handler; @@ -350,7 +351,13 @@ // excessive calls. Optional<DelayedWakeUp> scheduled_wake_up; // If false, queue will be disabled. Used only for tests. - bool is_enabled_for_test; + bool is_enabled_for_test = true; + // The time at which the task queue was disabled, if it is currently + // disabled. + Optional<TimeTicks> disabled_time; + // Whether or not the task queue should emit tracing events for tasks + // posted to this queue when it is disabled. + bool should_report_posted_tasks_when_disabled = false; }; void PostTask(PostedTask task); @@ -394,8 +401,6 @@ TimeTicks now, trace_event::TracedValue* state); - void EnableOrDisableWithSelector(bool enable); - // Schedules delayed work on time domain and calls the observer. void UpdateDelayedWakeUp(LazyNow* lazy_now); void UpdateDelayedWakeUpImpl(LazyNow* lazy_now, @@ -411,6 +416,23 @@ void MaybeLogPostTask(PostedTask* task); void MaybeAdjustTaskDelay(PostedTask* task, CurrentThread current_thread); + // Reports the task if it was due to IPC and was posted to a disabled queue. + // This should be called after WillQueueTask has been called for the task. + void MaybeReportIpcTaskQueuedFromMainThread(Task* pending_task, + const char* task_queue_name); + bool ShouldReportIpcTaskQueuedFromAnyThreadLocked( + base::TimeDelta* time_since_disabled) + EXCLUSIVE_LOCKS_REQUIRED(any_thread_lock_); + void MaybeReportIpcTaskQueuedFromAnyThreadLocked(Task* pending_task, + const char* task_queue_name) + EXCLUSIVE_LOCKS_REQUIRED(any_thread_lock_); + void MaybeReportIpcTaskQueuedFromAnyThreadUnlocked( + Task* pending_task, + const char* task_queue_name); + void ReportIpcTaskQueued(Task* pending_task, + const char* task_queue_name, + const base::TimeDelta& time_since_disabled); + const char* name_; SequenceManagerImpl* const sequence_manager_; @@ -421,6 +443,16 @@ mutable base::internal::CheckedLock any_thread_lock_; struct AnyThread { + // Mirrored from MainThreadOnly. These are only used for tracing. + struct TracingOnly { + TracingOnly(); + ~TracingOnly(); + + bool is_enabled = true; + Optional<TimeTicks> disabled_time; + bool should_report_posted_tasks_when_disabled = false; + }; + explicit AnyThread(TimeDomain* time_domain); ~AnyThread(); @@ -441,12 +473,14 @@ bool unregistered = false; #if DCHECK_IS_ON() - // A cached of |immediate_work_queue->work_queue_set_index()| which is used + // A cache of |immediate_work_queue->work_queue_set_index()| which is used // to index into // SequenceManager::Settings::per_priority_cross_thread_task_delay to apply // a priority specific delay for debugging purposes. int queue_set_index = 0; #endif + + TracingOnly tracing_only; }; AnyThread any_thread_ GUARDED_BY(any_thread_lock_);
diff --git a/base/task/thread_pool/task_source.cc b/base/task/thread_pool/task_source.cc index de0fcd3..b978251 100644 --- a/base/task/thread_pool/task_source.cc +++ b/base/task/thread_pool/task_source.cc
@@ -15,7 +15,7 @@ namespace base { namespace internal { -TaskSource::RunIntent::RunIntent(RunIntent&& other) +TaskSource::RunIntent::RunIntent(RunIntent&& other) noexcept : task_source_(other.task_source_), concurrency_status_(other.concurrency_status_) { other.task_source_ = nullptr; @@ -111,8 +111,8 @@ RegisteredTaskSource::RegisteredTaskSource(std::nullptr_t) : RegisteredTaskSource() {} -RegisteredTaskSource::RegisteredTaskSource(RegisteredTaskSource&& other) = - default; +RegisteredTaskSource::RegisteredTaskSource( + RegisteredTaskSource&& other) noexcept = default; RegisteredTaskSource::~RegisteredTaskSource() { Unregister();
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h index 2225bfc..426860c 100644 --- a/base/trace_event/builtin_categories.h +++ b/base/trace_event/builtin_categories.h
@@ -177,6 +177,7 @@ X(TRACE_DISABLED_BY_DEFAULT("gpu.service")) \ X(TRACE_DISABLED_BY_DEFAULT("ipc.flow")) \ X(TRACE_DISABLED_BY_DEFAULT("layer-element")) \ + X(TRACE_DISABLED_BY_DEFAULT("lifecycles")) \ X(TRACE_DISABLED_BY_DEFAULT("loading")) \ X(TRACE_DISABLED_BY_DEFAULT("memory-infra")) \ X(TRACE_DISABLED_BY_DEFAULT("memory-infra.v8.code_stats")) \
diff --git a/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java b/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java index efefcbc8..56b84845 100644 --- a/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java +++ b/build/android/bytecode/java/org/chromium/bytecode/ByteCodeProcessor.java
@@ -113,15 +113,20 @@ writer = new ClassWriter(reader, 0); } ClassVisitor chain = writer; - /* DEBUGGING: - To see the bytecode for a specific class: - if (entry.getName().contains("YourClassName")) { - chain = new TraceClassVisitor(chain, new PrintWriter(System.out)); - } + /* DEBUGGING:} To see objectweb.asm code that will generate bytecode for a given class: - java -cp "third_party/ow2_asm/lib/asm-5.0.1.jar:third_party/ow2_asm/lib/"\ - "asm-util-5.0.1.jar:out/Debug/lib.java/jar_containing_yourclass.jar" \ - org.objectweb.asm.util.ASMifier org.package.YourClassName + + java -cp + "third_party/ow2_asm/lib/asm.jar:third_party/ow2_asm/lib/asm-util.jar:out/Debug/lib.java/jar_containing_yourclass.jar" + org.objectweb.asm.util.ASMifier org.package.YourClassName + + See this pdf for more details: https://asm.ow2.io/asm4-guide.pdf + + To see the bytecode for a specific class, uncomment this code with your class name: + + if (entry.getName().contains("YOUR_CLASS_NAME")) { + chain = new TraceClassVisitor(chain, new PrintWriter(System.out)); + } */ if (sShouldUseThreadAnnotations) { chain = new ThreadAssertionClassAdapter(chain);
diff --git a/build/android/bytecode/java/org/chromium/bytecode/SplitCompatClassAdapter.java b/build/android/bytecode/java/org/chromium/bytecode/SplitCompatClassAdapter.java index 8d6ae69..d8aa284 100644 --- a/build/android/bytecode/java/org/chromium/bytecode/SplitCompatClassAdapter.java +++ b/build/android/bytecode/java/org/chromium/bytecode/SplitCompatClassAdapter.java
@@ -6,6 +6,7 @@ import static org.objectweb.asm.Opcodes.ACC_PROTECTED; import static org.objectweb.asm.Opcodes.ALOAD; +import static org.objectweb.asm.Opcodes.INVOKEINTERFACE; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import static org.objectweb.asm.Opcodes.RETURN; @@ -34,6 +35,9 @@ private static final String MODULE_INSTALLER_CLASS_NAME = "org/chromium/components/module_installer/ModuleInstaller"; + private static final String GET_INSTANCE_METHOD_NAME = "getInstance"; + private static final String GET_INSTANCE_DESCRIPTOR = + TypeUtils.getMethodDescriptor(MODULE_INSTALLER_CLASS_NAME); private static final String INIT_ACTIVITY_METHOD_NAME = "initActivity"; private static final String INIT_ACTIVITY_DESCRIPTOR = TypeUtils.getMethodDescriptor(VOID, CONTEXT); @@ -107,7 +111,7 @@ * <pre> * protected void attachBaseContext(Context base) { * super.attachBaseContext(base); - * ModuleInstaller.initActivity(this); + * ModuleInstaller.getInstance().initActivity(this); * } * </pre> */ @@ -115,16 +119,30 @@ MethodVisitor mv = super.visitMethod(ACC_PROTECTED, ATTACH_BASE_CONTEXT_METHOD_NAME, ATTACH_BASE_CONTEXT_DESCRIPTOR, null, null); mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); // load "this" on stack - mv.visitVarInsn(ALOAD, 1); // load first method parameter on stack (Context) + // Push "this" on stack. + mv.visitVarInsn(ALOAD, 0); + // Push first method parameter on stack (Context). + mv.visitVarInsn(ALOAD, 1); + // Pop argument from stack (Context). + // Pop target object from stack ("this"). + // Calls attachBaseContext. mv.visitMethodInsn(INVOKESPECIAL, ANDROID_APP_ACTIVITY_CLASS_NAME, - ATTACH_BASE_CONTEXT_METHOD_NAME, - ATTACH_BASE_CONTEXT_DESCRIPTOR); // invoke super's attach base context - mv.visitVarInsn(ALOAD, 0); // load "this" on stack - mv.visitMethodInsn(INVOKESTATIC, MODULE_INSTALLER_CLASS_NAME, INIT_ACTIVITY_METHOD_NAME, - INIT_ACTIVITY_DESCRIPTOR); + ATTACH_BASE_CONTEXT_METHOD_NAME, ATTACH_BASE_CONTEXT_DESCRIPTOR, false); + // Push return value on stack (ModuleInstaller). + // Calls getInstance. + mv.visitMethodInsn(INVOKESTATIC, MODULE_INSTALLER_CLASS_NAME, GET_INSTANCE_METHOD_NAME, + GET_INSTANCE_DESCRIPTOR, false); + // Push "this" on stack. + mv.visitVarInsn(ALOAD, 0); + // Pop argument from stack ("this"). + // Pop target object from stack (ModuleInstaller). + // Calls initActivity. + mv.visitMethodInsn(INVOKEINTERFACE, MODULE_INSTALLER_CLASS_NAME, INIT_ACTIVITY_METHOD_NAME, + INIT_ACTIVITY_DESCRIPTOR, true); mv.visitInsn(RETURN); - mv.visitMaxs(2, 2); // max stack size - 2, max locals - 2 + // Max stack size = 2 (Only push at most 2 before popping). + // Max locals = 2 ("this" and 1 parameter). + mv.visitMaxs(2, 2); mv.visitEnd(); }
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py index 57efc8b..199d8bcb 100755 --- a/build/android/gyp/compile_resources.py +++ b/build/android/gyp/compile_resources.py
@@ -139,6 +139,13 @@ help='Use resource IDs generated by aapt --emit-ids.') input_opts.add_argument( + '--extra-main-r-text-files', + help='Additional R.txt files that will be added to the root R.java file, ' + 'but not packaged in the generated resources.arsc. If these resources ' + 'entries contain duplicate resources with the generated R.txt file, they ' + 'must be identical.') + + input_opts.add_argument( '--support-zh-hk', action='store_true', help='Use zh-rTW resources for zh-rHK.') @@ -157,7 +164,8 @@ required=True, help="android:targetSdkVersion for APK.") input_opts.add_argument( - '--max-sdk-version', help="android:maxSdkVersion for APK.") + '--max-sdk-version', + help="android:maxSdkVersion expected in AndroidManifest.xml.") input_opts.add_argument( '--manifest-package', help='Package name of the AndroidManifest.xml.') @@ -244,6 +252,8 @@ options.shared_resources_whitelist_locales) options.resource_blacklist_exceptions = build_utils.ParseGnList( options.resource_blacklist_exceptions) + options.extra_main_r_text_files = build_utils.ParseGnList( + options.extra_main_r_text_files) if options.optimized_proto_path and not options.proto_path: # We could write to a temp file, but it's simpler to require it. @@ -467,8 +477,13 @@ options.android_manifest) manifest_utils.AssertUsesSdk(manifest_node, options.min_sdk_version, - options.target_sdk_version, - options.max_sdk_version) + options.target_sdk_version) + # We explicitly check that maxSdkVersion is set in the manifest since we don't + # add it later like minSdkVersion and targetSdkVersion. + manifest_utils.AssertUsesSdk( + manifest_node, + max_sdk_version=options.max_sdk_version, + fail_if_not_exist=True) manifest_utils.AssertPackage(manifest_node, options.manifest_package) manifest_node.set('platformBuildVersionCode', version_code) @@ -966,7 +981,8 @@ resource_utils.CreateRJavaFiles( build.srcjar_dir, None, build.r_txt_path, options.extra_res_packages, options.extra_r_text_files, rjava_build_options, options.srcjar_out, - custom_root_package_name, grandparent_custom_package_name) + custom_root_package_name, grandparent_custom_package_name, + options.extra_main_r_text_files) build_utils.ZipDir(build.srcjar_path, build.srcjar_dir)
diff --git a/build/android/gyp/merge_manifest.py b/build/android/gyp/merge_manifest.py index a7b2eff1..5680ad9 100755 --- a/build/android/gyp/merge_manifest.py +++ b/build/android/gyp/merge_manifest.py
@@ -30,14 +30,15 @@ @contextlib.contextmanager def _ProcessManifest(manifest_path, min_sdk_version, target_sdk_version, - manifest_package): + max_sdk_version, manifest_package): """Patches an Android manifest to always include the 'tools' namespace declaration, as it is not propagated by the manifest merger from the SDK. See https://issuetracker.google.com/issues/63411481 """ doc, manifest, _ = manifest_utils.ParseManifest(manifest_path) - manifest_utils.AssertUsesSdk(manifest, min_sdk_version, target_sdk_version) + manifest_utils.AssertUsesSdk(manifest, min_sdk_version, target_sdk_version, + max_sdk_version) assert manifest_utils.GetPackage(manifest) or manifest_package, \ 'Must set manifest package in GN or in AndroidManifest.xml' manifest_utils.AssertPackage(manifest, manifest_package) @@ -80,6 +81,8 @@ required=True, help='android:targetSdkVersion for merging.') parser.add_argument( + '--max-sdk-version', help='android:maxSdkVersion for merging.') + parser.add_argument( '--manifest-package', help='Package name of the merged AndroidManifest.xml.') args = parser.parse_args(argv) @@ -95,14 +98,24 @@ _MANIFEST_MERGER_MAIN_CLASS, '--out', output.name, + '--property', + 'MIN_SDK_VERSION=' + args.min_sdk_version, + '--property', + 'TARGET_SDK_VERSION=' + args.target_sdk_version, ] + if args.max_sdk_version: + cmd += [ + '--property', + 'MAX_SDK_VERSION=' + args.max_sdk_version, + ] + extras = build_utils.ParseGnList(args.extras) if extras: cmd += ['--libs', ':'.join(extras)] with _ProcessManifest(args.root_manifest, args.min_sdk_version, - args.target_sdk_version, + args.target_sdk_version, args.max_sdk_version, args.manifest_package) as tup: root_manifest, package = tup cmd += [ @@ -110,10 +123,6 @@ root_manifest, '--property', 'PACKAGE=' + package, - '--property', - 'MIN_SDK_VERSION=' + args.min_sdk_version, - '--property', - 'TARGET_SDK_VERSION=' + args.target_sdk_version, ] build_utils.CheckOutput(cmd, # https://issuetracker.google.com/issues/63514300:
diff --git a/build/android/gyp/util/manifest_utils.py b/build/android/gyp/util/manifest_utils.py index e036014..309230f 100644 --- a/build/android/gyp/util/manifest_utils.py +++ b/build/android/gyp/util/manifest_utils.py
@@ -66,13 +66,15 @@ def AssertUsesSdk(manifest_node, - min_sdk_version, + min_sdk_version=None, target_sdk_version=None, - max_sdk_version=None): + max_sdk_version=None, + fail_if_not_exist=False): """Asserts values of attributes of <uses-sdk> element. - Will only assert if both the passed value is not None and the value of - attribute exist. + Unless |fail_if_not_exist| is true, will only assert if both the passed value + is not None and the value of attribute exist. If |fail_if_not_exist| is true + will fail if passed value is not None but attribute does not exist. """ uses_sdk_node = manifest_node.find('./uses-sdk') if uses_sdk_node is None: @@ -81,6 +83,10 @@ target_sdk_version), ('max', max_sdk_version)): value = uses_sdk_node.get('{%s}%sSdkVersion' % (ANDROID_NAMESPACE, prefix)) + if fail_if_not_exist and not value and sdk_version: + assert False, ( + '%sSdkVersion in Android manifest does not exist but we expect %s' % + (prefix, sdk_version)) if not value or not sdk_version: continue assert value == sdk_version, (
diff --git a/build/android/gyp/util/resource_utils.py b/build/android/gyp/util/resource_utils.py index 633d600d..65061f5 100644 --- a/build/android/gyp/util/resource_utils.py +++ b/build/android/gyp/util/resource_utils.py
@@ -335,7 +335,8 @@ rjava_build_options, srcjar_out, custom_root_package_name=None, - grandparent_custom_package_name=None): + grandparent_custom_package_name=None, + extra_main_r_text_files=None): """Create all R.java files for a set of packages and R.txt files. Args: @@ -358,6 +359,7 @@ as the grandparent_custom_package_name. The format of this package name is identical to custom_root_package_name. (eg. for vr grandparent_custom_package_name would be "base") + extra_main_r_text_files: R.txt files to be added to the root R.java file. Raises: Exception if a package name appears several times in |extra_res_packages| """ @@ -378,12 +380,23 @@ all_resources = {} all_resources_by_type = collections.defaultdict(list) - for entry in _ParseTextSymbolsFile(main_r_txt_file, fix_package_ids=True): - all_resources[(entry.resource_type, entry.name)] = entry - all_resources_by_type[entry.resource_type].append(entry) - assert entry.resource_type in _ALL_RESOURCE_TYPES, ( - 'Unknown resource type: %s, add to _ALL_RESOURCE_TYPES!' % - entry.resource_type) + main_r_text_files = [main_r_txt_file] + if extra_main_r_text_files: + main_r_text_files.extend(extra_main_r_text_files) + for r_txt_file in main_r_text_files: + for entry in _ParseTextSymbolsFile(r_txt_file, fix_package_ids=True): + entry_key = (entry.resource_type, entry.name) + if entry_key in all_resources: + assert entry == all_resources[entry_key], ( + 'Input R.txt %s provided a duplicate resource with a different ' + 'entry value. Got %s, expected %s.' % (r_txt_file, entry, + all_resources[entry_key])) + else: + all_resources[entry_key] = entry + all_resources_by_type[entry.resource_type].append(entry) + assert entry.resource_type in _ALL_RESOURCE_TYPES, ( + 'Unknown resource type: %s, add to _ALL_RESOURCE_TYPES!' % + entry.resource_type) if custom_root_package_name: # Custom package name is available, thus use it for root_r_java_package.
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py index b4d8c71..40de1fe 100755 --- a/build/android/gyp/write_build_config.py +++ b/build/android/gyp/write_build_config.py
@@ -120,22 +120,17 @@ [`android_app_bundle_module`](#target_android_app_bundle_module) type. Whether or not this module is the base module for some bundle. -# Top-level `resources` dictionary: - -This dictionary only appears for a few target types that can contain or -relate to Android resources (e.g. `android_resources` or `android_apk`): - -* `resources['dependency_zips']`: +* `deps_info['dependency_zips']`: List of `deps_info['resources_zip']` entries for all `android_resources` dependencies for the current target. -* `resource['extra_package_names']`: +* `deps_info['extra_package_names']`: Always empty for `android_resources` types. Otherwise, the list of `deps_info['package_name']` entries for all `android_resources` dependencies for the current target. Computed automatically by `write_build_config.py`. -* `resources['extra_r_text_files']`: +* `deps_info['extra_r_text_files']`: Always empty for `android_resources` types. Otherwise, the list of `deps_info['r_text']` entries for all `android_resources` dependencies for the current target. Computed automatically. @@ -840,7 +835,6 @@ # android_resources options parser.add_option('--srcjar', help='Path to target\'s resources srcjar.') parser.add_option('--resources-zip', help='Path to target\'s resources zip.') - parser.add_option('--r-text', help='Path to target\'s R.txt file.') parser.add_option('--package-name', help='Java package name for these resources.') parser.add_option('--android-manifest', help='Path to android manifest.') @@ -929,6 +923,19 @@ parser.add_option('--incremental-install-json-path', help="Path to the target's generated incremental install " "json.") + parser.add_option( + '--tested-apk-config', + help='Path to the build config of the tested apk (for an instrumentation ' + 'test apk).') + parser.add_option( + '--proguard-enabled', + action='store_true', + help='Whether proguard is enabled for this apk or bundle module.') + parser.add_option( + '--proguard-configs', + help='GN-list of proguard flag files to use in final apk.') + parser.add_option( + '--proguard-mapping-path', help='Path to jar created by ProGuard step') # apk options that are static library specific parser.add_option( @@ -936,22 +943,13 @@ help='GN list of .build_configs of targets that use this target as a ' 'static library.') parser.add_option( - '--static-library-jar-path', - help='Equivalent to what normally would be the jar_path for the APK.') - parser.add_option( '--resource-ids-provider', help='Path to the .build_config for the APK that this static library ' 'target uses to generate stable resource IDs.') - parser.add_option('--tested-apk-config', - help='Path to the build config of the tested apk (for an instrumentation ' - 'test apk).') - parser.add_option('--proguard-enabled', action='store_true', - help='Whether proguard is enabled for this apk or bundle module.') - parser.add_option('--proguard-configs', - help='GN-list of proguard flag files to use in final apk.') - parser.add_option('--proguard-mapping-path', - help='Path to jar created by ProGuard step') + # options shared between android_resources and apk targets + parser.add_option('--r-text-path', help='Path to target\'s R.txt file.') + parser.add_option('--fail', help='GN-list of error message lines to fail with.') @@ -966,9 +964,6 @@ '--module-pathmap-path', help='Path to pathmap file for resource paths in a bundle module.') parser.add_option( - '--module-rtxt-path', - help='Path to R.txt file for resources in a bundle module.') - parser.add_option( '--base-whitelist-rtxt-path', help='Path to R.txt file for the base resources whitelist.') parser.add_option( @@ -1033,9 +1028,6 @@ if options.apk_proto_resources: raise Exception('--apk-proto-resources can only be used with ' '--type=android_app_bundle_module') - if options.module_rtxt_path: - raise Exception('--module-rxt-path can only be used with ' - '--type=android_app_bundle_module') if options.module_pathmap_path: raise Exception('--module-pathmap-path can only be used with ' '--type=android_app_bundle_module') @@ -1077,9 +1069,6 @@ if options.type != 'android_apk': raise Exception( '--static-library-dependent-configs only supports --type=android_apk') - if not options.static_library_jar_path: - raise Exception('Can\'t have --static-library-dependent-configs without ' - '--static-library-jar-path') options.static_library_dependent_configs = build_utils.ParseGnList( options.static_library_dependent_configs) static_library_dependent_configs_by_path = { @@ -1163,6 +1152,9 @@ else: gradle['dependent_java_projects'].append(c['path']) + if options.r_text_path: + deps_info['r_text_path'] = options.r_text_path + # TODO(tiborg): Remove creation of JNI info for type group and java_library # once we can generate the JNI registration based on APK / module targets as # opposed to groups and libraries. @@ -1177,9 +1169,6 @@ if options.apk_proto_resources: deps_info['proto_resources_path'] = options.apk_proto_resources - if options.module_rtxt_path: - deps_info['module_rtxt_path'] = options.module_rtxt_path - if options.module_pathmap_path: deps_info['module_pathmap_path'] = options.module_pathmap_path else: @@ -1256,8 +1245,6 @@ deps_info['package_name'] = manifest.GetPackageName() if options.package_name: deps_info['package_name'] = options.package_name - if options.r_text: - deps_info['r_text'] = options.r_text deps_info['resources_dirs'] = [] if options.resource_dirs: @@ -1304,7 +1291,6 @@ if options.type in ( 'android_resources', 'android_apk', 'junit_binary', 'resource_rewriter', 'dist_aar', 'android_app_bundle_module'): - config['resources'] = {} dependency_zips = [ c['resources_zip'] for c in all_resources_deps if c['resources_zip'] @@ -1316,32 +1302,33 @@ extra_package_names = [ c['package_name'] for c in all_resources_deps if 'package_name' in c] extra_r_text_files = [ - c['r_text'] for c in all_resources_deps if 'r_text' in c] + c['r_text_path'] for c in all_resources_deps if 'r_text_path' in c + ] # For feature modules, remove any resources that already exist in the base # module. if base_module_build_config: dependency_zips = [ c for c in dependency_zips - if c not in base_module_build_config['resources']['dependency_zips'] + if c not in base_module_build_config['deps_info']['dependency_zips'] ] extra_package_names = [ c for c in extra_package_names if c not in - base_module_build_config['resources']['extra_package_names'] + base_module_build_config['deps_info']['extra_package_names'] ] extra_r_text_files = [ c for c in extra_r_text_files if c not in - base_module_build_config['resources']['extra_r_text_files'] + base_module_build_config['deps_info']['extra_r_text_files'] ] - config['resources']['dependency_zips'] = dependency_zips - config['resources']['extra_package_names'] = extra_package_names - config['resources']['extra_r_text_files'] = extra_r_text_files + config['deps_info']['dependency_zips'] = dependency_zips + config['deps_info']['extra_package_names'] = extra_package_names + config['deps_info']['extra_r_text_files'] = extra_r_text_files if options.type == 'android_apk' and options.tested_apk_config: - config['resources']['arsc_package_name'] = ( + config['deps_info']['arsc_package_name'] = ( tested_apk_config['package_name']) if options.res_size_info: - config['resources']['size_info'] = options.res_size_info + config['deps_info']['res_size_info'] = options.res_size_info if is_apk_or_module_target: deps_dex_files = [c['dex_path'] for c in all_library_deps] @@ -1446,38 +1433,43 @@ assert len(base_module_configs) == 1, 'Must have exactly 1 base module!' deps_info['base_module_config'] = base_module_configs[0]['path'] + # Map configs to classpath entries that should be included in their final dex. + classpath_entries_by_owning_config = collections.defaultdict(list) + extra_main_r_text_files = [] if is_static_library_dex_provider_target: # Map classpath entries to configs that include them in their classpath. configs_by_classpath_entry = collections.defaultdict(list) static_lib_jar_paths = {} - for config_path, dep_config in ( - static_library_dependent_configs_by_path.iteritems()): + for config_path, dep_config in (sorted( + static_library_dependent_configs_by_path.iteritems())): # For bundles, only the jar path and jni sources of the base module # are relevant for proguard. Should be updated when bundle feature # modules support JNI. base_config = dep_config if dep_config['type'] == 'android_app_bundle': base_config = GetDepConfig(dep_config['base_module_config']) + extra_main_r_text_files.append(base_config['r_text_path']) static_lib_jar_paths[config_path] = base_config['jar_path'] all_configs.extend(dep_config['proguard_all_configs']) extra_proguard_classpath_jars.extend( dep_config['proguard_classpath_jars']) all_java_sources.extend(base_config['jni']['all_source']) + + # The srcjars containing the generated R.java files are excluded for APK + # targets the use static libraries, so we add them here to ensure the + # union of resource IDs are available in the static library APK. + for r_text in base_config['extra_r_text_files']: + if r_text not in extra_r_text_files: + extra_r_text_files.append(r_text) + for package in base_config['extra_package_names']: + if package not in extra_package_names: + extra_package_names.append(package) for cp_entry in dep_config['java_runtime_classpath']: - # The APK Java targets for the static library dependent targets will - # have some of the same classes (R.java) due to shared resource - # dependencies. To avoid Proguard failures due to duplicate classes, we - # merge the APK jars into the static library's jar_path as a - # preprocessing build step. - if cp_entry != base_config['jar_path']: - configs_by_classpath_entry[cp_entry].append(config_path) + configs_by_classpath_entry[cp_entry].append(config_path) for cp_entry in java_full_classpath: configs_by_classpath_entry[cp_entry].append(options.build_config) - # Map configs to classpath entries that should be included in their final - # dex. - classpath_entries_by_owning_config = collections.defaultdict(list) for cp_entry, candidate_configs in configs_by_classpath_entry.iteritems(): config_path = (candidate_configs[0] if len(candidate_configs) == 1 else options.build_config) @@ -1485,32 +1477,16 @@ java_full_classpath.append(cp_entry) java_full_classpath = sorted(set(java_full_classpath)) - deps_info['static_library_dependent_classpath_configs'] = { - path: sorted(set(classpath)) - for path, classpath in classpath_entries_by_owning_config.iteritems() - } - # resource_ids_provider's jar must go first to ensure the correct R.java - # IDs are used. - ordered_static_lib_jar_paths = [] - if options.resource_ids_provider: - assert (options.resource_ids_provider in options. - static_library_dependent_configs), ( - '--resource-ids-provider must be in ' - '--static-library-dependent-configs') - ordered_static_lib_jar_paths.append( - static_lib_jar_paths[options.resource_ids_provider]) - - ordered_static_lib_jar_paths.extend( - x for x in static_lib_jar_paths.itervalues() - if x not in ordered_static_lib_jar_paths) - ordered_static_lib_jar_paths.append(options.static_library_jar_path) - deps_info[ - 'static_library_dependent_apk_jars'] = ordered_static_lib_jar_paths - deps_info['static_library_proguard_mapping_output_paths'] = [ - d['proguard_mapping_path'] - for d in static_library_dependent_configs_by_path.itervalues() - ] + deps_info['static_library_proguard_mapping_output_paths'] = sorted([ + d['proguard_mapping_path'] + for d in static_library_dependent_configs_by_path.itervalues() + ]) + deps_info['static_library_dependent_classpath_configs'] = { + path: sorted(set(classpath)) + for path, classpath in classpath_entries_by_owning_config.iteritems() + } + deps_info['extra_main_r_text_files'] = sorted(extra_main_r_text_files) if is_apk_or_module_target or options.type in ('group', 'java_library', 'junit_binary'):
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py index f94f1a8..47933c2 100644 --- a/build/android/pylib/linker/test_case.py +++ b/build/android/pylib/linker/test_case.py
@@ -27,11 +27,7 @@ Host-driven tests have also been tried, but since they're really sub-classes of instrumentation tests, they didn't work well either. - To build and run the linker tests, do the following: - - ninja -C out/Debug chromium_linker_test_apk - out/Debug/bin/run_chromium_linker_test_apk - + To build and run, refer to android_linker_testing.md. """ # pylint: disable=R0201
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index a9273aa..abf6922 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -309,7 +309,7 @@ } if (defined(invoker.r_text)) { args += [ - "--r-text", + "--r-text-path", rebase_path(invoker.r_text, root_build_dir), ] } @@ -328,9 +328,9 @@ rebase_path(invoker.proto_resources_path, root_build_dir) args += [ "--apk-proto-resources=$_rebased_proto_resources" ] } - if (defined(invoker.module_rtxt_path)) { - _rebased_rtxt_path = rebase_path(invoker.module_rtxt_path, root_build_dir) - args += [ "--module-rtxt-path=$_rebased_rtxt_path" ] + if (defined(invoker.r_text_path)) { + _rebased_rtxt_path = rebase_path(invoker.r_text_path, root_build_dir) + args += [ "--r-text-path=$_rebased_rtxt_path" ] } if (defined(invoker.module_pathmap_path)) { _rebased_pathmap_path = @@ -456,11 +456,6 @@ args += [ "--proguard-configs=$_rebased_proguard_configs" ] } if (defined(invoker.static_library_dependent_targets)) { - assert(defined(invoker.static_library_jar_path)) - args += [ - "--static-library-jar-path", - rebase_path(invoker.static_library_jar_path, root_build_dir), - ] _dependent_configs = [] foreach(_target, invoker.static_library_dependent_targets) { _target_name = _target.name @@ -1754,6 +1749,10 @@ if (defined(invoker.manifest_package)) { args += [ "--manifest-package=${invoker.manifest_package}" ] } + + if (defined(invoker.max_sdk_version)) { + args += [ "--max-sdk-version=${invoker.max_sdk_version}" ] + } } } @@ -1860,9 +1859,9 @@ "--include-resources=@FileArg($_rebased_build_config:android:sdk_jars)", "--aapt-path", rebase_path(_android_aapt_path, root_build_dir), - "--dependencies-res-zips=@FileArg($_rebased_build_config:resources:dependency_zips)", - "--extra-res-packages=@FileArg($_rebased_build_config:resources:extra_package_names)", - "--extra-r-text-files=@FileArg($_rebased_build_config:resources:extra_r_text_files)", + "--dependencies-res-zips=@FileArg($_rebased_build_config:deps_info:dependency_zips)", + "--extra-res-packages=@FileArg($_rebased_build_config:deps_info:extra_package_names)", + "--extra-r-text-files=@FileArg($_rebased_build_config:deps_info:extra_r_text_files)", ] if (defined(invoker.android_manifest)) { @@ -2108,9 +2107,10 @@ "--include-resources=@FileArg($_rebased_build_config:android:sdk_jars)", "--aapt2-path", rebase_path(android_sdk_tools_bundle_aapt2, root_build_dir), - "--dependencies-res-zips=@FileArg($_rebased_build_config:resources:dependency_zips)", - "--extra-res-packages=@FileArg($_rebased_build_config:resources:extra_package_names)", - "--extra-r-text-files=@FileArg($_rebased_build_config:resources:extra_r_text_files)", + "--dependencies-res-zips=@FileArg($_rebased_build_config:deps_info:dependency_zips)", + "--extra-res-packages=@FileArg($_rebased_build_config:deps_info:extra_package_names)", + "--extra-r-text-files=@FileArg($_rebased_build_config:deps_info:extra_r_text_files)", + "--extra-main-r-text-files=@FileArg($_rebased_build_config:deps_info:extra_main_r_text_files)", "--min-sdk-version=${invoker.min_sdk_version}", "--target-sdk-version=${invoker.target_sdk_version}", ] @@ -2337,6 +2337,7 @@ args += [ "--use-resource-ids-path=$_rebased_ids_path" ] deps += [ _compile_res_dep ] } + if (defined(invoker.max_sdk_version)) { _max_sdk_version = invoker.max_sdk_version args += [ "--max-sdk-version=$_max_sdk_version" ] @@ -2389,7 +2390,7 @@ args += [ "--r-text-whitelist", rebase_path(invoker.shared_resources_whitelist, root_build_dir), - "--r-text", + "--r-text-path", rebase_path(invoker.r_text_out_path, root_build_dir), ] } @@ -2454,7 +2455,7 @@ args += [ "--jar-files=@FileArg($_rebased_build_config:deps_info:unprocessed_jar_path)", "--jar-files=@FileArg($_rebased_build_config:deps_info:javac_full_classpath)", - "--in-res-info-path=@FileArg($_rebased_build_config:resources:size_info)", + "--in-res-info-path=@FileArg($_rebased_build_config:deps_info:res_size_info)", "--assets=@FileArg($_rebased_build_config:assets)", "--uncompressed-assets=@FileArg($_rebased_build_config:uncompressed_assets)", ] @@ -3038,8 +3039,6 @@ # java_files is empty. If not # jar_path: Optional path to a prebuilt .jar file for this target. # Mutually exclusive with java_files and srcjar_deps. - # intermediate_jar_path: Optional path to the output .jar file. If used, - # final_jar_path must be created by another target. # final_jar_path: Optional path to the final output .jar file (after # processing). If not provided, the output will go under # $root_build_dir/lib.java/ @@ -3125,8 +3124,8 @@ # proto_resources_path: The path of an zip archive containing the APK's # resources compiled to the protocol buffer format (instead of regular # binary xml + resources.arsc). - # module_rtxt_path: The path of the R.txt file generated when compiling the - # resources for the bundle module. + # r_text_path: The path of the R.txt file generated when compiling the + # resources for this target. # module_pathmap_path: The path of the pathmap file generated when compiling # the resources for the bundle module, if path shortening is enabled. # base_whitelist_rtxt_path: The path of the R.txt file containing the @@ -3213,9 +3212,6 @@ # for the ijar as well, but this is only used for APK targets where # the ijar path isn't actually used. _build_config_jar_path = _final_jar_path - if (defined(invoker.intermediate_jar_path)) { - _final_jar_path = invoker.intermediate_jar_path - } _final_ijar_path = get_path_info(_final_jar_path, "dir") + "/" + get_path_info(_final_jar_path, "name") + ".interface.jar" @@ -3334,6 +3330,7 @@ "proguard_configs", "proguard_enabled", "proguard_mapping_path", + "r_text_path", "secondary_abi_loadable_modules", "type", ]) @@ -3370,7 +3367,6 @@ "base_module_target", "is_base_module", "module_pathmap_path", - "module_rtxt_path", "proto_resources_path", ]) } @@ -3385,9 +3381,6 @@ bypass_platform_checks = defined(invoker.bypass_platform_checks) && invoker.bypass_platform_checks - if (defined(invoker.intermediate_jar_path)) { - static_library_jar_path = invoker.intermediate_jar_path - } if (defined(_final_jar_path)) { jar_path = _build_config_jar_path ijar_path = _final_ijar_path
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index bcf645ca..4481c20 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -1757,8 +1757,8 @@ rebase_path(depfile, root_build_dir), "--output", rebase_path(invoker.output, root_build_dir), - "--dependencies-res-zips=@FileArg($_rebased_build_config:resources:dependency_zips)", - "--r-text-files=@FileArg($_rebased_build_config:resources:extra_r_text_files)", + "--dependencies-res-zips=@FileArg($_rebased_build_config:deps_info:dependency_zips)", + "--r-text-files=@FileArg($_rebased_build_config:deps_info:extra_r_text_files)", "--proguard-configs=@FileArg($_rebased_build_config:deps_info:proguard_all_configs)", ] if (_direct_deps_only) { @@ -2308,7 +2308,6 @@ _is_static_library_provider = defined(invoker.static_library_dependent_targets) && _proguard_enabled if (_is_static_library_provider) { - _static_library_apk_java_target_output = _jar_path _static_library_sync_dex_path = "$_gen_dir/static_library_synchronized_proguard.classes.dex.zip" _resource_ids_provider_deps = [] @@ -2344,7 +2343,11 @@ "$target_gen_dir/${_template_name}_manifest/AndroidManifest.xml" _merge_manifest_target = "${_template_name}__merge_manifests" merge_manifests(_merge_manifest_target) { - forward_variables_from(invoker, [ "manifest_package" ]) + forward_variables_from(invoker, + [ + "manifest_package", + "max_sdk_version", + ]) input_manifest = _android_root_manifest output_manifest = _android_manifest build_config = _build_config @@ -2457,13 +2460,21 @@ _android_sdk_dep, ] + # The static library uses the R.txt files generated by the + # static_library_dependent_targets when generating the final R.java file. + if (_is_static_library_provider) { + foreach(_dep, invoker.static_library_dependent_targets) { + deps += [ "${_dep.name}__compile_resources" ] + } + } + if (defined(invoker.apk_under_test)) { # Set the arsc package name to match the apk_under_test package name # So that test resources can references under_test resources via # @type/name syntax. r_java_root_package_name = "test" arsc_package_name = - "@FileArg($_rebased_build_config:resources:arsc_package_name)" + "@FileArg($_rebased_build_config:deps_info:arsc_package_name)" # Passing in the --emit-ids mapping will cause aapt2 to assign resources # IDs that do not conflict with those from apk_under_test. @@ -2572,7 +2583,20 @@ } } - _srcjar_deps += [ ":$_compile_resources_target" ] + # The static library will provide all R.java files, but we still need to + # have a dep on the compile_resources() target from the java_library_impl() + # target below. Using a group to rename the target avoids the naming + # restrictions described in crbug.com/908819. + if (_uses_static_library) { + group("${_compile_resources_target}__compile_only_dep") { + public_deps = [ + ":$_compile_resources_target", + ] + } + _deps += [ ":${_compile_resources_target}__compile_only_dep" ] + } else { + _srcjar_deps += [ ":$_compile_resources_target" ] + } if (_native_libs_deps != [] || _secondary_abi_native_libs_deps != []) { _enable_chromium_linker_tests = false @@ -2769,24 +2793,19 @@ } else { type = "android_apk" } + r_text_path = _compile_resources_rtxt_out main_target_name = _template_name supports_android = true requires_android = true min_sdk_version = _min_sdk_version deps = _deps - srcjar_deps = _srcjar_deps final_jar_path = _jar_path - if (_is_static_library_provider) { - intermediate_jar_path = "$_base_path.intermediate.jar" - final_jar_path = _static_library_apk_java_target_output - } dex_path = _lib_dex_path final_dex_path = _final_dex_path if (_is_bundle_module) { proto_resources_path = _proto_resources_path - module_rtxt_path = _compile_resources_rtxt_out if (_optimize_resources) { proto_resources_path = _optimized_proto_resources_path if (_short_resource_paths) { @@ -2855,38 +2874,6 @@ } } - if (_is_static_library_provider) { - _static_library_apk_java_target = "${_template_name}__combine_apk_jars" - - # Since some of the static_libary_dependent_targets may have overlapping - # resource dependencies, we can't include all jars created by the - # static_library_dependent_targets or else proguard will fail with - # duplicate class definitions. This step combines these jars into - # a single jar with duplicates ignored. - action_with_pydeps(_static_library_apk_java_target) { - script = "//build/android/gyp/zip.py" - deps = [ - ":$_build_config_target", - ":$_java_target", - ] - foreach(_dep, invoker.static_library_dependent_targets) { - _target_label = get_label_info(_dep.name, "label_no_toolchain") - deps += [ "${_target_label}__java" ] - } - inputs = [ - _build_config, - ] - outputs = [ - _static_library_apk_java_target_output, - ] - args = [ - "--input-zips=@FileArg($_rebased_build_config:deps_info:static_library_dependent_apk_jars)", - "--output", - rebase_path(_static_library_apk_java_target_output, root_build_dir), - ] - } - } - if (_proguard_enabled && _uses_static_library) { _final_dex_target_dep = "${invoker.static_library_provider}__dexsplitter" } else if (!(_is_bundle_module && _proguard_enabled)) { @@ -2909,9 +2896,6 @@ ":$_build_config_target", ":$_java_target", ] - if (_is_static_library_provider) { - deps += [ ":$_static_library_apk_java_target" ] - } if (_proguard_enabled) { forward_variables_from(invoker, [ "proguard_jar_path" ]) deps += _deps + [ ":$_compile_resources_target" ] @@ -2927,6 +2911,13 @@ } if (_is_static_library_provider) { + # The list of input jars is already recorded in the .build_config, but + # we need to explicitly add the java deps here to ensure they're + # available to be used as inputs to the dex step. + foreach(_dep, invoker.static_library_dependent_targets) { + _target_label = get_label_info(_dep.name, "label_no_toolchain") + deps += [ "${_target_label}__java" ] + } output = _static_library_sync_dex_path is_static_library = true } else { @@ -4506,6 +4497,11 @@ group("${target_name}__java") { deps = _sync_module_java_targets } + group("${target_name}__compile_resources") { + deps = [ + "${invoker.base_module_target}__compile_resources", + ] + } _build_config = "$target_gen_dir/${target_name}.build_config" _rebased_build_config = rebase_path(_build_config, root_build_dir) @@ -4712,7 +4708,8 @@ if (_enable_language_splits) { args += [ "--base-whitelist-rtxt-path=@FileArg(" + "${_rebased_base_module_build_config}:deps_info:base_whitelist_rtxt_path)", - "--base-module-rtxt-path=@FileArg(" + "${_rebased_base_module_build_config}:deps_info:module_rtxt_path)", + "--base-module-rtxt-path=@FileArg(" + + "${_rebased_base_module_build_config}:deps_info:r_text_path)", ] } @@ -4722,7 +4719,7 @@ "--uncompressed-assets=@FileArg(" + "$_rebased_build_config:uncompressed_assets)", "--rtxt-in-paths=@FileArg(" + - "$_rebased_build_config:deps_info:module_rtxt_path)", + "$_rebased_build_config:deps_info:r_text_path)", "--pathmap-in-paths=@FileArg(" + "$_rebased_build_config:deps_info:module_pathmap_path)", ]
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 28ca2a5..7afac95 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8908254478258311552 \ No newline at end of file +8908200315658417376 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 097742f5..be0f203 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8908254542434342448 \ No newline at end of file +8908199400534799360 \ No newline at end of file
diff --git a/buildtools/ensure_gn_version.py b/buildtools/ensure_gn_version.py index 9c01f58..acb1c1d 100755 --- a/buildtools/ensure_gn_version.py +++ b/buildtools/ensure_gn_version.py
@@ -18,6 +18,7 @@ from __future__ import print_function import argparse +import errno import io import os import re @@ -67,14 +68,22 @@ except subprocess.CalledProcessError as e: print('`%s` returned %d:\n%s' % (cmd_str, e.returncode, e.output)) return 1 + except OSError as e: + if e.errno != errno.ENOENT: + print('`%s` failed:\n%s' % (cmd_str, e)) + return 1 + + # The tool doesn't exist, so redownload it. + out = '' except Exception as e: - print('`%s` failed:\n%s' % (cmd_str, e.message)) + print('`%s` failed:\n%s' % (cmd_str, e)) return 1 - current_revision = re.findall(r'\((.*)\)', out)[0] - if desired_revision.startswith(current_revision): - # We're on the right version, so we're done. - return 0 + if out: + current_revision = re.findall(r'\((.*)\)', out)[0] + if desired_revision.startswith(current_revision): + # We're on the right version, so we're done. + return 0 print("`%s` returned '%s', which wasn't what we were expecting." % (cmd_str, out.strip())) @@ -96,7 +105,7 @@ zf = zipfile.ZipFile(io.BytesIO(zipdata)) zf.extract(member, os.path.join(BUILDTOOLS_DIR, dest_dir)) except Exception as e: - print('Failed to extract the binary:\n%s\n' % e.msg) + print('Failed to extract the binary:\n%s\n' % e) return 1 try:
diff --git a/cc/layers/mirror_layer_impl.cc b/cc/layers/mirror_layer_impl.cc index b36f293..7a916bf 100644 --- a/cc/layers/mirror_layer_impl.cc +++ b/cc/layers/mirror_layer_impl.cc
@@ -41,8 +41,8 @@ viz::SharedQuadState* shared_quad_state = render_pass->CreateAndAppendSharedQuadState(); PopulateScaledSharedQuadStateWithContentRects( - shared_quad_state, GetIdealContentsScale(), content_rect, content_rect, - contents_opaque); + shared_quad_state, mirrored_layer->GetIdealContentsScale(), content_rect, + content_rect, contents_opaque); AppendDebugBorderQuad(render_pass, content_rect, shared_quad_state, append_quads_data); @@ -75,7 +75,10 @@ } gfx::Rect MirrorLayerImpl::GetEnclosingRectInTargetSpace() const { - return GetScaledEnclosingRectInTargetSpace(GetIdealContentsScale()); + const LayerImpl* mirrored_layer = + layer_tree_impl()->LayerById(mirrored_layer_id_); + return GetScaledEnclosingRectInTargetSpace( + mirrored_layer->GetIdealContentsScale()); } const char* MirrorLayerImpl::LayerTypeAsString() const {
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc index 3e181f6..0ffd87e 100644 --- a/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -298,15 +298,9 @@ true) {} }; -SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) { +SkMatrix CreateMatrix(const SkSize& scale) { SkMatrix matrix; matrix.setScale(scale.width(), scale.height()); - - if (!is_decomposable) { - // Perspective is not decomposable, add it. - matrix[SkMatrix::kMPersp0] = 0.1f; - } - return matrix; } @@ -420,6 +414,28 @@ gfx::ColorSpace::TransferID::LINEAR); } + DrawImage CreateDrawImageInternal( + const PaintImage& paint_image, + const SkMatrix& matrix = SkMatrix::I(), + gfx::ColorSpace* color_space = nullptr, + SkFilterQuality filter_quality = kMedium_SkFilterQuality, + SkIRect* src_rect = nullptr, + size_t frame_index = PaintImage::kDefaultFrameIndex) { + SkIRect src_rectangle; + gfx::ColorSpace cs; + if (!src_rect) { + src_rectangle = + SkIRect::MakeWH(paint_image.width(), paint_image.height()); + src_rect = &src_rectangle; + } + if (!color_space) { + cs = DefaultColorSpace(); + color_space = &cs; + } + return DrawImage(paint_image, *src_rect, filter_quality, matrix, + frame_index, *color_space); + } + GPUImageDecodeTestMockContextProvider* context_provider() { return context_provider_.get(); } @@ -524,22 +540,16 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) { auto cache = CreateCache(); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); EXPECT_TRUE(result.task); - DrawImage another_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage another_draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f))); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -555,13 +565,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) { auto cache = CreateCache(); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -571,10 +576,8 @@ EXPECT_EQ(result.task->dependencies().size(), 1u); EXPECT_TRUE(result.task->dependencies()[0]); - DrawImage another_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage another_draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); @@ -597,21 +600,15 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) { auto cache = CreateCache(); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - bool is_decomposable = true; - SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable); - - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - kHigh_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f)); + DrawImage draw_image = CreateDrawImageInternal(image, matrix); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); EXPECT_TRUE(result.task); - DrawImage another_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage another_draw_image = CreateDrawImageInternal( + image, matrix, nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -626,25 +623,18 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); EXPECT_TRUE(first_result.task); PaintImage second_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage second_draw_image( - second_image, - SkIRect::MakeWH(second_image.width(), second_image.height()), quality, - CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal( + second_image, CreateMatrix(SkSize::Make(0.25f, 0.25f))); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -662,14 +652,10 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -680,20 +666,15 @@ cache->UnrefImage(first_draw_image); - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal(first_image); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); EXPECT_TRUE(second_result.task); EXPECT_TRUE(first_result.task.get() != second_result.task.get()); - DrawImage third_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage third_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( third_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(third_result.need_unref); @@ -708,33 +689,23 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); EXPECT_TRUE(first_result.task); - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal(first_image); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); EXPECT_TRUE(second_result.task); EXPECT_TRUE(first_result.task.get() != second_result.task.get()); - DrawImage third_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage third_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( third_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(third_result.need_unref); @@ -752,14 +723,10 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) { auto cache = CreateCache(); - bool is_decomposable = true; - SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable); - + SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f)); PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, matrix, nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -770,10 +737,8 @@ cache->UnrefImage(first_draw_image); - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal( + first_image, matrix, nullptr /* color_space */, kMedium_SkFilterQuality); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -787,14 +752,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -829,14 +789,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -871,14 +826,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -902,14 +852,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -945,14 +890,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -992,14 +932,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageUploadCanceledButDecodeRun) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1021,14 +956,9 @@ TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1051,14 +981,9 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1085,14 +1010,9 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreateLargePaintImageForSoftwareFallback(); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1119,16 +1039,11 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1155,14 +1070,10 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), + nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1171,10 +1082,8 @@ TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); TestTileTaskRunner::ProcessTask(result.task.get()); - DrawImage larger_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage larger_draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f))); ImageDecodeCache::TaskResult larger_result = cache->GetTaskForImageAndRef( larger_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(larger_result.need_unref); @@ -1210,13 +1119,10 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) { auto cache = CreateCache(); - bool is_decomposable = true; - SkMatrix matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable); - + SkMatrix matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f)); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal( + image, matrix, nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1225,10 +1131,7 @@ TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); TestTileTaskRunner::ProcessTask(result.task.get()); - DrawImage higher_quality_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage higher_quality_draw_image = CreateDrawImageInternal(image, matrix); ImageDecodeCache::TaskResult hq_result = cache->GetTaskForImageAndRef( higher_quality_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(hq_result.need_unref); @@ -1263,14 +1166,9 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(-0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(-0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1301,15 +1199,11 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreateLargePaintImageForSoftwareFallback( gfx::Size(GetLargeImageSize().width(), GetLargeImageSize().height() * 2)); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), + nullptr /* color_space */, kHigh_SkFilterQuality); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1342,17 +1236,11 @@ TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; const gfx::Size test_image_size = GetNormalImageSize(); - cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */); PaintImage image = CreatePaintImageInternal(test_image_size); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1386,16 +1274,11 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecodeMultipleTimes) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. @@ -1424,16 +1307,10 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDrawAtRasterDecodeMultipleTimes) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */); PaintImage image = CreateLargePaintImageForSoftwareFallback(); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. @@ -1463,14 +1340,9 @@ TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.f, 0.f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1489,15 +1361,12 @@ TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); DrawImage draw_image(image, SkIRect::MakeXYWH(image.width() + 1, image.height() + 1, image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), + kMedium_SkFilterQuality, + CreateMatrix(SkSize::Make(1.f, 1.f)), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = @@ -1517,14 +1386,11 @@ TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image( - image, SkIRect::MakeXYWH(0, 0, image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + SkIRect src_rect = SkIRect::MakeXYWH(0, 0, image.width(), image.height()); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(SkSize::Make(1.f, 1.f)), nullptr /* color_space */, + kMedium_SkFilterQuality, &src_rect); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1543,14 +1409,9 @@ TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); { ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); @@ -1604,15 +1465,10 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Create a downscaled image. PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -1624,10 +1480,8 @@ // Create a larger version of |first_image|, this should immediately free the // memory used by |first_image| for the smaller scale. - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f))); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -1652,15 +1506,10 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Create a downscaled image. PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -1676,10 +1525,7 @@ // Create a larger version of |first_image|, this should immediately free the // memory used by |first_image| for the smaller scale. - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal(first_image); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -1699,14 +1545,11 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) { auto cache = CreateCache(); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - bool is_decomposable = true; - SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable); + SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f)); // Create an image with kLow_FilterQuality. - DrawImage low_draw_image(image, - SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage low_draw_image = CreateDrawImageInternal( + image, matrix, nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult low_result = cache->GetTaskForImageAndRef( low_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(low_result.need_unref); @@ -1714,21 +1557,16 @@ // Get the same image at kMedium_SkFilterQuality. We can't re-use low, so we // should get a new task/ref. - DrawImage medium_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), - kMedium_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage medium_draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult medium_result = cache->GetTaskForImageAndRef( medium_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(medium_result.need_unref); EXPECT_TRUE(medium_result.task.get()); EXPECT_FALSE(low_result.task.get() == medium_result.task.get()); - // Get the same image at kHigh_FilterQuality. We should re-use medium. - DrawImage high_quality_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + // Get the same image at kHigh_SkFilterQuality. We should re-use medium. + DrawImage high_quality_draw_image = CreateDrawImageInternal( + image, matrix, nullptr /* color_space */, kHigh_SkFilterQuality); ImageDecodeCache::TaskResult high_quality_result = cache->GetTaskForImageAndRef(high_quality_draw_image, ImageDecodeCache::TracingInfo()); @@ -1749,15 +1587,9 @@ // cache entry creation doesn't cause a buffer overflow/crash. TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Create an image decode task and cache entry that does not need mips. PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1776,10 +1608,8 @@ viz::ContextProvider::ScopedContextLock context_lock(context_provider()); // Do an at-raster decode of the above image that *does* require mips. - DrawImage draw_image_mips( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image_mips = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f))); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image_mips)); cache->DrawWithImageFinished(draw_image_mips, decoded_draw_image); @@ -1787,13 +1617,10 @@ TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) { auto cache = CreateCache(); - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - bool is_decomposable = true; - SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f)); + DrawImage draw_image = CreateDrawImageInternal( + image, matrix, nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult result = cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image); @@ -1812,16 +1639,10 @@ TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) { SetCachedTexturesLimit(0); auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Add an image to the cache-> Due to normal working set, this should produce // a task and a ref. PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1865,19 +1686,13 @@ // Cache will fit one image. SetCachedTexturesLimit(1); auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); PaintImage image2 = CreatePaintImageInternal(GetNormalImageSize()); DrawImage draw_image2( - image2, SkIRect::MakeWH(image2.width(), image2.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + image2, SkIRect::MakeWH(image2.width(), image2.height()), + kMedium_SkFilterQuality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); // Add an image to the cache and un-ref it. @@ -1947,15 +1762,9 @@ TEST_P(GpuImageDecodeCacheTest, ClearCache) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - for (int i = 0; i < 10; ++i) { PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1977,15 +1786,9 @@ TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Create an image but keep it reffed so it can't be immediately freed. PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2012,36 +1815,27 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - gfx::ColorSpace color_space_a = gfx::ColorSpace::CreateSRGB(); gfx::ColorSpace color_space_b = gfx::ColorSpace::CreateXYZD50(); PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100)); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_a); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_a); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); EXPECT_TRUE(first_result.task); - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_b); + DrawImage second_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_b); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); EXPECT_TRUE(second_result.task); EXPECT_TRUE(first_result.task.get() != second_result.task.get()); - DrawImage third_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_a); + DrawImage third_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_a); ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( third_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(third_result.need_unref); @@ -2059,15 +1853,10 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImageNonSRGBColorSpace) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); - PaintImage image = CreateLargePaintImageForSoftwareFallback(); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2081,7 +1870,6 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { auto cache = CreateCache(); - std::vector<FrameMetadata> frames = { FrameMetadata(true, base::TimeDelta::FromMilliseconds(2)), FrameMetadata(true, base::TimeDelta::FromMilliseconds(3)), @@ -2103,12 +1891,10 @@ viz::ContextProvider::ScopedContextLock context_lock(context_provider()); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; + SkFilterQuality quality = kMedium_SkFilterQuality; DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - 1u, DefaultColorSpace()); + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), 1u, + DefaultColorSpace()); auto decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -2135,8 +1921,7 @@ ASSERT_LT(subset_height, test_image_size.height()); DrawImage subset_draw_image( image, SkIRect::MakeWH(subset_width, subset_height), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u, - DefaultColorSpace()); + CreateMatrix(SkSize::Make(1.0f, 1.0f)), 3u, DefaultColorSpace()); decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(subset_draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -2148,15 +1933,10 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Create a downscaled image. PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -2167,10 +1947,7 @@ // Create a larger version of |first_image|, this should immediately free // the memory used by |first_image| for the smaller scale. - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal(first_image); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -2203,15 +1980,10 @@ TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) { auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; const gfx::Size test_image_size = GetNormalImageSize(); PaintImage image = CreatePaintImageInternal(test_image_size); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); const size_t bytes_for_test_image = GetBytesNeededForSingleImage(test_image_size); @@ -2244,8 +2016,6 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) { auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; const gfx::Size test_image_size = GetNormalImageSize(); // Allow a single image by count. Use a high byte limit as we want to test the @@ -2255,10 +2025,7 @@ cache->SetWorkingSetLimitsForTesting( bytes_for_test_image * 100 /* max_bytes */, 1u /* max_items */); PaintImage image = CreatePaintImageInternal(test_image_size); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); // The image counts against our budget. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); @@ -2268,11 +2035,9 @@ EXPECT_TRUE(decoded_draw_image.is_budgeted()); // Try another image, it shouldn't be budgeted and should be at-raster. - DrawImage second_draw_image( - CreatePaintImageInternal(GetNormalImageSize()), - SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage second_paint_image = + CreatePaintImageInternal(GetNormalImageSize()); + DrawImage second_draw_image = CreateDrawImageInternal(second_paint_image); // Should be at raster. ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( @@ -2291,15 +2056,10 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) { auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; const gfx::Size test_image_size = GetNormalImageSize(); PaintImage image = CreatePaintImageInternal(test_image_size); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); const size_t bytes_for_test_image = GetBytesNeededForSingleImage(test_image_size); @@ -2317,11 +2077,8 @@ EXPECT_TRUE(decoded_draw_image.is_budgeted()); // Try another image, it shouldn't be budgeted and should be at-raster. - DrawImage second_draw_image( - CreatePaintImageInternal(test_image_size), - SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage test_paint_image = CreatePaintImageInternal(test_image_size); + DrawImage second_draw_image = CreateDrawImageInternal(test_paint_image); // Should be at raster. ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( @@ -2341,15 +2098,11 @@ TEST_P(GpuImageDecodeCacheTest, ColorConversionDuringDecodeForLargeImageNonSRGBColorSpace) { auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); PaintImage image = CreateLargePaintImageForSoftwareFallback(); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2396,15 +2149,11 @@ TEST_P(GpuImageDecodeCacheTest, ColorConversionDuringUploadForSmallImageNonSRGBColorSpace) { auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65(); PaintImage image = CreatePaintImageInternal(gfx::Size(11, 12)); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2449,14 +2198,9 @@ return; } auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage image = CreateBitmapImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2474,14 +2218,9 @@ return; } auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage image = CreateBitmapImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); auto result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2498,14 +2237,9 @@ return; } auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage image = CreateBitmapImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); auto result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2526,14 +2260,10 @@ const bool should_cache_sw_image = cache->SupportsColorSpaceConversion() && !use_transfer_cache_; - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreateBitmapImageInternal(GetLargeImageSize()); - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, gfx::ColorSpace::CreateDisplayP3D65()); + gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65(); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2545,9 +2275,8 @@ auto sw_image = cache->GetSWImageDecodeForTesting(draw_image); ASSERT_EQ(!!sw_image, should_cache_sw_image); if (should_cache_sw_image) { - EXPECT_TRUE(SkColorSpace::Equals( - sw_image->colorSpace(), - gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace().get())); + EXPECT_TRUE(SkColorSpace::Equals(sw_image->colorSpace(), + color_space.ToSkColorSpace().get())); } } @@ -2557,14 +2286,10 @@ return; } auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage image = CreateBitmapImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2575,8 +2300,6 @@ TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; viz::ContextProvider::ScopedContextLock context_lock(context_provider()); const PaintImage::Id paint_image_id = PaintImage::GetNextId(); @@ -2586,10 +2309,8 @@ for (int i = 0; i < 10; ++i) { PaintImage image = CreatePaintImageInternal( GetNormalImageSize(), SkColorSpace::MakeSRGB(), paint_image_id); - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2625,8 +2346,6 @@ return; } auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kMedium_SkFilterQuality; viz::ContextProvider::ScopedContextLock context_lock(context_provider()); const SkISize full_size = SkISize::Make(100, 100); @@ -2643,10 +2362,8 @@ .set_paint_image_generator(generator) .TakePaintImage(); - DrawImage draw_image( - paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), - quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal( + paint_image, CreateMatrix(SkSize::Make(0.5, 0.5))); DecodedDrawImage decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); const int expected_width = @@ -2672,8 +2389,6 @@ return; } auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kNone_SkFilterQuality; viz::ContextProvider::ScopedContextLock context_lock(context_provider()); SkISize full_size = SkISize::Make(100, 100); @@ -2690,10 +2405,9 @@ .set_paint_image_generator(generator) .TakePaintImage(); - DrawImage draw_image( - paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), - quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(paint_image, CreateMatrix(SkSize::Make(0.5, 0.5)), + nullptr /* color_space */, kNone_SkFilterQuality); DecodedDrawImage decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -2716,12 +2430,10 @@ SkSize scale, gfx::ColorSpace color_space, bool should_have_mips) { auto cache = CreateCache(); - bool is_decomposable = true; PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - filter_quality, CreateMatrix(scale, is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(scale), &color_space, filter_quality); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2777,9 +2489,6 @@ // Medium filter quality == mips decode_and_check_mips(kMedium_SkFilterQuality, SkSize::Make(0.6f, 0.6f), DefaultColorSpace(), true); - // High filter quality == mips - decode_and_check_mips(kHigh_SkFilterQuality, SkSize::Make(0.6f, 0.6f), - DefaultColorSpace(), true); // Color conversion preserves mips decode_and_check_mips(kMedium_SkFilterQuality, SkSize::Make(0.6f, 0.6f), gfx::ColorSpace::CreateXYZD50(), true); @@ -2787,17 +2496,12 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) { auto cache = CreateCache(); - bool is_decomposable = true; - auto filter_quality = kMedium_SkFilterQuality; PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); // Create an image with no scaling. It will not have mips. { - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2839,10 +2543,8 @@ // no new task (re-uses the existing image), but mips should have been // added. { - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, - CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2882,9 +2584,6 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { auto cache = CreateCache(); - bool is_decomposable = true; - auto filter_quality = kMedium_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); struct Decode { @@ -2895,10 +2594,7 @@ // Create an image with no scaling. It will not have mips. { - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2933,10 +2629,8 @@ // Second decode with mips. { - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, - CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -3019,15 +2713,14 @@ return; } auto cache = CreateCache(); - bool is_decomposable = true; SkFilterQuality filter_quality = kMedium_SkFilterQuality; SkSize requires_decode_at_original_scale = SkSize::Make(0.8f, 0.8f); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, - CreateMatrix(requires_decode_at_original_scale, is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + filter_quality, + CreateMatrix(requires_decode_at_original_scale), + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -3068,15 +2761,13 @@ return; } auto cache = CreateCache(); - bool is_decomposable = true; SkFilterQuality filter_quality = kMedium_SkFilterQuality; SkSize less_than_half_scale = SkSize::Make(0.45f, 0.45f); gfx::Size image_size = GetNormalImageSize(); PaintImage image = CreatePaintImageInternal(image_size); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - filter_quality, - CreateMatrix(less_than_half_scale, is_decomposable), + filter_quality, CreateMatrix(less_than_half_scale), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -3122,17 +2813,10 @@ // We will create a texture that's at the maximum size the GPU says it can // support for uploads. auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage almost_too_large_image = CreatePaintImageInternal(gfx::Size(max_texture_size_, max_texture_size_)); - DrawImage draw_image(almost_too_large_image, - SkIRect::MakeWH(almost_too_large_image.width(), - almost_too_large_image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(almost_too_large_image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -3227,12 +2911,10 @@ ASSERT_TRUE(target_color_space.IsValid()); const PaintImage image = CreatePaintImageForDecodeAcceleration(image_size, image_color_space); - const bool is_decomposable = true; const SkFilterQuality quality = kHigh_SkFilterQuality; - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), - PaintImage::kDefaultFrameIndex, target_color_space); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)), + PaintImage::kDefaultFrameIndex, target_color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -3264,12 +2946,10 @@ ASSERT_TRUE(target_color_space.IsValid()); const PaintImage image = CreatePaintImageForDecodeAcceleration(image_size, image_color_space); - const bool is_decomposable = true; const SkFilterQuality quality = kHigh_SkFilterQuality; - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), - PaintImage::kDefaultFrameIndex, target_color_space); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)), + PaintImage::kDefaultFrameIndex, target_color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -3305,12 +2985,10 @@ ASSERT_TRUE(target_color_space.IsValid()); const PaintImage image = CreatePaintImageForDecodeAcceleration(image_size, image_color_space); - const bool is_decomposable = true; const SkFilterQuality quality = kHigh_SkFilterQuality; - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), - PaintImage::kDefaultFrameIndex, target_color_space); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)), + PaintImage::kDefaultFrameIndex, target_color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -3347,11 +3025,9 @@ ASSERT_TRUE(target_color_space.IsValid()); const PaintImage image = CreatePaintImageForDecodeAcceleration(image_size, image_color_space); - const bool is_decomposable = true; const SkFilterQuality quality = kHigh_SkFilterQuality; DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), PaintImage::kDefaultFrameIndex, target_color_space); ImageDecodeCache::TaskResult result = cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image); @@ -3373,11 +3049,9 @@ ASSERT_TRUE(target_color_space.IsValid()); const PaintImage image = CreatePaintImageForDecodeAcceleration(image_size, image_color_space); - const bool is_decomposable = true; const SkFilterQuality quality = kHigh_SkFilterQuality; DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), + quality, CreateMatrix(SkSize::Make(0.5f, 0.5f)), PaintImage::kDefaultFrameIndex, target_color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -3402,11 +3076,9 @@ const PaintImage image = CreatePaintImageForDecodeAcceleration( image_size, image_color_space, false /* is_eligible_for_accelerated_decoding */); - const bool is_decomposable = true; const SkFilterQuality quality = kHigh_SkFilterQuality; DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), PaintImage::kDefaultFrameIndex, target_color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -3431,11 +3103,9 @@ ASSERT_TRUE(target_color_space.IsValid()); const PaintImage image = CreatePaintImageForDecodeAcceleration(image_size, image_color_space); - const bool is_decomposable = true; const SkFilterQuality quality = kHigh_SkFilterQuality; DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), PaintImage::kDefaultFrameIndex, target_color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -3459,12 +3129,10 @@ ASSERT_TRUE(target_color_space.IsValid()); const PaintImage image = CreatePaintImageForDecodeAcceleration(image_size, image_color_space); - const bool is_decomposable = true; const SkFilterQuality quality = kHigh_SkFilterQuality; - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), - PaintImage::kDefaultFrameIndex, target_color_space); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)), + PaintImage::kDefaultFrameIndex, target_color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref);
diff --git a/cc/trees/layer_tree_host_pixeltest_mirror.cc b/cc/trees/layer_tree_host_pixeltest_mirror.cc index cbd67e31..02ab6cc 100644 --- a/cc/trees/layer_tree_host_pixeltest_mirror.cc +++ b/cc/trees/layer_tree_host_pixeltest_mirror.cc
@@ -17,14 +17,14 @@ class LayerTreeHostMirrorPixelTest : public LayerTreePixelTest, - public ::testing::WithParamInterface<LayerTreeTest::RendererType> { + public ::testing::WithParamInterface< + ::testing::tuple<LayerTreeTest::RendererType, bool>> { protected: - RendererType renderer_type() { return GetParam(); } + RendererType renderer_type() { return std::get<0>(GetParam()); } void InitializeSettings(LayerTreeSettings* settings) override { - // MirrorLayer is only used by UI compositor; so, match its behavior by - // setting layer_transforms_should_scale_layer_contents to false. - settings->layer_transforms_should_scale_layer_contents = false; + settings->layer_transforms_should_scale_layer_contents = + std::get<1>(GetParam()); } }; @@ -37,9 +37,11 @@ #endif }; -INSTANTIATE_TEST_SUITE_P(, - LayerTreeHostMirrorPixelTest, - ::testing::ValuesIn(kRendererTypes)); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostMirrorPixelTest, + ::testing::Combine(::testing::ValuesIn(kRendererTypes), + /*layer_transforms_scale_content=*/testing::Bool())); // Verifies that a mirror layer with a scale mirrors another layer correctly. TEST_P(LayerTreeHostMirrorPixelTest, MirrorLayer) {
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index 109bcf5..38c7314 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -424,7 +424,6 @@ "//content/app/resources", "//content/public/common:service_names", "//crypto", - "//headless:headless_shell_browser_lib", "//net:net_resources", "//ppapi/buildflags", "//services/service_manager/embedder", @@ -445,19 +444,16 @@ "/DELAYLOAD:dbghelp.dll", "/DELAYLOAD:dhcpcsvc.dll", "/DELAYLOAD:dwmapi.dll", - "/DELAYLOAD:dwrite.dll", "/DELAYLOAD:dxgi.dll", "/DELAYLOAD:esent.dll", "/DELAYLOAD:gdi32.dll", "/DELAYLOAD:hid.dll", "/DELAYLOAD:imagehlp.dll", "/DELAYLOAD:imm32.dll", - "/DELAYLOAD:iphlpapi.dll", "/DELAYLOAD:msi.dll", "/DELAYLOAD:netapi32.dll", "/DELAYLOAD:ole32.dll", "/DELAYLOAD:oleacc.dll", - "/DELAYLOAD:oleaut32.dll", "/DELAYLOAD:ncrypt.dll", "/DELAYLOAD:propsys.dll", "/DELAYLOAD:psapi.dll", @@ -474,16 +470,29 @@ "/DELAYLOAD:wevtapi.dll", "/DELAYLOAD:winhttp.dll", "/DELAYLOAD:wininet.dll", - "/DELAYLOAD:winmm.dll", "/DELAYLOAD:winspool.drv", "/DELAYLOAD:wintrust.dll", "/DELAYLOAD:winusb.dll", - "/DELAYLOAD:ws2_32.dll", "/DELAYLOAD:wsock32.dll", "/DELAYLOAD:wtsapi32.dll", "/DELAYLOAD:api-ms-win-core-winrt-string-l1-1-0.dll", ] + if (is_multi_dll_chrome) { + ldflags += [ + "/DELAYLOAD:dwrite.dll", + "/DELAYLOAD:iphlpapi.dll", + "/DELAYLOAD:oleaut32.dll", + "/DELAYLOAD:winmm.dll", + "/DELAYLOAD:ws2_32.dll", + ] + } else { + ldflags += [ + "/DELAYLOAD:dxva2.dll", + "/DELAYLOAD:rstrtmgr.dll", + ] + } + if (!is_component_build) { # This is a large module that can't do incremental linking in some # cases. @@ -498,7 +507,10 @@ if (is_multi_dll_chrome) { defines += [ "CHROME_MULTIPLE_DLL_BROWSER" ] - deps += [ "//content/public/app:browser" ] + deps += [ + "//content/public/app:browser", + "//headless:headless_shell_browser_lib", + ] assert_no_deps = [ # The browser DLL may not depend on blink or v8. "//third_party/blink/public:blink", @@ -512,6 +524,7 @@ deps += [ ":child_dependencies", "//content/public/app:both", + "//headless:headless_shell_lib", ] }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 88b6bd2..c357fcd 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -569,7 +569,7 @@ "//chrome/browser/ntp_snippets/ntp_snippets_metrics.h", "//chrome/browser/profiles/profile_metrics.h", "//chrome/browser/translate/android/translate_utils.h", - "//chrome/browser/ui/android/bluetooth_scanning_prompt_android.h", + "//chrome/browser/ui/android/device_dialog/bluetooth_scanning_prompt_android.h", "//chrome/browser/ui/android/infobars/infobar_android.h", ] } @@ -852,7 +852,6 @@ "//third_party/android_deps:com_android_support_preference_v7_java", "//third_party/android_deps:com_android_support_recyclerview_v7_java", "//third_party/android_deps:com_android_support_support_annotations_java", - "//third_party/android_deps:com_google_ar_core_java", "//third_party/android_deps:com_google_protobuf_protobuf_lite_java", "//third_party/android_sdk:android_test_base_java", "//third_party/android_sdk:android_test_mock_java", @@ -1039,6 +1038,7 @@ "//third_party/gvr-android-sdk:gvr_common_java", ":chrome_test_util_java", "//components/module_installer/android:module_installer_java", + "//components/module_installer/android:module_installer_stub_java", "//components/module_installer/android:module_installer_test_java", ] @@ -1756,6 +1756,8 @@ android_manifest_dep = ":trichrome_library_android_manifest" if (trichrome_synchronized_proguard) { + shared_resources_whitelist_target = "//android_webview:system_webview_apk" + shared_resources_whitelist_locales = locales static_library_dependent_targets = [ { name = "//android_webview:trichrome_webview_apk" @@ -1777,6 +1779,8 @@ android_manifest_dep = ":trichrome_library_android_manifest" if (trichrome_synchronized_proguard) { + shared_resources_whitelist_target = "//android_webview:system_webview_apk" + shared_resources_whitelist_locales = locales static_library_dependent_targets = [ { name = "//android_webview:trichrome_webview_for_bundle_apk" @@ -2424,8 +2428,6 @@ "java/src/org/chromium/chrome/browser/AppHooks.java", "java/src/org/chromium/chrome/browser/ApplicationLifetime.java", "java/src/org/chromium/chrome/browser/BackgroundSyncLauncher.java", - "java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java", - "java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java", "java/src/org/chromium/chrome/browser/ChromeBackupAgent.java", "java/src/org/chromium/chrome/browser/ChromeBackupWatcher.java", "java/src/org/chromium/chrome/browser/ChromeFeatureList.java", @@ -2438,7 +2440,6 @@ "java/src/org/chromium/chrome/browser/SearchGeolocationDisclosureTabHelper.java", "java/src/org/chromium/chrome/browser/ServiceTabLauncher.java", "java/src/org/chromium/chrome/browser/ShortcutHelper.java", - "java/src/org/chromium/chrome/browser/UsbChooserDialog.java", "java/src/org/chromium/chrome/browser/WarmupManager.java", "java/src/org/chromium/chrome/browser/WebContentsFactory.java", "java/src/org/chromium/chrome/browser/accessibility/FontSizePrefs.java", @@ -2495,6 +2496,9 @@ "java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java", "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleMetrics.java", "java/src/org/chromium/chrome/browser/database/SQLiteCursor.java", + "java/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialog.java", + "java/src/org/chromium/chrome/browser/device_dialog/BluetoothScanningPermissionDialog.java", + "java/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialog.java", "java/src/org/chromium/chrome/browser/document/DocumentWebContentsDelegate.java", "java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerServiceFactory.java", "java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerTabUtils.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 251b6cd..7047ad6 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -14,8 +14,6 @@ "java/src/org/chromium/chrome/browser/ApplicationLifetime.java", "java/src/org/chromium/chrome/browser/AssistStatusHandler.java", "java/src/org/chromium/chrome/browser/BackgroundSyncLauncher.java", - "java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java", - "java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java", "java/src/org/chromium/chrome/browser/BrowserRestartActivity.java", "java/src/org/chromium/chrome/browser/ChromeActionModeCallback.java", "java/src/org/chromium/chrome/browser/ChromeActivity.java", @@ -40,15 +38,12 @@ "java/src/org/chromium/chrome/browser/DelayedScreenLockIntentHandler.java", "java/src/org/chromium/chrome/browser/DevToolsServer.java", "java/src/org/chromium/chrome/browser/DeviceConditions.java", - "java/src/org/chromium/chrome/browser/DeviceItemAdapter.java", - "java/src/org/chromium/chrome/browser/DeviceItemRow.java", "java/src/org/chromium/chrome/browser/FileProviderHelper.java", "java/src/org/chromium/chrome/browser/GlobalDiscardableReferencePool.java", "java/src/org/chromium/chrome/browser/InsetObserverView.java", "java/src/org/chromium/chrome/browser/IntentHandler.java", "java/src/org/chromium/chrome/browser/IntentHeadersRecorder.java", "java/src/org/chromium/chrome/browser/IntentHelper.java", - "java/src/org/chromium/chrome/browser/ItemChooserDialog.java", "java/src/org/chromium/chrome/browser/KeyboardShortcuts.java", "java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java", "java/src/org/chromium/chrome/browser/LauncherShortcutActivity.java", @@ -66,7 +61,6 @@ "java/src/org/chromium/chrome/browser/SynchronousInitializationActivity.java", "java/src/org/chromium/chrome/browser/TabThemeColorProvider.java", "java/src/org/chromium/chrome/browser/ThemeColorProvider.java", - "java/src/org/chromium/chrome/browser/UsbChooserDialog.java", "java/src/org/chromium/chrome/browser/WarmupManager.java", "java/src/org/chromium/chrome/browser/WebContentsFactory.java", "java/src/org/chromium/chrome/browser/WindowDelegate.java", @@ -447,6 +441,12 @@ "java/src/org/chromium/chrome/browser/dependency_injection/ChromeCommonQualifiers.java", "java/src/org/chromium/chrome/browser/dependency_injection/ModuleFactoryOverrides.java", "java/src/org/chromium/chrome/browser/device/DeviceClassManager.java", + "java/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialog.java", + "java/src/org/chromium/chrome/browser/device_dialog/BluetoothScanningPermissionDialog.java", + "java/src/org/chromium/chrome/browser/device_dialog/DeviceItemAdapter.java", + "java/src/org/chromium/chrome/browser/device_dialog/DeviceItemRow.java", + "java/src/org/chromium/chrome/browser/device_dialog/ItemChooserDialog.java", + "java/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialog.java", "java/src/org/chromium/chrome/browser/directactions/ChromeDirectActionIds.java", "java/src/org/chromium/chrome/browser/directactions/MenuDirectActionHandler.java", "java/src/org/chromium/chrome/browser/directactions/DirectActionCoordinator.java",
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni index d16003f7..a92cc41 100644 --- a/chrome/android/chrome_public_apk_tmpl.gni +++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -226,9 +226,6 @@ if (_target_type == "android_app_bundle_module") { deps += [ "//components/module_installer/android:module_installer_impl_java" ] - } else if (_target_type == "instrumentation_test_apk") { - deps += - [ "//components/module_installer/android:module_installer_test_java" ] } else { deps += [ "//components/module_installer/android:module_installer_stub_java" ]
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index d02d0795..5b9f9cc 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -9,8 +9,6 @@ "javatests/src/org/chromium/chrome/browser/ActivityTabProviderTest.java", "javatests/src/org/chromium/chrome/browser/AudioTest.java", "javatests/src/org/chromium/chrome/browser/BackgroundSyncLauncherTest.java", - "javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java", - "javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java", "javatests/src/org/chromium/chrome/browser/ChromeActivityTest.java", "javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java", "javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java", @@ -21,7 +19,6 @@ "javatests/src/org/chromium/chrome/browser/HTTPSTabsOpenedFromExternalAppTest.java", "javatests/src/org/chromium/chrome/browser/InstalledAppTest.java", "javatests/src/org/chromium/chrome/browser/IntentHandlerTest.java", - "javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java", "javatests/src/org/chromium/chrome/browser/JavaScriptEvalChromeTest.java", "javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java", "javatests/src/org/chromium/chrome/browser/MockSafeBrowsingApiHandler.java", @@ -47,7 +44,6 @@ "javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java", "javatests/src/org/chromium/chrome/browser/TabsTest.java", "javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java", - "javatests/src/org/chromium/chrome/browser/UsbChooserDialogTest.java", "javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java", "javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java", "javatests/src/org/chromium/chrome/browser/accessibility/FontSizePrefsTest.java", @@ -79,6 +75,10 @@ "javatests/src/org/chromium/chrome/browser/compositor/layouts/MockLayoutHost.java", "javatests/src/org/chromium/chrome/browser/compositor/layouts/MockResourcesForLayout.java", "javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java", + "javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialogTest.java", + "javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothScanningPermissionDialogTest.java", + "javatests/src/org/chromium/chrome/browser/device_dialog/ItemChooserDialogTest.java", + "javatests/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialogTest.java", "javatests/src/org/chromium/chrome/browser/directactions/CloseTabDirectActionHandlerTest.java", "javatests/src/org/chromium/chrome/browser/directactions/DirectActionAvailabilityTest.java", "javatests/src/org/chromium/chrome/browser/directactions/DirectActionTestRule.java",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn index a3f2d624..919d5a7 100644 --- a/chrome/android/features/autofill_assistant/BUILD.gn +++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -72,7 +72,7 @@ "java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTagsForTesting.java", "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java", "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java", - "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactoryImpl.java", + "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java", "java/src/org/chromium/chrome/browser/autofill_assistant/BottomSheetUtils.java", "java/src/org/chromium/chrome/browser/autofill_assistant/EditDistance.java", "java/src/org/chromium/chrome/browser/autofill_assistant/FeedbackContext.java", @@ -162,6 +162,7 @@ "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestUiTest.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java", + "javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java", "javatests/src/org/chromium/chrome/browser/autofill_assistant/EditDistanceTest.java", ]
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java index ac3e29a..3237350 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
@@ -257,7 +257,8 @@ /** Request showing the Assistant bottom bar view and expand the sheet. */ public void showAndExpand() { - BottomSheetUtils.showContentAndExpand(mBottomSheetController, mContent); + BottomSheetUtils.showContentAndExpand( + mBottomSheetController, mContent, /* animate= */ true); } /** Hide the Assistant bottom bar view. */
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java index f9d27be..776880d6 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.autofill_assistant; import android.content.Context; +import android.support.annotation.Nullable; import android.text.SpannableString; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; @@ -13,8 +14,15 @@ import android.widget.TextView; import org.chromium.base.Callback; +import org.chromium.base.VisibleForTesting; import org.chromium.chrome.autofill_assistant.R; +import org.chromium.chrome.browser.autofill_assistant.metrics.OnBoarding; +import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayCoordinator; +import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayModel; +import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayState; import org.chromium.chrome.browser.customtabs.CustomTabActivity; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; import org.chromium.ui.text.NoUnderlineClickableSpan; import org.chromium.ui.text.SpanApplier; @@ -27,24 +35,112 @@ class AssistantOnboardingCoordinator { private static final String SMALL_ONBOARDING_EXPERIMENT_ID = "4257013"; + private final String mExperimentIds; + private final Context mContext; + private final BottomSheetController mController; + @Nullable + private final Tab mTab; + + @Nullable + private AssistantOverlayCoordinator mOverlayCoordinator; + + @Nullable + private AssistantBottomSheetContent mContent; + private boolean mAnimate = true; + + AssistantOnboardingCoordinator(String experimentIds, Context context, + BottomSheetController controller, @Nullable Tab tab) { + mExperimentIds = experimentIds; + mContext = context; + mController = controller; + mTab = tab; + } + /** - * Set the content of {@code bottomSheetContent} to be the Autofill Assistant onboarding. {@code - * callback} will be called with true or false when the user accepts or cancels the onboarding - * (respectively). + * Shows onboarding and provides the result to the given callback. + * + * <p>The {@code callback} will be called with true or false when the user accepts or cancels + * the onboarding (respectively). + * + * <p>Note that the bottom sheet will be hidden after the callback returns. Call, from the + * callback, {@link #hide} to hide it earlier or {@link #transferControls} to take ownership of + * it and possibly keep it past the end of the callback. */ - static void setOnboardingContent(String experimentIds, Context context, - AssistantBottomSheetContent bottomSheetContent, Callback<Boolean> callback) { - ScrollView initView = (ScrollView) LayoutInflater.from(context).inflate( + void show(Callback<Boolean> callback) { + AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_SHOWN); + + if (mTab != null) { + // If there's a tab, cover it with an overlay. + AssistantOverlayModel overlayModel = new AssistantOverlayModel(); + mOverlayCoordinator = new AssistantOverlayCoordinator(mTab.getActivity(), overlayModel); + overlayModel.set(AssistantOverlayModel.STATE, AssistantOverlayState.FULL); + } + mContent = new AssistantBottomSheetContent(mContext); + initContent(callback); + BottomSheetUtils.showContentAndExpand(mController, mContent, mAnimate); + } + + /** + * Transfers ownership of the controls to the caller, returns the overlay coordinator, if one + * was created. + * + * <p>This call is only useful when called from inside a callback provided to {@link #show}, as + * before that there are no controls and after that the coordinator automatically hides them. + * This call allows callbacks to reuse the controls setup for onboarding and provide a smooth + * transition. + */ + @Nullable + AssistantOverlayCoordinator transferControls() { + assert isInProgress(); + + AssistantOverlayCoordinator coordinator = mOverlayCoordinator; + mOverlayCoordinator = null; + mContent = null; + return coordinator; + } + + /** Hides the UI, if one is shown. */ + void hide() { + if (mOverlayCoordinator != null) { + mOverlayCoordinator.destroy(); + mOverlayCoordinator = null; + } + + if (mContent != null) { + mController.hideContent(mContent, /* animate= */ mAnimate); + mContent = null; + } + } + + /** + * Returns {@code true} between the time {@link #show} is called and the time + * the callback has returned. + */ + boolean isInProgress() { + return mContent != null; + } + + /** Don't animate the bottom sheet expansion. */ + @VisibleForTesting + void disableAnimationForTesting() { + mAnimate = false; + } + + /** + * Set the content of the bottom sheet to be the Autofill Assistant onboarding. + */ + private void initContent(Callback<Boolean> callback) { + ScrollView initView = (ScrollView) LayoutInflater.from(mContext).inflate( R.layout.autofill_assistant_onboarding, /* root= */ null); TextView termsTextView = initView.findViewById(R.id.google_terms_message); - String termsString = context.getApplicationContext().getString( + String termsString = mContext.getApplicationContext().getString( R.string.autofill_assistant_google_terms_description); - NoUnderlineClickableSpan termsSpan = new NoUnderlineClickableSpan(context.getResources(), + NoUnderlineClickableSpan termsSpan = new NoUnderlineClickableSpan(mContext.getResources(), (widget) - -> CustomTabActivity.showInfoPage(context.getApplicationContext(), - context.getApplicationContext().getString( + -> CustomTabActivity.showInfoPage(mContext.getApplicationContext(), + mContext.getApplicationContext().getString( R.string.autofill_assistant_google_terms_url))); SpannableString spannableMessage = SpanApplier.applySpans( termsString, new SpanApplier.SpanInfo("<link>", "</link>", termsSpan)); @@ -59,24 +155,27 @@ initView.findViewById(R.id.button_init_not_ok) .setOnClickListener(unusedView -> onClicked(false, callback)); initView.setContentDescription( - context.getString(R.string.autofill_assistant_first_run_accessibility)); + mContext.getString(R.string.autofill_assistant_first_run_accessibility)); // Hide views that should not be displayed when showing the small onboarding. - if (Arrays.asList(experimentIds.split(",")).contains(SMALL_ONBOARDING_EXPERIMENT_ID)) { + if (Arrays.asList(mExperimentIds.split(",")).contains(SMALL_ONBOARDING_EXPERIMENT_ID)) { hide(initView, R.id.onboarding_image); hide(initView, R.id.onboarding_subtitle); hide(initView, R.id.onboarding_separator); } - bottomSheetContent.setContent(initView, initView); + mContent.setContent(initView, initView); } private static void hide(View root, int resId) { root.findViewById(resId).setVisibility(View.GONE); } - private static void onClicked(boolean accept, Callback<Boolean> callback) { + private void onClicked(boolean accept, Callback<Boolean> callback) { AutofillAssistantPreferencesUtil.setInitialPreferences(accept); + AutofillAssistantMetrics.recordOnBoarding( + accept ? OnBoarding.OB_ACCEPTED : OnBoarding.OB_CANCELLED); callback.onResult(accept); + hide(); } }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactoryImpl.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactoryImpl.java deleted file mode 100644 index 2eba277e1..0000000 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactoryImpl.java +++ /dev/null
@@ -1,89 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.autofill_assistant; - -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import org.chromium.base.annotations.UsedByReflection; -import org.chromium.chrome.browser.ChromeActivity; -import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason; -import org.chromium.chrome.browser.autofill_assistant.metrics.OnBoarding; -import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayCoordinator; -import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayModel; -import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayState; -import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; -import org.chromium.content_public.browser.WebContents; - -import java.util.Map; - -/** - * Factory implementation to create AutofillAssistantClient as - * as AutofillAssistantModuleEntry to serve as interface between - * base module and assistant DFM. - */ -@UsedByReflection("AutofillAssistantModuleEntryProvider.java") -public class AutofillAssistantModuleEntryFactoryImpl - implements AutofillAssistantModuleEntryFactory { - @Override - public AutofillAssistantModuleEntry createEntry( - @NonNull ChromeActivity activity, @NonNull WebContents webContents) { - return new AutofillAssistantModuleEntryImpl(activity, webContents); - } - - private static class AutofillAssistantModuleEntryImpl implements AutofillAssistantModuleEntry { - private final ChromeActivity mActivity; - private final WebContents mWebContents; - - private AutofillAssistantModuleEntryImpl(ChromeActivity activity, WebContents webContents) { - mActivity = activity; - mWebContents = webContents; - } - - @Override - public void start(boolean skipOnboarding, String initialUrl, Map<String, String> parameters, - String experimentIds, Bundle intentExtras) { - if (skipOnboarding) { - AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_NOT_SHOWN); - - start(initialUrl, parameters, experimentIds, intentExtras, null); - } else { - AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_SHOWN); - - BottomSheetController controller = mActivity.getBottomSheetController(); - AssistantBottomSheetContent content = new AssistantBottomSheetContent(mActivity); - AssistantOverlayModel overlayModel = new AssistantOverlayModel(); - AssistantOverlayCoordinator overlayCoordinator = - new AssistantOverlayCoordinator(mActivity, overlayModel); - overlayModel.set(AssistantOverlayModel.STATE, AssistantOverlayState.FULL); - AssistantOnboardingCoordinator.setOnboardingContent( - experimentIds, mActivity, content, accepted -> { - if (accepted) { - AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_ACCEPTED); - - // We transfer the ownership of the overlay to #start() and the - // bottom sheet content will be replaced. - start(initialUrl, parameters, experimentIds, intentExtras, - overlayCoordinator); - } else { - AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_CANCELLED); - overlayCoordinator.destroy(); - controller.hideContent(content, /* animate= */ true); - AutofillAssistantMetrics.recordDropOut(DropOutReason.DECLINED); - } - }); - - BottomSheetUtils.showContentAndExpand(controller, content); - } - } - - private void start(String initialUrl, Map<String, String> parameters, String experimentIds, - Bundle intentExtras, @Nullable AssistantOverlayCoordinator overlayCoordinator) { - AutofillAssistantClient client = AutofillAssistantClient.fromWebContents(mWebContents); - client.start(initialUrl, parameters, experimentIds, intentExtras, overlayCoordinator); - } - } -} \ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java new file mode 100644 index 0000000..f415368 --- /dev/null +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java
@@ -0,0 +1,46 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.autofill_assistant; + +import android.os.Bundle; +import android.support.annotation.NonNull; + +import org.chromium.base.annotations.UsedByReflection; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.autofill_assistant.metrics.OnBoarding; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.content_public.browser.WebContents; + +import java.util.Map; + +/** + * Implementation of {@link AutofillAssistantModuleEntry}. This is the entry point into the + * assistant DFM. + */ +@UsedByReflection("AutofillAssistantModuleEntryProvider.java") +public class AutofillAssistantModuleEntryImpl implements AutofillAssistantModuleEntry { + @Override + public void start(@NonNull Tab tab, @NonNull WebContents webContents, boolean skipOnboarding, + String initialUrl, Map<String, String> parameters, String experimentIds, + Bundle intentExtras) { + if (skipOnboarding) { + AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_NOT_SHOWN); + AutofillAssistantClient.fromWebContents(tab.getWebContents()) + .start(initialUrl, parameters, experimentIds, intentExtras, null); + return; + } + + ChromeActivity activity = tab.getActivity(); + AssistantOnboardingCoordinator onboardingCoordinator = new AssistantOnboardingCoordinator( + experimentIds, activity, activity.getBottomSheetController(), tab); + onboardingCoordinator.show(accepted -> { + if (!accepted) return; + + AutofillAssistantClient.fromWebContents(tab.getWebContents()) + .start(initialUrl, parameters, experimentIds, intentExtras, + onboardingCoordinator.transferControls()); + }); + } +}
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/BottomSheetUtils.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/BottomSheetUtils.java index 3c2d6dd..695c588 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/BottomSheetUtils.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/BottomSheetUtils.java
@@ -13,8 +13,8 @@ class BottomSheetUtils { /** Request {@code controller} to show {@code content} and expand the sheet when it is shown. */ - static void showContentAndExpand( - BottomSheetController controller, AssistantBottomSheetContent content) { + static void showContentAndExpand(BottomSheetController controller, + AssistantBottomSheetContent content, boolean animate) { // Add an observer that makes sure the bottom sheet content is always shown, even in the // peek state. BottomSheet bottomSheet = controller.getBottomSheet(); @@ -62,7 +62,7 @@ }); // Show the content. - if (controller.requestShowContent(content, /* animate= */ true)) { + if (controller.requestShowContent(content, animate)) { controller.expandSheet(); } else { // If the content is not directly shown, add an observer that will expand the sheet when
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderViewBinder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderViewBinder.java index 3165381..f593c37 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderViewBinder.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderViewBinder.java
@@ -137,7 +137,7 @@ view.mProfileIconMenu.setOnMenuItemClickListener(item -> { int itemId = item.getItemId(); if (itemId == R.id.settings) { - PreferencesLauncher.launchSettingsPage( + PreferencesLauncher.launchSettingsPageCompat( view.mHeader.getContext(), AutofillAssistantPreferences.class); return true; } else if (itemId == R.id.send_feedback) {
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java new file mode 100644 index 0000000..330d373e --- /dev/null +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java
@@ -0,0 +1,153 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.autofill_assistant; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.assertThat; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.verify; + +import android.support.annotation.IdRes; +import android.support.test.filters.MediumTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import org.chromium.base.Callback; +import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.autofill_assistant.R; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayCoordinator; +import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayModel; +import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayState; +import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Tests {@link AssistantOnboardingCoordinator} + */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE) +public class AssistantOnboardingCoordinatorTest { + @Rule + public CustomTabActivityTestRule mCustomTabActivityTestRule = new CustomTabActivityTestRule(); + + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Mock + Callback<Boolean> mCallback; + + private ChromeActivity mActivity; + private BottomSheetController mBottomSheetController; + private Tab mTab; + + @Before + public void setUp() throws Exception { + AutofillAssistantUiTestUtil.startOnBlankPage(mCustomTabActivityTestRule); + mActivity = mCustomTabActivityTestRule.getActivity(); + mBottomSheetController = ThreadUtils.runOnUiThreadBlocking( + () -> AutofillAssistantUiTestUtil.createBottomSheetController(mActivity)); + mTab = mActivity.getTabModelSelector().getCurrentTab(); + } + + private AssistantOnboardingCoordinator createCoordinator(Tab tab) { + AssistantOnboardingCoordinator coordinator = + new AssistantOnboardingCoordinator("", mActivity, mBottomSheetController, mTab); + coordinator.disableAnimationForTesting(); + return coordinator; + } + + @Test + @MediumTest + public void testAcceptOnboarding() throws Exception { + testOnboarding(R.id.button_init_ok, true); + } + + @Test + @MediumTest + public void testRejectOnboarding() throws Exception { + testOnboarding(R.id.button_init_not_ok, false); + } + + private void testOnboarding(@IdRes int buttonToClick, boolean expectAccept) throws Exception { + AutofillAssistantPreferencesUtil.setInitialPreferences(!expectAccept); + + AssistantOnboardingCoordinator coordinator = createCoordinator(mTab); + + ThreadUtils.runOnUiThreadBlocking(() -> coordinator.show(mCallback)); + + assertTrue(ThreadUtils.runOnUiThreadBlocking(coordinator::isInProgress)); + onView(is(mActivity.getScrim())).check(matches(isDisplayed())); + onView(withId(buttonToClick)).perform(click()); + + verify(mCallback).onResult(expectAccept); + + assertFalse(ThreadUtils.runOnUiThreadBlocking(coordinator::isInProgress)); + assertEquals(expectAccept, AutofillAssistantPreferencesUtil.isAutofillOnboardingAccepted()); + } + + @Test + @MediumTest + public void testOnboardingWithNoTabs() throws Exception { + AssistantOnboardingCoordinator coordinator = createCoordinator(/* tab= */ null); + + ThreadUtils.runOnUiThreadBlocking(() -> coordinator.show(mCallback)); + + onView(withId(R.id.button_init_ok)).perform(click()); + + verify(mCallback).onResult(true); + } + + @Test + @MediumTest + public void testTransfertControls() throws Exception { + AssistantOnboardingCoordinator coordinator = createCoordinator(mTab); + + List<AssistantOverlayCoordinator> capturedOverlays = + Collections.synchronizedList(new ArrayList<>()); + ThreadUtils.runOnUiThreadBlocking(() -> coordinator.show((accepted) -> { + capturedOverlays.add(coordinator.transferControls()); + })); + + onView(withId(R.id.button_init_ok)).perform(click()); + assertFalse(ThreadUtils.runOnUiThreadBlocking(coordinator::isInProgress)); + + // An overlay was captured, and it is still shown. + onView(is(mActivity.getScrim())).check(matches(isDisplayed())); + assertEquals(1, capturedOverlays.size()); + AssistantOverlayCoordinator overlay = capturedOverlays.get(0); + assertNotNull(overlay); + assertEquals( + AssistantOverlayState.FULL, overlay.getModel().get(AssistantOverlayModel.STATE)); + + // The bottom sheet content is still the assistant one. + assertThat(mBottomSheetController.getBottomSheet().getCurrentSheetContent(), + instanceOf(AssistantBottomSheetContent.class)); + } +}
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java index 540c4b6..fd52f00 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTest.java
@@ -12,15 +12,11 @@ import static org.hamcrest.Matchers.not; import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.verify; -import android.content.Context; import android.content.Intent; -import android.support.annotation.IdRes; import android.support.test.InstrumentationRegistry; import android.support.test.filters.MediumTest; import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; @@ -55,8 +51,6 @@ import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.firstrun.FirstRunStatus; -import org.chromium.chrome.browser.snackbar.BottomContainer; -import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.test.util.TestThreadUtils; @@ -111,53 +105,10 @@ return mCustomTabActivityTestRule.getActivity(); } - // Copied from {@link ChromeActivity#initializeBottomSheet}. protected BottomSheetController initializeBottomSheet() { - CustomTabActivity activity = getActivity(); - ViewGroup coordinator = activity.findViewById(R.id.coordinator); - LayoutInflater.from(activity).inflate(R.layout.bottom_sheet, coordinator); - BottomSheet bottomSheet = coordinator.findViewById(R.id.bottom_sheet); - bottomSheet.init(coordinator, activity); - - ((BottomContainer) activity.findViewById(R.id.bottom_container)) - .setBottomSheet(bottomSheet); - - return new BottomSheetController(activity, activity.getLifecycleDispatcher(), - activity.getActivityTabProvider(), activity.getScrim(), bottomSheet, - activity.getCompositorViewHolder().getLayoutManager().getOverlayPanelManager(), - /* suppressSheetForContextualSearch= */ false); + return AutofillAssistantUiTestUtil.createBottomSheetController(getActivity()); } - @Test - @MediumTest - public void testAcceptOnboarding() throws Exception { - testOnboarding(true, R.id.button_init_ok); - } - - @Test - @MediumTest - public void testDeclineOnboarding() throws Exception { - testOnboarding(false, R.id.button_init_not_ok); - } - - private void testOnboarding(boolean expectedAccepted, @IdRes int buttonToClick) - throws Exception { - mCustomTabActivityTestRule.startCustomTabActivityWithIntent(createMinimalCustomTabIntent()); - Context context = getActivity(); - AssistantBottomSheetContent bottomSheetContent = new AssistantBottomSheetContent(context); - - AssistantOnboardingCoordinator.setOnboardingContent( - /* experimentIds= */ "", context, bottomSheetContent, accepted -> { - Assert.assertEquals(expectedAccepted, accepted); - mRunnableMock.run(); - }); - - View button = bottomSheetContent.getContentView().findViewById(buttonToClick); - Assert.assertNotNull(button); - - TestThreadUtils.runOnUiThreadBlocking(button::performClick); - TestThreadUtils.runOnUiThreadBlocking(() -> verify(mRunnableMock).run()); - } // TODO(crbug.com/806868): Add more UI details test and check, like payment request UI, // highlight chips and so on.
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java index 45d18ee..7ec9b81 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
@@ -9,6 +9,7 @@ import android.support.design.widget.CoordinatorLayout; import android.support.test.InstrumentationRegistry; import android.view.Gravity; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; @@ -18,11 +19,16 @@ import org.chromium.base.Callback; import org.chromium.base.ThreadUtils; +import org.chromium.chrome.autofill_assistant.R; +import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.customtabs.CustomTabActivity; import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; import org.chromium.chrome.browser.image_fetcher.ImageFetcher; import org.chromium.chrome.browser.image_fetcher.ImageFetcherConfig; +import org.chromium.chrome.browser.snackbar.BottomContainer; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; import jp.tomorrowkey.android.gifplayer.BaseGifImage; @@ -79,6 +85,29 @@ } /** + * Creates a {@link BottomSheetController} for the activity, suitable for testing. + * + * <p>The returned controller is different from the one returned by {@link + * ChromeActivity#getBottomSheetController}. + */ + static BottomSheetController createBottomSheetController(ChromeActivity activity) { + // Copied from {@link ChromeActivity#initializeBottomSheet}. + + ViewGroup coordinator = activity.findViewById(R.id.coordinator); + LayoutInflater.from(activity).inflate(R.layout.bottom_sheet, coordinator); + BottomSheet bottomSheet = coordinator.findViewById(R.id.bottom_sheet); + bottomSheet.init(coordinator, activity); + + ((BottomContainer) activity.findViewById(R.id.bottom_container)) + .setBottomSheet(bottomSheet); + + return new BottomSheetController(activity, activity.getLifecycleDispatcher(), + activity.getActivityTabProvider(), activity.getScrim(), bottomSheet, + activity.getCompositorViewHolder().getLayoutManager().getOverlayPanelManager(), + /* suppressSheetForContextualSearch= */ false); + } + + /** * Attaches the specified view to the Chrome coordinator. Must be called from the UI thread. */ public static void attachToCoordinator(CustomTabActivity activity, View view) {
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java index 8a92e67..8b0df5d 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -11,12 +11,15 @@ import android.support.annotation.Nullable; import org.chromium.base.BuildInfo; +import org.chromium.base.Callback; +import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity.ActivityType; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason; import org.chromium.chrome.browser.directactions.DirectActionHandler; import org.chromium.chrome.browser.metrics.UmaSessionStats; +import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.chrome.browser.widget.ScrimView; @@ -104,18 +107,20 @@ // Have an "attempted starts" baseline for the drop out histogram. AutofillAssistantMetrics.recordDropOut(DropOutReason.AA_START); - AutofillAssistantModuleEntryProvider.getModuleEntry(activity, (moduleEntry) -> { - if (moduleEntry == null) { - AutofillAssistantMetrics.recordDropOut(DropOutReason.DFM_INSTALL_FAILED); - return; - } + waitForTabWithWebContents(activity, tab -> { + AutofillAssistantModuleEntryProvider.getModuleEntry(activity, tab, (moduleEntry) -> { + if (moduleEntry == null) { + AutofillAssistantMetrics.recordDropOut(DropOutReason.DFM_INSTALL_FAILED); + return; + } - Bundle bundleExtras = activity.getInitialIntent().getExtras(); - Map<String, String> parameters = extractParameters(bundleExtras); - parameters.remove(PARAMETER_ENABLED); - String initialUrl = activity.getInitialIntent().getDataString(); - moduleEntry.start(canStartWithoutOnboarding, initialUrl, parameters, experimentIds, - activity.getInitialIntent().getExtras()); + Bundle bundleExtras = activity.getInitialIntent().getExtras(); + Map<String, String> parameters = extractParameters(bundleExtras); + parameters.remove(PARAMETER_ENABLED); + String initialUrl = activity.getInitialIntent().getDataString(); + moduleEntry.start(tab, tab.getWebContents(), canStartWithoutOnboarding, initialUrl, + parameters, experimentIds, activity.getInitialIntent().getExtras()); + }); }); } @@ -227,4 +232,25 @@ } return false; } + + /** Provides the callback with a tab that has a web contents, waits if necessary. */ + private static void waitForTabWithWebContents(ChromeActivity activity, Callback<Tab> callback) { + if (activity.getActivityTab() != null + && activity.getActivityTab().getWebContents() != null) { + callback.onResult(activity.getActivityTab()); + return; + } + + // The tab is not yet available. We need to register as listener and wait for it. + activity.getActivityTabProvider().addObserverAndTrigger( + new ActivityTabProvider.HintlessActivityTabObserver() { + @Override + public void onActivityTabChanged(Tab tab) { + if (tab == null) return; + activity.getActivityTabProvider().removeObserver(this); + assert tab.getWebContents() != null; + callback.onResult(tab); + } + }); + } }
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java index 44b802e2..590dc7b 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java
@@ -5,19 +5,28 @@ package org.chromium.chrome.browser.autofill_assistant; import android.os.Bundle; +import android.support.annotation.NonNull; + +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.components.module_installer.ModuleInterface; +import org.chromium.content_public.browser.WebContents; import java.util.Map; /** - * Interface for base module to start the autofill assistant - * experience in dynamic feature module. + * Interface between base module and assistant DFM. */ +@ModuleInterface(module = "autofill_assistant", + impl = "org.chromium.chrome.browser.autofill_assistant.AutofillAssistantModuleEntryImpl") interface AutofillAssistantModuleEntry { /** - * Launches Autofill Assistant on the current web contents, expecting autostart. If {@code - * skipOnboarding} is false, the onboarding will first be shown and the Autofill Assistant will - * start only if the user accepts to proceed. + * Starts Autofill Assistant on the current tab of the given chrome activity. + * + * <p>When started this way, Autofill Assistant appears immediately in the bottom sheet, expects + * a single autostartable script for the tab's current URL, runs that script until the end and + * disappears. */ - void start(boolean skipOnboarding, String initialUrl, Map<String, String> parameters, - String experimentIds, Bundle intentExtras); -} \ No newline at end of file + void start(@NonNull Tab tab, @NonNull WebContents webContents, boolean skipOnboarding, + String initialUrl, Map<String, String> parameters, String experimentIds, + Bundle intentExtras); +}
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactory.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactory.java deleted file mode 100644 index 214ce76..0000000 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactory.java +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.autofill_assistant; - -import android.support.annotation.NonNull; - -import org.chromium.chrome.browser.ChromeActivity; -import org.chromium.components.module_installer.ModuleInterface; -import org.chromium.content_public.browser.WebContents; - -/** - * Interface to create AutofillAssistantModuleEntry as inferface - * between base module and assistant DFM. - */ -@ModuleInterface(module = "autofill_assistant", - impl = "org.chromium.chrome.browser.autofill_assistant." - + "AutofillAssistantModuleEntryFactoryImpl") -interface AutofillAssistantModuleEntryFactory { - AutofillAssistantModuleEntry createEntry( - @NonNull ChromeActivity activity, @NonNull WebContents webContents); -} \ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java index 517615c9..991c3f0 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java
@@ -4,13 +4,14 @@ package org.chromium.chrome.browser.autofill_assistant; +import android.content.Context; +import android.support.annotation.Nullable; + import org.chromium.base.BundleUtils; import org.chromium.base.Callback; import org.chromium.base.Log; import org.chromium.base.SysUtils; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; -import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.modules.ModuleInstallUi; import org.chromium.chrome.browser.tab.Tab; import org.chromium.components.module_installer.ModuleInstaller; @@ -22,21 +23,26 @@ public class AutofillAssistantModuleEntryProvider { private static final String TAG = "AutofillAssistant"; - /** - * Returns AutofillAssistantModuleEntry by using it as argument to the - * passed in callback, or null if DFM loading fails. - */ + /* Returns the AA module entry, if it is already installed. */ + @Nullable + /* package */ static AutofillAssistantModuleEntry getModuleEntryIfInstalled(Context context) { + // Required to access resources in DFM using this activity as context. + ModuleInstaller.getInstance().initActivity(context); + if (AutofillAssistantModule.isInstalled()) { + return AutofillAssistantModule.getImpl(); + } + return null; + } + + /** Gets the AA module entry, installing it if necessary. */ /* package */ static void getModuleEntry( - ChromeActivity activity, Callback<AutofillAssistantModuleEntry> callback) { - getTab(activity, tab -> { - // Required to access resources in DFM using this activity as context. - ModuleInstaller.initActivity(activity); - if (AutofillAssistantModule.isInstalled()) { - callback.onResult(createEntry(tab)); - return; - } - loadDynamicModuleWithUi(activity, tab, callback); - }); + Context context, Tab tab, Callback<AutofillAssistantModuleEntry> callback) { + AutofillAssistantModuleEntry entry = getModuleEntryIfInstalled(context); + if (entry != null) { + callback.onResult(entry); + return; + } + loadDynamicModuleWithUi(context, tab, callback); } /** @@ -70,13 +76,8 @@ AutofillAssistantModule.installDeferred(); } - private static AutofillAssistantModuleEntry createEntry(Tab tab) { - AutofillAssistantModuleEntryFactory factory = AutofillAssistantModule.getImpl(); - return factory.createEntry(tab.getActivity(), tab.getWebContents()); - } - private static void loadDynamicModuleWithUi( - ChromeActivity activity, Tab tab, Callback<AutofillAssistantModuleEntry> callback) { + Context activity, Tab tab, Callback<AutofillAssistantModuleEntry> callback) { ModuleInstallUi ui = new ModuleInstallUi(tab, R.string.autofill_assistant_module_title, new ModuleInstallUi.FailureUiListener() { @Override @@ -91,37 +92,17 @@ }); // Shows toast informing user about install start. ui.showInstallStartUi(); - ModuleInstaller.install("autofill_assistant", (success) -> { + ModuleInstaller.getInstance().install("autofill_assistant", (success) -> { if (success) { // Clean install of chrome will have issues here without initializing // after installation of DFM. - ModuleInstaller.initActivity(activity); + ModuleInstaller.getInstance().initActivity(activity); // Don't show success UI from DFM, transition to autobot UI directly. - callback.onResult(createEntry(tab)); + callback.onResult(AutofillAssistantModule.getImpl()); return; } // Show inforbar to ask user if they want to retry or cancel. ui.showInstallFailureUi(); }); } - - private static void getTab(ChromeActivity activity, Callback<Tab> callback) { - if (activity.getActivityTab() != null - && activity.getActivityTab().getWebContents() != null) { - callback.onResult(activity.getActivityTab()); - return; - } - - // The tab is not yet available. We need to register as listener and wait for it. - activity.getActivityTabProvider().addObserverAndTrigger( - new ActivityTabProvider.HintlessActivityTabObserver() { - @Override - public void onActivityTabChanged(Tab tab) { - if (tab == null) return; - activity.getActivityTabProvider().removeObserver(this); - assert tab.getWebContents() != null; - callback.onResult(tab); - } - }); - } }
diff --git a/chrome/android/features/autofill_assistant/public/java_sources.gni b/chrome/android/features/autofill_assistant/public/java_sources.gni index 1d79e4d..357f8ea 100644 --- a/chrome/android/features/autofill_assistant/public/java_sources.gni +++ b/chrome/android/features/autofill_assistant/public/java_sources.gni
@@ -6,7 +6,6 @@ "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java", "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java", "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java", - "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactory.java", "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java", "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java", ]
diff --git a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_address_info.xml b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_address_info.xml index a06df67..5ea4e1a 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_address_info.xml +++ b/chrome/android/features/keyboard_accessory/internal/java/res/layout/keyboard_accessory_sheet_tab_address_info.xml
@@ -15,37 +15,12 @@ android:layout_marginBottom="@dimen/keyboard_accessory_sheet_bottom_margin" android:orientation="vertical"> - <LinearLayout + <org.chromium.ui.widget.ChipView + android:id="@+id/name_full" android:gravity="center_vertical|start" - android:fillViewport="true" - android:layout_height="@dimen/keyboard_accessory_suggestion_height" - android:layout_width="match_parent" - android:orientation="horizontal"> - - <org.chromium.ui.widget.ChipView - android:id="@+id/name_first" - android:gravity="center_vertical|start" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - style="@style/InputChip" /> - - <org.chromium.ui.widget.ChipView - android:id="@+id/name_middle" - android:gravity="center_vertical|start" - android:layout_marginStart="@dimen/keyboard_accessory_sheet_padding" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - style="@style/InputChip" /> - - <org.chromium.ui.widget.ChipView - android:id="@+id/name_last" - android:gravity="center_vertical|start" - android:layout_marginStart="@dimen/keyboard_accessory_sheet_padding" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - style="@style/InputChip" /> - - </LinearLayout> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/InputChip" /> <org.chromium.ui.widget.ChipView android:id="@+id/company_name" @@ -78,6 +53,7 @@ <org.chromium.ui.widget.ChipView android:id="@+id/address_home_state" android:gravity="center_vertical|start" + android:layout_marginEnd="@dimen/keyboard_accessory_sheet_padding" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/InputChip" /> @@ -85,7 +61,7 @@ <org.chromium.ui.widget.ChipView android:id="@+id/address_home_city" android:gravity="center_vertical|start" - android:layout_marginStart="@dimen/keyboard_accessory_sheet_padding" + android:layout_marginEnd="@dimen/keyboard_accessory_sheet_padding" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/InputChip" /> @@ -93,7 +69,6 @@ <org.chromium.ui.widget.ChipView android:id="@+id/address_home_zip" android:gravity="center_vertical|start" - android:layout_marginStart="@dimen/keyboard_accessory_sheet_padding" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/InputChip" />
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryInfoView.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryInfoView.java index 272ae28..1460611 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryInfoView.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryInfoView.java
@@ -18,9 +18,7 @@ * This view represents a section of user data in the address tab of the keyboard accessory. */ class AddressAccessoryInfoView extends LinearLayout { - private ChipView mNameFirst; - private ChipView mNameMiddle; - private ChipView mNameLast; + private ChipView mNameFull; private ChipView mCompanyName; private ChipView mAddressHomeLine1; private ChipView mAddressHomeLine2; @@ -61,9 +59,7 @@ @Override protected void onFinishInflate() { super.onFinishInflate(); - mNameFirst = findViewById(R.id.name_first); - mNameMiddle = findViewById(R.id.name_middle); - mNameLast = findViewById(R.id.name_last); + mNameFull = findViewById(R.id.name_full); mCompanyName = findViewById(R.id.company_name); mAddressHomeLine1 = findViewById(R.id.address_home_line_1); mAddressHomeLine2 = findViewById(R.id.address_home_line_2); @@ -75,16 +71,8 @@ mEmailAddress = findViewById(R.id.email_address); } - public ChipView getNameFirst() { - return mNameFirst; - } - - public ChipView getNameMiddle() { - return mNameMiddle; - } - - public ChipView getNameLast() { - return mNameLast; + public ChipView getNameFull() { + return mNameFull; } public ChipView getCompanyName() {
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewBinder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewBinder.java index 4ef49e9..dda8664 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewBinder.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewBinder.java
@@ -46,18 +46,16 @@ @Override protected void bind(KeyboardAccessoryData.UserInfo info, AddressAccessoryInfoView view) { - bindChipView(view.getNameFirst(), info.getFields().get(0)); - bindChipView(view.getNameMiddle(), info.getFields().get(1)); - bindChipView(view.getNameLast(), info.getFields().get(2)); - bindChipView(view.getCompanyName(), info.getFields().get(3)); - bindChipView(view.getAddressHomeLine1(), info.getFields().get(4)); - bindChipView(view.getAddressHomeLine2(), info.getFields().get(5)); - bindChipView(view.getAddressHomeZip(), info.getFields().get(6)); - bindChipView(view.getAddressHomeCity(), info.getFields().get(7)); - bindChipView(view.getAddressHomeState(), info.getFields().get(8)); - bindChipView(view.getAddressHomeCountry(), info.getFields().get(9)); - bindChipView(view.getPhoneHomeWholeNumber(), info.getFields().get(10)); - bindChipView(view.getEmailAddress(), info.getFields().get(11)); + bindChipView(view.getNameFull(), info.getFields().get(0)); + bindChipView(view.getCompanyName(), info.getFields().get(1)); + bindChipView(view.getAddressHomeLine1(), info.getFields().get(2)); + bindChipView(view.getAddressHomeLine2(), info.getFields().get(3)); + bindChipView(view.getAddressHomeZip(), info.getFields().get(4)); + bindChipView(view.getAddressHomeCity(), info.getFields().get(5)); + bindChipView(view.getAddressHomeState(), info.getFields().get(6)); + bindChipView(view.getAddressHomeCountry(), info.getFields().get(7)); + bindChipView(view.getPhoneHomeWholeNumber(), info.getFields().get(8)); + bindChipView(view.getEmailAddress(), info.getFields().get(9)); } void bindChipView(ChipView chip, UserInfoField field) {
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java index 63ce6aed2..4b069887 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessoryIntegrationTest.java
@@ -114,7 +114,7 @@ // Focus the field to bring up the accessory. mHelper.focusPasswordField(); - mHelper.waitForKeyboardAccessoryToBeShown(true); + mHelper.waitForKeyboardAccessoryToBeShown(); // Click the tab to show the sheet and hide the keyboard. whenDisplayed(allOf(withContentDescription(R.string.address_accessory_sheet_toggle), @@ -142,9 +142,10 @@ whenDisplayed(withId(R.id.addresses_sheet)); // Click a suggestion. - whenDisplayed(withText("McSpartangregor")).perform(click()); + whenDisplayed(withText("Marcus McSpartangregor")).perform(click()); - CriteriaHelper.pollInstrumentationThread( - () -> { return mHelper.getFieldText("NAME_FIRST").equals("McSpartangregor"); }); + CriteriaHelper.pollInstrumentationThread(() -> { + return mHelper.getFieldText("NAME_FIRST").equals("Marcus McSpartangregor"); + }); } }
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java index 8a0d98e..1fddc52b 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetViewTest.java
@@ -115,9 +115,7 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { mModel.add(new AccessorySheetDataPiece( createInfo( - /*nameFirst=*/"Maya", - /*nameMiddle=*/"J.", - /*nameLast=*/"Park", + /*nameFull=*/"Maya J. Park", /*companyName=*/"", /*addressHomeLine1=*/"100 Test Str.", /*addressHomeLine2=*/"", @@ -138,9 +136,7 @@ CriteriaHelper.pollUiThread(() -> mView.get().getChildCount() > 0); // Check that the titles are correct: - assertThat(getChipText(R.id.name_first), is("Maya")); - assertThat(getChipText(R.id.name_middle), is("J.")); - assertThat(getChipText(R.id.name_last), is("Park")); + assertThat(getChipText(R.id.name_full), is("Maya J. Park")); assertThat(getChipText(R.id.company_name), is("")); assertThat(getChipText(R.id.address_home_line_1), is("100 Test Str.")); assertThat(getChipText(R.id.address_home_line_2), is("")); @@ -155,25 +151,20 @@ assertThat(findChipView(R.id.company_name).isShown(), is(false)); // Chips are clickable: - TestThreadUtils.runOnUiThreadBlocking(findChipView(R.id.name_first)::performClick); + TestThreadUtils.runOnUiThreadBlocking(findChipView(R.id.name_full)::performClick); assertThat(clicked.get(), is(true)); clicked.set(false); TestThreadUtils.runOnUiThreadBlocking(findChipView(R.id.email_address)::performClick); assertThat(clicked.get(), is(true)); } - private UserInfo createInfo(String nameFirst, String nameMiddle, String nameLast, - String companyName, String addressHomeLine1, String addressHomeLine2, - String addressHomeZip, String addressHomeCity, String addressHomeState, - String addressHomeCountry, String phoneHomeWholeNumber, String emailAddress, - AtomicBoolean clickRecorder) { + private UserInfo createInfo(String nameFull, String companyName, String addressHomeLine1, + String addressHomeLine2, String addressHomeZip, String addressHomeCity, + String addressHomeState, String addressHomeCountry, String phoneHomeWholeNumber, + String emailAddress, AtomicBoolean clickRecorder) { UserInfo info = new UserInfo("", null); - info.addField(new UserInfoField( - nameFirst, nameFirst, "", false, item -> clickRecorder.set(true))); - info.addField(new UserInfoField( - nameMiddle, nameMiddle, "", false, item -> clickRecorder.set(true))); info.addField( - new UserInfoField(nameLast, nameLast, "", false, item -> clickRecorder.set(true))); + new UserInfoField(nameFull, nameFull, "", false, item -> clickRecorder.set(true))); info.addField(new UserInfoField( companyName, companyName, "", false, item -> clickRecorder.set(true))); info.addField(new UserInfoField(
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java index 0dc6ce19..f3ef0c3 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessoryIntegrationTest.java
@@ -119,7 +119,7 @@ // Focus the field to bring up the accessory. mHelper.focusPasswordField(); - mHelper.waitForKeyboardAccessoryToBeShown(true); + mHelper.waitForKeyboardAccessoryToBeShown(); // Click the tab to show the sheet and hide the keyboard. whenDisplayed(allOf(withContentDescription(R.string.credit_card_accessory_sheet_toggle),
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/ArConsentDialog.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/ArConsentDialog.java index 1a268a5..29f9031f 100644 --- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/ArConsentDialog.java +++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/ArConsentDialog.java
@@ -142,6 +142,6 @@ @NativeMethods /* package */ interface Natives { - void onUserConsentResult(long nativeArcoreConsentPrompt, boolean allowed); + void onUserConsentResult(long nativeArCoreConsentPrompt, boolean allowed); } }
diff --git a/chrome/android/java/res/layout/location_status_icon.xml b/chrome/android/java/res/layout/location_status_icon.xml index 7f23056..0310480 100644 --- a/chrome/android/java/res/layout/location_status_icon.xml +++ b/chrome/android/java/res/layout/location_status_icon.xml
@@ -8,11 +8,8 @@ <org.chromium.ui.widget.ChromeImageButton android:id="@+id/location_bar_status_icon" - style="@style/LocationBarButton" - android:layout_width="@dimen/location_bar_start_icon_width" - android:layout_height="match_parent" + style="@style/OmniboxIcon" android:layout_gravity="center" - android:paddingEnd="4dp" android:src="@android:color/transparent" android:visibility="gone" android:contentDescription="@string/accessibility_toolbar_btn_site_info"
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml index 9a138cd6..7ab7a8b 100644 --- a/chrome/android/java/res/layout/new_tab_page_layout.xml +++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -40,6 +40,13 @@ android:background="@drawable/ntp_search_box" android:orientation="horizontal" android:paddingStart="@dimen/location_bar_lateral_padding" > + <ImageView + style="@style/OmniboxIcon" + android:id="@+id/search_engine_logo" + android:visibility="gone" + android:importantForAccessibility="no" + android:src="@drawable/ic_logo_googleg_24dp" + android:scaleType="centerInside" /> <!-- TODO(crbug.com/900912): Fix and remove lint ignore --> <EditText tools:ignore="Autofill,LabelFor"
diff --git a/chrome/android/java/res/layout/revamped_context_menu_header.xml b/chrome/android/java/res/layout/revamped_context_menu_header.xml index 47916bd..2cdbba33 100644 --- a/chrome/android/java/res/layout/revamped_context_menu_header.xml +++ b/chrome/android/java/res/layout/revamped_context_menu_header.xml
@@ -13,9 +13,7 @@ android:layout_height="wrap_content" android:orientation="horizontal" android:paddingStart="@dimen/revamped_context_menu_list_lateral_padding" - android:paddingEnd="@dimen/revamped_context_menu_list_lateral_padding" - android:paddingTop="@dimen/revamped_context_menu_header_vertical_padding" - android:paddingBottom="@dimen/revamped_context_menu_header_vertical_padding"> + android:paddingEnd="@dimen/revamped_context_menu_list_lateral_padding"> <FrameLayout android:layout_width="wrap_content" @@ -28,7 +26,9 @@ android:background="@drawable/tile_view_icon_background_modern" android:layout_width="@dimen/revamped_context_menu_header_circle_bg_diameter" android:layout_height="@dimen/revamped_context_menu_header_circle_bg_diameter" - android:layout_margin="@dimen/revamped_context_menu_header_circle_bg_margin" + android:layout_marginTop="@dimen/revamped_context_menu_header_circle_bg_vertical_margin" + android:layout_marginStart="@dimen/revamped_context_menu_header_circle_bg_lateral_margin" + android:layout_marginEnd="@dimen/revamped_context_menu_header_circle_bg_lateral_margin" android:visibility="invisible" /> <org.chromium.ui.widget.RoundedCornerImageView @@ -37,6 +37,8 @@ android:layout_height="@dimen/revamped_context_menu_header_image_max_size" android:scaleType="centerInside" android:importantForAccessibility="no" + android:layout_marginTop="@dimen/revamped_context_menu_header_vertical_padding" + android:layout_marginBottom="@dimen/revamped_context_menu_header_vertical_padding" app:cornerRadiusTopStart="@dimen/default_rounded_corner_radius" app:cornerRadiusTopEnd="@dimen/default_rounded_corner_radius" app:cornerRadiusBottomStart="@dimen/default_rounded_corner_radius" @@ -45,10 +47,13 @@ </FrameLayout> <LinearLayout + android:id="@+id/title_and_url" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:layout_gravity="center_vertical"> + android:layout_gravity="center_vertical" + android:paddingTop="@dimen/revamped_context_menu_header_vertical_padding" + android:paddingBottom="@dimen/revamped_context_menu_header_vertical_padding"> <org.chromium.ui.widget.TextViewWithLeading android:id="@+id/menu_header_title"
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml index 8f9ac197..88c1c9a 100644 --- a/chrome/android/java/res/values-v17/styles.xml +++ b/chrome/android/java/res/values-v17/styles.xml
@@ -1009,6 +1009,12 @@ <item name="tint">@color/default_icon_color</item> </style> + <style name="OmniboxIcon" parent="LocationBarButton"> + <item name="android:layout_width">@dimen/location_bar_start_icon_width</item> + <item name="android:layout_height">match_parent</item> + <item name="android:layout_marginEnd">4dp</item> + </style> + <!-- Revamped context menu --> <style name="RevampedContextMenuItemText"> <item name="android:background">?attr/selectableItemBackground</item>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index dded95b..5582f203 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -573,7 +573,8 @@ <dimen name="revamped_context_menu_divider_padding">8dp</dimen> <dimen name="revamped_context_menu_header_image_max_size">60dp</dimen> <dimen name="revamped_context_menu_header_circle_bg_diameter">48dp</dimen> - <dimen name="revamped_context_menu_header_circle_bg_margin">6dp</dimen> + <dimen name="revamped_context_menu_header_circle_bg_lateral_margin">6dp</dimen> + <dimen name="revamped_context_menu_header_circle_bg_vertical_margin">22dp</dimen> <dimen name="revamped_context_menu_header_monogram_text_size">16dp</dimen> <dimen name="revamped_context_menu_header_monogram_size">26dp</dimen> <!-- Reader Mode dimensions -->
diff --git a/chrome/android/java/res/xml/contextual_search_preferences.xml b/chrome/android/java/res/xml/contextual_search_preferences.xml index f20942c4..4bd9f7b 100644 --- a/chrome/android/java/res/xml/contextual_search_preferences.xml +++ b/chrome/android/java/res/xml/contextual_search_preferences.xml
@@ -3,17 +3,17 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<PreferenceScreen +<android.support.v7.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> - <org.chromium.chrome.browser.preferences.ChromeSwitchPreference + <org.chromium.chrome.browser.preferences.ChromeSwitchPreferenceCompat android:key="contextual_search_switch" android:summaryOn="@string/text_on" - android:summaryOff="@string/text_off" - app:drawDivider="true" /> + android:summaryOff="@string/text_off" /> - <org.chromium.chrome.browser.preferences.TextMessagePreference - android:title="@string/contextual_search_description" /> + <org.chromium.chrome.browser.preferences.TextMessagePreferenceCompat + android:title="@string/contextual_search_description" + app:allowDividerBelow="false" /> -</PreferenceScreen> +</android.support.v7.preference.PreferenceScreen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java index cf2a02f..9fcf46b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -121,12 +121,12 @@ // Record via UMA all modules that have been requested and are currently installed. This // will tell us the install penetration of each module over time. - ModuleInstaller.recordModuleAvailability(); + ModuleInstaller.getInstance().recordModuleAvailability(); } // Write installed modules to crash keys. This needs to be done as early as possible so that // these values are set before any crashes are reported. - ModuleInstaller.updateCrashKeys(); + ModuleInstaller.getInstance().updateCrashKeys(); BuildInfo.setFirebaseAppId(FirebaseConfig.getFirebaseAppId());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index 81433226..1c1b4a07 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -284,6 +284,7 @@ public static final String OMNIBOX_SHOW_SUGGESTION_FAVICONS = "OmniboxUIExperimentShowSuggestionFavicons"; public static final String OMNIBOX_SPARE_RENDERER = "OmniboxSpareRenderer"; + public static final String OMNIBOX_SEARCH_ENGINE_LOGO = "OmniboxSearchEngineLogo"; public static final String OVERLAY_NEW_LAYOUT = "OverlayNewLayout"; public static final String OVERSCROLL_HISTORY_NAVIGATION = "OverscrollHistoryNavigation"; public static final String PASSWORD_EDITING_ANDROID = "PasswordEditingAndroid";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java index 15343d48..e742931 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
@@ -773,6 +773,7 @@ List<String> names = new ArrayList<>(); List<String> shortNames = new ArrayList<>(); List<String> packageNames = new ArrayList<>(); + List<String> ids = new ArrayList<>(); List<Integer> shellApkVersions = new ArrayList<>(); List<Integer> versionCodes = new ArrayList<>(); List<String> uris = new ArrayList<>(); @@ -785,6 +786,7 @@ List<Long> backgroundColors = new ArrayList<>(); List<Long> lastUpdateCheckTimesMs = new ArrayList<>(); List<Boolean> relaxUpdates = new ArrayList<>(); + List<String> updateStatuses = new ArrayList<>(); Context context = ContextUtils.getApplicationContext(); PackageManager packageManager = context.getPackageManager(); @@ -799,6 +801,7 @@ names.add(webApkInfo.name()); shortNames.add(webApkInfo.shortName()); packageNames.add(webApkInfo.webApkPackageName()); + ids.add(webApkInfo.id()); shellApkVersions.add(webApkInfo.shellApkVersion()); versionCodes.add(packageInfo.versionCode); uris.add(webApkInfo.uri().toString()); @@ -821,12 +824,13 @@ } lastUpdateCheckTimesMs.add(lastUpdateCheckTimeMsForStorage); relaxUpdates.add(relaxUpdatesForStorage); + updateStatuses.add(storage.getUpdateStatus()); } } } nativeOnWebApksRetrieved(callbackPointer, names.toArray(new String[0]), shortNames.toArray(new String[0]), packageNames.toArray(new String[0]), - CollectionUtil.integerListToIntArray(shellApkVersions), + ids.toArray(new String[0]), CollectionUtil.integerListToIntArray(shellApkVersions), CollectionUtil.integerListToIntArray(versionCodes), uris.toArray(new String[0]), scopes.toArray(new String[0]), manifestUrls.toArray(new String[0]), manifestStartUrls.toArray(new String[0]), @@ -835,13 +839,23 @@ CollectionUtil.longListToLongArray(themeColors), CollectionUtil.longListToLongArray(backgroundColors), CollectionUtil.longListToLongArray(lastUpdateCheckTimesMs), - CollectionUtil.booleanListToBooleanArray(relaxUpdates)); + CollectionUtil.booleanListToBooleanArray(relaxUpdates), + updateStatuses.toArray(new String[0])); + } + + @CalledByNative + public static void setForceWebApkUpdate(String id) { + WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(id); + if (storage != null) { + storage.setShouldForceUpdate(true); + } } private static native void nativeOnWebappDataStored(long callbackPointer); private static native void nativeOnWebApksRetrieved(long callbackPointer, String[] names, - String[] shortNames, String[] packageName, int[] shellApkVersions, int[] versionCodes, - String[] uris, String[] scopes, String[] manifestUrls, String[] manifestStartUrls, - int[] displayModes, int[] orientations, long[] themeColors, long[] backgroundColors, - long[] lastUpdateCheckTimesMs, boolean[] relaxUpdates); + String[] shortNames, String[] packageNames, String[] ids, int[] shellApkVersions, + int[] versionCodes, String[] uris, String[] scopes, String[] manifestUrls, + String[] manifestStartUrls, int[] displayModes, int[] orientations, long[] themeColors, + long[] backgroundColors, long[] lastUpdateCheckTimesMs, boolean[] relaxUpdates, + String[] updateStatuses); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPromoControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPromoControl.java index f28bcc3..2955971 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPromoControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPromoControl.java
@@ -386,7 +386,7 @@ new Handler().post(new Runnable() { @Override public void run() { - PreferencesLauncher.launchSettingsPage( + PreferencesLauncher.launchSettingsPageCompat( getContext(), ContextualSearchPreferenceFragment.class); } });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderViewBinder.java index 1470c4d6..420e5a5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderViewBinder.java
@@ -34,7 +34,7 @@ ? View.GONE : View.VISIBLE); } else if (propertyKey == RevampedContextMenuHeaderProperties.URL_CLICK_LISTENER) { - view.findViewById(R.id.menu_header_url) + view.findViewById(R.id.title_and_url) .setOnClickListener( model.get(RevampedContextMenuHeaderProperties.URL_CLICK_LISTENER)); } else if (propertyKey == RevampedContextMenuHeaderProperties.URL_MAX_LINES) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialog.java similarity index 99% rename from chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java rename to chrome/android/java/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialog.java index 913a37a..44e5778 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialog.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.chrome.browser; +package org.chromium.chrome.browser.device_dialog; import android.Manifest; import android.app.Activity; @@ -26,6 +26,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeBaseAppCompatActivity; import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.components.location.LocationUtils;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/BluetoothScanningPermissionDialog.java similarity index 98% rename from chrome/android/java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java rename to chrome/android/java/src/org/chromium/chrome/browser/device_dialog/BluetoothScanningPermissionDialog.java index 572c3126..bcdb010e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/BluetoothScanningPermissionDialog.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.chrome.browser; +package org.chromium.chrome.browser.device_dialog; import android.app.Activity; import android.app.Dialog; @@ -27,6 +27,7 @@ import org.chromium.base.annotations.JCaller; import org.chromium.base.annotations.NativeMethods; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeBaseAppCompatActivity; import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.util.MathUtils;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DeviceItemAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/DeviceItemAdapter.java similarity index 99% rename from chrome/android/java/src/org/chromium/chrome/browser/DeviceItemAdapter.java rename to chrome/android/java/src/org/chromium/chrome/browser/device_dialog/DeviceItemAdapter.java index ebd7bd1..42710ea2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/DeviceItemAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/DeviceItemAdapter.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.chrome.browser; +package org.chromium.chrome.browser.device_dialog; import android.content.Context; import android.content.res.Resources;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DeviceItemRow.java b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/DeviceItemRow.java similarity index 97% rename from chrome/android/java/src/org/chromium/chrome/browser/DeviceItemRow.java rename to chrome/android/java/src/org/chromium/chrome/browser/device_dialog/DeviceItemRow.java index 2e907e2..8b2ffe4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/DeviceItemRow.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/DeviceItemRow.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.chrome.browser; +package org.chromium.chrome.browser.device_dialog; import android.graphics.drawable.Drawable; import android.os.Build;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/ItemChooserDialog.java similarity index 91% rename from chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java rename to chrome/android/java/src/org/chromium/chrome/browser/device_dialog/ItemChooserDialog.java index 4ff29f0..77205cf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/ItemChooserDialog.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.chrome.browser; +package org.chromium.chrome.browser.device_dialog; import android.app.Activity; import android.app.Dialog; @@ -18,6 +18,7 @@ import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.Window; +import android.widget.AdapterView; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ListView; @@ -26,6 +27,7 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; +import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.MathUtils; import org.chromium.ui.base.DeviceFormFactor; import org.chromium.ui.widget.TextViewWithClickableSpans; @@ -170,20 +172,40 @@ mConfirmButton = (Button) dialogContainer.findViewById(R.id.positive); mConfirmButton.setText(labels.positiveButton); mConfirmButton.setEnabled(false); - mConfirmButton.setOnClickListener(v -> { - mItemSelectedCallback.onItemSelected(mItemAdapter.getSelectedItemKey()); - mDialog.setOnDismissListener(null); - mDialog.dismiss(); - }); + + View.OnClickListener clickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + mItemSelectedCallback.onItemSelected(mItemAdapter.getSelectedItemKey()); + mDialog.setOnDismissListener(null); + mDialog.dismiss(); + } + }; mItemAdapter = new DeviceItemAdapter( mActivity, /*itemsSelectable=*/true, R.layout.item_chooser_dialog_row); mItemAdapter.setNotifyOnChange(true); mItemAdapter.setObserver(this); + + if (FeatureUtilities.isNoTouchModeEnabled()) { + // TODO(crbug.com/982869): ideally we would port to using the modal dialog + // manager. Until then, we will treat clicking on the items as selecting them. + mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { + mItemAdapter.onItemClick(adapter, view, position, id); + clickListener.onClick(null); + } + }); + mConfirmButton.setVisibility(View.GONE); + } else { + mConfirmButton.setOnClickListener(clickListener); + mListView.setOnItemClickListener(mItemAdapter); + } + mListView.setAdapter(mItemAdapter); mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); mListView.setEmptyView(mEmptyMessage); - mListView.setOnItemClickListener(mItemAdapter); mListView.setDivider(null); setState(State.STARTING);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/OWNERS new file mode 100644 index 0000000..298cd1c --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/OWNERS
@@ -0,0 +1,2 @@ +juncai@chromium.org +reillyg@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialog.java similarity index 98% rename from chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java rename to chrome/android/java/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialog.java index 02668b0..23cd8ad 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialog.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.chrome.browser; +package org.chromium.chrome.browser.device_dialog; import android.app.Activity; import android.text.SpannableString;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java index a854524..2a6c9dc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -39,6 +39,7 @@ import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener; import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; +import org.chromium.chrome.browser.omnibox.LocationBarLayout; import org.chromium.chrome.browser.partnercustomizations.HomepageManager; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.suggestions.SiteSuggestion; @@ -282,6 +283,16 @@ manager.addDestructionObserver(NewTabPageLayout.this::onDestroy); + // Native will be initialized at this time (see NativePageFactory.java). + // TODO(crbug.com/982430): Check for changes to the DSE and react accordingly. + // TODO(crbug.com/973150): Fetch the favicon when the DSE isn't Google. + if (LocationBarLayout.shouldShowGoogleLogo()) { + ImageView logoView = findViewById(R.id.search_engine_logo); + + assert logoView != null; + logoView.setVisibility(VISIBLE); + } + mInitialized = true; TraceEvent.end(TAG + ".initialize()");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java index 6db6ed6..f5ae08cd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -32,6 +32,7 @@ import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.ActivityTabProvider; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.WindowDelegate; import org.chromium.chrome.browser.locale.LocaleManager; @@ -85,8 +86,6 @@ protected ToolbarDataProvider mToolbarDataProvider; private ObserverList<UrlFocusChangeListener> mUrlFocusChangeListeners = new ObserverList<>(); - protected boolean mNativeInitialized; - private final List<Runnable> mDeferredNativeRunnables = new ArrayList<Runnable>(); protected StatusViewCoordinator mStatusViewCoordinator; @@ -96,11 +95,12 @@ private WindowAndroid mWindowAndroid; private WindowDelegate mWindowDelegate; - private boolean mUrlHasFocus; protected boolean mUrlFocusChangeInProgress; + protected boolean mNativeInitialized; + protected boolean mShouldShowGoogleLogo; + private boolean mUrlHasFocus; private boolean mUrlFocusedFromFakebox; private boolean mUrlFocusedWithoutAnimations; - private boolean mVoiceSearchEnabled; private OmniboxPrerender mOmniboxPrerender; @@ -140,6 +140,7 @@ return false; } } + public LocationBarLayout(Context context, AttributeSet attrs) { this(context, attrs, R.layout.location_bar); } @@ -289,6 +290,16 @@ } /** + * Encapsulates complicated boolean check for reuse and readability. + */ + public static boolean shouldShowGoogleLogo() { + return !LocaleManager.getInstance().needToCheckForSearchEnginePromo() + && TemplateUrlServiceFactory.get().isDefaultSearchEngineGoogle() + && ChromeFeatureList.isInitialized() + && ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_SEARCH_ENGINE_LOGO); + } + + /** * Handles native dependent initialization for this class. */ @Override @@ -308,6 +319,15 @@ } mDeferredNativeRunnables.clear(); + // Show the DSE logo when the url has focus. + // TODO(crbug.com/982430): Check for changes to the DSE and react accordingly. + mShouldShowGoogleLogo = LocationBarLayout.shouldShowGoogleLogo(); + mStatusViewCoordinator.setShouldShowGoogleLogo(mShouldShowGoogleLogo); + mToolbarDataProvider.setShouldShowGoogleLogo(mShouldShowGoogleLogo); + if (mShouldShowGoogleLogo) { + mStatusViewCoordinator.setShowIconsWhenUrlFocused(true); + } + updateVisualsForState(); updateMicButtonVisibility(mUrlFocusChangePercent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java index bd0dd563..7defcab6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
@@ -39,7 +39,10 @@ protected void onFinishInflate() { super.onFinishInflate(); - mFirstVisibleFocusedView = findViewById(R.id.url_bar); + // Assign the first visible view here only if it hasn't been set by the DSE icon experiment. + // See onNativeLibrary ready for when this variable is set for the DSE icon case. + mFirstVisibleFocusedView = mFirstVisibleFocusedView == null ? findViewById(R.id.url_bar) + : mFirstVisibleFocusedView; Rect delegateArea = new Rect(); mUrlActionContainer.getHitRect(delegateArea); @@ -49,6 +52,16 @@ setTouchDelegate(touchDelegate); } + @Override + public void onNativeLibraryReady() { + super.onNativeLibraryReady(); + + // The search logo will be the first visible view when the google logo is showing. + if (mShouldShowGoogleLogo) { + mFirstVisibleFocusedView = findViewById(R.id.location_bar_status); + } + } + /** * @return The first view visible when the location bar is focused. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java index 4830f8d..37a8795 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
@@ -27,6 +27,7 @@ private boolean mVerboseStatusSpaceAvailable; private boolean mPageIsPreview; private boolean mPageIsOffline; + private boolean mShouldShowGoogleLogo; private boolean mShowStatusIconWhenUrlFocused; @@ -281,6 +282,14 @@ } /** + * Turn on/off the google logo in the omnibox. + */ + void setShouldShowGoogleLogo(boolean shouldShowGoogleLogo) { + mShouldShowGoogleLogo = shouldShowGoogleLogo; + updateLocationBarIcon(); + } + + /** * Update selection of icon presented on the location bar. * * - Navigation button is: @@ -301,10 +310,15 @@ if (mUrlHasFocus) { if (mShowStatusIconWhenUrlFocused) { - icon = mFirstSuggestionIsSearchQuery ? R.drawable.omnibox_search - : R.drawable.ic_omnibox_page; - tint = mNavigationIconTintRes; - description = R.string.accessibility_toolbar_btn_site_info; + if (mShouldShowGoogleLogo) { + // TODO(crbug.com/973150): Fetch the favicon when the DSE isn't Google. + icon = R.drawable.ic_logo_googleg_24dp; + } else { + icon = mFirstSuggestionIsSearchQuery ? R.drawable.omnibox_search + : R.drawable.ic_omnibox_page; + tint = mNavigationIconTintRes; + description = R.string.accessibility_toolbar_btn_site_info; + } } } else if (mSecurityIconRes != 0) { mIsSecurityButtonShown = true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusViewCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusViewCoordinator.java index f8151774..1fab538 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusViewCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusViewCoordinator.java
@@ -194,4 +194,11 @@ public void setFirstSuggestionIsSearchType(boolean firstSuggestionIsSearchQuery) { mMediator.setFirstSuggestionIsSearchType(firstSuggestionIsSearchQuery); } + + /** + * Turn on/off the google logo in the omnibox. + */ + public void setShouldShowGoogleLogo(boolean shouldShowGoogleLogo) { + mMediator.setShouldShowGoogleLogo(shouldShowGoogleLogo); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java index 2d7de927..5d866a2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java
@@ -391,6 +391,11 @@ } @Override + public void onVerificationError(String errorMessage) { + mCallback.onGetPaymentAppsError(errorMessage); + } + + @Override public void onFinishedVerification() { mPendingVerifiersCount--; if (mPendingVerifiersCount != 0) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java index 06d181d..3946823 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactory.java
@@ -38,6 +38,12 @@ void onPaymentAppCreated(PaymentApp paymentApp); /** + * Called when an error has occurred. + * @param errorMessage Developer facing error message. + */ + void onGetPaymentAppsError(String errorMessage); + + /** * Called when the factory is finished creating payment apps. */ void onAllPaymentAppsCreated(); @@ -119,6 +125,11 @@ } @Override + public void onGetPaymentAppsError(String errorMessage) { + callback.onGetPaymentAppsError(errorMessage); + } + + @Override public void onAllPaymentAppsCreated() { mPendingTasks.remove(additionalFactory); if (mPendingTasks.isEmpty()) callback.onAllPaymentAppsCreated();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentManifestVerifier.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentManifestVerifier.java index 8c0ec0b..d2e1dba 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentManifestVerifier.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentManifestVerifier.java
@@ -70,6 +70,13 @@ void onAllOriginsSupported(URI methodName); /** + * Called when a part of verification has failed. + * + * @param errorMessage Developer facing error message. + */ + void onVerificationError(String errorMessage); + + /** * Called when the manifest has been fully verified. No more valid apps or origins will * be found after this call. */ @@ -524,10 +531,12 @@ } @Override - public void onManifestDownloadFailure() { + public void onManifestDownloadFailure(String errorMessage) { if (mAtLeastOneManifestFailedToDownloadOrParse) return; mAtLeastOneManifestFailedToDownloadOrParse = true; + mCallback.onVerificationError(errorMessage); + if (mIsManifestCacheStaleOrUnusable) mCallback.onFinishedVerification(); mCallback.onFinishedUsingResources(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java index 20bd792b..1b2eb70 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -409,7 +409,13 @@ private PaymentResponseHelper mPaymentResponseHelper; /** If not empty, use this error message for rejecting PaymentRequest.show(). */ - private String mProhibitedOriginOrInvalidSslErrorMessage; + private String mRejectShowErrorMessage; + + /** + * True when Payment Request is invoked on a prohibited origin (e.g., blob:) or with an invalid + * SSL certificate (e.g., self-signed). + */ + private boolean mIsProhibitedOriginOrInvalidSsl; /** * Builds the PaymentRequest service implementation. @@ -488,8 +494,9 @@ // TODO(crbug.com/978471): Improve architecture for handling prohibited origins and invalid // SSL certificates. if (!UrlUtil.isOriginAllowedToUseWebPaymentApis(mWebContents.getLastCommittedUrl())) { - mProhibitedOriginOrInvalidSslErrorMessage = ErrorStrings.PROHIBITED_ORIGIN; - Log.d(TAG, mProhibitedOriginOrInvalidSslErrorMessage); + mIsProhibitedOriginOrInvalidSsl = true; + mRejectShowErrorMessage = ErrorStrings.PROHIBITED_ORIGIN; + Log.d(TAG, mRejectShowErrorMessage); Log.d(TAG, ErrorStrings.PROHIBITED_ORIGIN_OR_INVALID_SSL_EXPLANATION); // Don't show any UI. Resolve .canMakePayment() with "false". Reject .show() with // "NotSupportedError". @@ -500,10 +507,11 @@ mJourneyLogger.setRequestedInformation( mRequestShipping, mRequestPayerEmail, mRequestPayerPhone, mRequestPayerName); - mProhibitedOriginOrInvalidSslErrorMessage = - mDelegate.getInvalidSslCertificateErrorMessage(mWebContents); - if (!TextUtils.isEmpty(mProhibitedOriginOrInvalidSslErrorMessage)) { - Log.d(TAG, mProhibitedOriginOrInvalidSslErrorMessage); + assert mRejectShowErrorMessage == null; + mRejectShowErrorMessage = mDelegate.getInvalidSslCertificateErrorMessage(mWebContents); + if (!TextUtils.isEmpty(mRejectShowErrorMessage)) { + mIsProhibitedOriginOrInvalidSsl = true; + Log.d(TAG, mRejectShowErrorMessage); Log.d(TAG, ErrorStrings.PROHIBITED_ORIGIN_OR_INVALID_SSL_EXPLANATION); // Don't show any UI. Resolve .canMakePayment() with "false". Reject .show() with // "NotSupportedError". @@ -811,6 +819,11 @@ } @Override + public void onGetPaymentAppsError(String errorMessage) { + if (TextUtils.isEmpty(mRejectShowErrorMessage)) mRejectShowErrorMessage = errorMessage; + } + + @Override public void onAllPaymentAppsCreated() { if (mClient == null) return; @@ -2117,11 +2130,11 @@ mJourneyLogger.setNotShown(mArePaymentMethodsSupported ? NotShownReason.NO_MATCHING_PAYMENT_METHOD : NotShownReason.NO_SUPPORTED_PAYMENT_METHOD); - if (!TextUtils.isEmpty(mProhibitedOriginOrInvalidSslErrorMessage)) { + if (mIsProhibitedOriginOrInvalidSsl) { if (mNativeObserverForTest != null) mNativeObserverForTest.onNotSupportedError(); // Chrome always refuses payments with invalid SSL and in prohibited origin types. - disconnectFromClientWithDebugMessage(mProhibitedOriginOrInvalidSslErrorMessage, - PaymentErrorReason.NOT_SUPPORTED); + disconnectFromClientWithDebugMessage( + mRejectShowErrorMessage, PaymentErrorReason.NOT_SUPPORTED); } else if (mIsIncognito) { // If the user is in the incognito mode, hide the absence of their payment methods // from the merchant site. @@ -2130,7 +2143,10 @@ } else { if (mNativeObserverForTest != null) mNativeObserverForTest.onNotSupportedError(); disconnectFromClientWithDebugMessage( - ErrorStrings.GENERIC_PAYMENT_METHOD_NOT_SUPPORTED_MESSAGE, + ErrorStrings.GENERIC_PAYMENT_METHOD_NOT_SUPPORTED_MESSAGE + + (TextUtils.isEmpty(mRejectShowErrorMessage) + ? "" + : " " + mRejectShowErrorMessage), PaymentErrorReason.NOT_SUPPORTED); } if (sObserverForTest != null) sObserverForTest.onPaymentRequestServiceShowFailed();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java index 504944c..913e3b13 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
@@ -403,6 +403,14 @@ } @CalledByNative + private static void onGetPaymentAppsError( + PaymentAppFactory.PaymentAppCreatedCallback callback, String errorMessage) { + ThreadUtils.assertOnUiThread(); + + callback.onGetPaymentAppsError(errorMessage); + } + + @CalledByNative private static void onHasServiceWorkerPaymentApps( HasServiceWorkerPaymentAppsCallback callback, boolean hasPaymentApps) { ThreadUtils.assertOnUiThread();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferences.java index 07e93f1..7a667fca 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferences.java
@@ -4,44 +4,42 @@ package org.chromium.chrome.browser.preferences.autofill_assistant; +import android.content.Context; import android.os.Bundle; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceChangeListener; -import android.preference.PreferenceFragment; +import android.support.v7.preference.PreferenceFragmentCompat; +import android.support.v7.preference.PreferenceScreen; import org.chromium.base.ContextUtils; import org.chromium.chrome.R; -import org.chromium.chrome.browser.preferences.ChromeSwitchPreference; +import org.chromium.chrome.browser.preferences.ChromeSwitchPreferenceCompat; /** The "Autofill Assistant" preferences screen in Settings. */ -public class AutofillAssistantPreferences extends PreferenceFragment { +public class AutofillAssistantPreferences extends PreferenceFragmentCompat { /** Autofill Assistant switch preference key name. */ public static final String PREF_AUTOFILL_ASSISTANT_SWITCH = "autofill_assistant_switch"; @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { getActivity().setTitle(R.string.prefs_autofill_assistant_title); - setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity())); + + PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getStyledContext()); + setPreferenceScreen(screen); createAutofillAssistantSwitch(); } private void createAutofillAssistantSwitch() { - ChromeSwitchPreference autofillAssistantSwitch = - new ChromeSwitchPreference(getActivity(), null); + ChromeSwitchPreferenceCompat autofillAssistantSwitch = + new ChromeSwitchPreferenceCompat(getStyledContext(), null); autofillAssistantSwitch.setKey(PREF_AUTOFILL_ASSISTANT_SWITCH); autofillAssistantSwitch.setTitle(R.string.prefs_autofill_assistant_switch); autofillAssistantSwitch.setSummaryOn(R.string.text_on); autofillAssistantSwitch.setSummaryOff(R.string.text_off); - autofillAssistantSwitch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - ContextUtils.getAppSharedPreferences() - .edit() - .putBoolean(PREF_AUTOFILL_ASSISTANT_SWITCH, (boolean) newValue) - .apply(); - return true; - } + autofillAssistantSwitch.setOnPreferenceChangeListener((preference, newValue) -> { + ContextUtils.getAppSharedPreferences() + .edit() + .putBoolean(PREF_AUTOFILL_ASSISTANT_SWITCH, (boolean) newValue) + .apply(); + return true; }); getPreferenceScreen().addPreference(autofillAssistantSwitch); @@ -52,4 +50,8 @@ autofillAssistantSwitch.setChecked(ContextUtils.getAppSharedPreferences().getBoolean( PREF_AUTOFILL_ASSISTANT_SWITCH, true)); } + + private Context getStyledContext() { + return getPreferenceManager().getContext(); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ContextualSearchPreferenceFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ContextualSearchPreferenceFragment.java index 10355f7e..3988888 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ContextualSearchPreferenceFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ContextualSearchPreferenceFragment.java
@@ -5,26 +5,22 @@ package org.chromium.chrome.browser.preferences.privacy; import android.os.Bundle; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceChangeListener; -import android.preference.PreferenceFragment; +import android.support.v7.preference.PreferenceFragmentCompat; import org.chromium.chrome.R; import org.chromium.chrome.browser.contextualsearch.ContextualSearchUma; -import org.chromium.chrome.browser.preferences.ChromeSwitchPreference; +import org.chromium.chrome.browser.preferences.ChromeSwitchPreferenceCompat; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.preferences.PreferenceUtils; /** * Fragment to manage the Contextual Search preference and to explain to the user what it does. */ -public class ContextualSearchPreferenceFragment extends PreferenceFragment { - +public class ContextualSearchPreferenceFragment extends PreferenceFragmentCompat { private static final String PREF_CONTEXTUAL_SEARCH_SWITCH = "contextual_search_switch"; @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { PreferenceUtils.addPreferencesFromResource(this, R.xml.contextual_search_preferences); getActivity().setTitle(R.string.contextual_search_title); setHasOptionsMenu(true); @@ -32,23 +28,19 @@ } private void initContextualSearchSwitch() { - ChromeSwitchPreference contextualSearchSwitch = - (ChromeSwitchPreference) findPreference(PREF_CONTEXTUAL_SEARCH_SWITCH); + ChromeSwitchPreferenceCompat contextualSearchSwitch = + (ChromeSwitchPreferenceCompat) findPreference(PREF_CONTEXTUAL_SEARCH_SWITCH); boolean isContextualSearchEnabled = !PrefServiceBridge.getInstance().isContextualSearchDisabled(); contextualSearchSwitch.setChecked(isContextualSearchEnabled); - contextualSearchSwitch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - PrefServiceBridge.getInstance().setContextualSearchState((boolean) newValue); - ContextualSearchUma.logPreferenceChange((boolean) newValue); - return true; - } + contextualSearchSwitch.setOnPreferenceChangeListener((preference, newValue) -> { + PrefServiceBridge.getInstance().setContextualSearchState((boolean) newValue); + ContextualSearchUma.logPreferenceChange((boolean) newValue); + return true; }); contextualSearchSwitch.setManagedPreferenceDelegate( preference -> PrefServiceBridge.getInstance().isContextualSearchDisabledByPolicy()); } - }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java index cde33f2..8d645c1e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchBoxDataProvider.java
@@ -123,4 +123,7 @@ public @ColorRes int getSecurityIconColorStateList() { return 0; } + + @Override + public void setShouldShowGoogleLogo(boolean shouldShowGoogleLogo) {} }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSitesBridge.java index 5276129..4e6de776 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSitesBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSitesBridge.java
@@ -85,21 +85,25 @@ @Override public void addBlacklistedUrl(String url) { + if (mNativeMostVisitedSitesBridge == 0) return; nativeAddOrRemoveBlacklistedUrl(mNativeMostVisitedSitesBridge, url, true); } @Override public void removeBlacklistedUrl(String url) { + if (mNativeMostVisitedSitesBridge == 0) return; nativeAddOrRemoveBlacklistedUrl(mNativeMostVisitedSitesBridge, url, false); } @Override public void recordPageImpression(int tilesCount) { + if (mNativeMostVisitedSitesBridge == 0) return; nativeRecordPageImpression(mNativeMostVisitedSitesBridge, tilesCount); } @Override public void recordTileImpression(Tile tile) { + if (mNativeMostVisitedSitesBridge == 0) return; nativeRecordTileImpression(mNativeMostVisitedSitesBridge, tile.getIndex(), tile.getType(), tile.getIconType(), tile.getTitleSource(), tile.getSource(), tile.getData().dataGenerationTime.getTime(), tile.getUrl()); @@ -107,6 +111,7 @@ @Override public void recordOpenedMostVisitedItem(Tile tile) { + if (mNativeMostVisitedSitesBridge == 0) return; nativeRecordOpenedMostVisitedItem(mNativeMostVisitedSitesBridge, tile.getIndex(), tile.getType(), tile.getTitleSource(), tile.getSource(), tile.getData().dataGenerationTime.getTime());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabState.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabState.java index 01fe3ca2f..c787370 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabState.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabState.java
@@ -460,9 +460,10 @@ * thread. * @param bundle Bundle to write the tab's state to. * @param state State object obtained from from {@link Tab#getState()}. + * @return Whether the tab state was successfully saved. */ - public static void saveState(Bundle bundle, TabState state) { - if (state == null || state.contentsState == null) return; + public static boolean saveState(Bundle bundle, TabState state) { + if (state == null || state.contentsState == null) return false; byte[] contentsStateBytes = getContentStateByteArray(state.contentsState.buffer()); @@ -479,6 +480,7 @@ bundle.putInt(VERSION, state.contentsState.version()); bundle.putInt(THEME_COLOR, state.themeColor); bundle.putBoolean(IS_INCOGNITO, state.isIncognito()); + return true; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java index d94d1e8..e92934f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -47,11 +47,13 @@ private final Context mContext; private Tab mTab; - private boolean mIsIncognito; private int mPrimaryColor; + private OverviewModeBehavior mOverviewModeBehavior; + + private boolean mIsIncognito; private boolean mIsUsingBrandColor; private boolean mShouldShowOmniboxInOverviewMode; - private OverviewModeBehavior mOverviewModeBehavior; + private boolean mShouldShowGoogleLogo; private long mNativeLocationBarModelAndroid; @@ -362,8 +364,17 @@ // If we're showing a query in the omnibox, and the security level is high enough to show // the search icon, return that instead of the security icon. if (getDisplaySearchTerms() != null) { - return R.drawable.omnibox_search; + if (mShouldShowGoogleLogo) { + // TODO(crbug.com/973150): Fetch the favicon when the DSE isn't Google. + return R.drawable.ic_logo_googleg_24dp; + } else { + return R.drawable.omnibox_search; + } + } else if (getNewTabPageForCurrentTab() != null && mShouldShowGoogleLogo) { + // TODO(crbug.com/973150): Fetch the favicon when the DSE isn't Google. + return R.drawable.ic_logo_googleg_24dp; } + return getSecurityIconResource(getSecurityLevel(), !isTablet, isOfflinePage(), isPreview()); } @@ -415,6 +426,12 @@ @Override public @ColorRes int getSecurityIconColorStateList() { + // Don't apply tint to the search logo, which is shown on the NTP and the SRP pages. + if ((getNewTabPageForCurrentTab() != null || getDisplaySearchTerms() != null) + && mShouldShowGoogleLogo) { + return 0; + } + int securityLevel = getSecurityLevel(); int color = getPrimaryColor(); boolean needLightIcon = ColorUtils.shouldUseLightForegroundOnBackground(color); @@ -477,6 +494,11 @@ return nativeGetURLForDisplay(mNativeLocationBarModelAndroid); } + @Override + public void setShouldShowGoogleLogo(boolean shouldShowGoogleLogo) { + mShouldShowGoogleLogo = shouldShowGoogleLogo; + } + private native long nativeInit(); private native void nativeDestroy(long nativeLocationBarModelAndroid); private native String nativeGetFormattedFullURL(long nativeLocationBarModelAndroid);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java index d4bcfa94..44e23ba 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
@@ -153,4 +153,9 @@ default public String getDisplaySearchTerms() { return null; } + + /** + * Turn on/off the google logo in the omnibox + */ + void setShouldShowGoogleLogo(boolean shouldShowGoogleLogo); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index 2593b38b..1e57a77a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -27,7 +27,6 @@ import org.chromium.base.metrics.CachedMetrics.EnumeratedHistogramSample; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; -import org.chromium.base.task.PostTask; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeTabbedActivity; @@ -114,7 +113,6 @@ import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.NavigationEntry; import org.chromium.content_public.browser.NavigationHandle; -import org.chromium.content_public.browser.UiThreadTaskTraits; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.common.ContentUrlConstants; import org.chromium.ui.base.DeviceFormFactor; @@ -1698,22 +1696,34 @@ * @param activityName Simple class name for the activity this toolbar belongs to. */ public void onDeferredStartup(final long activityCreationTimeMs, final String activityName) { - // Record startup performance statistics + recordStartupHistograms(activityCreationTimeMs, activityName); + mLocationBar.onDeferredStartup(); + } + + /** + * Record histograms covering Chrome startup. + * This method will collect metrics no sooner than RECORD_UMA_PERFORMANCE_METRICS_DELAY_MS since + * Activity creation to ensure availability of collected data. + * + * Histograms will not be collected if Chrome is destroyed before the above timeout passed. + */ + private void recordStartupHistograms( + final long activityCreationTimeMs, final String activityName) { + // Schedule call to self if minimum time since activity creation has not yet passed. long elapsedTime = SystemClock.elapsedRealtime() - activityCreationTimeMs; if (elapsedTime < RECORD_UMA_PERFORMANCE_METRICS_DELAY_MS) { - PostTask.postDelayedTask(UiThreadTaskTraits.DEFAULT, () -> { - onDeferredStartup(activityCreationTimeMs, activityName); - }, RECORD_UMA_PERFORMANCE_METRICS_DELAY_MS - elapsedTime); + // clang-format off + mHandler.postDelayed( + () -> recordStartupHistograms(activityCreationTimeMs, activityName), + RECORD_UMA_PERFORMANCE_METRICS_DELAY_MS - elapsedTime); + // clang-format on return; } + RecordHistogram.recordTimesHistogram("MobileStartup.ToolbarFirstDrawTime2." + activityName, mToolbar.getFirstDrawTime() - activityCreationTimeMs); - // mOmniboxStartupMetrics might be null. ie. ToolbarManager is destroyed. See - // https://crbug.com/860449 - if (mOmniboxStartupMetrics != null) mOmniboxStartupMetrics.maybeRecordHistograms(); - - mLocationBar.onDeferredStartup(); + mOmniboxStartupMetrics.maybeRecordHistograms(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java index 47c94f9f..c5dfdc5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -315,6 +315,9 @@ public @ColorRes int getSecurityIconColorStateList() { return 0; } + + @Override + public void setShouldShowGoogleLogo(boolean shouldShowGoogleLogo) {} }; // Set menu button background in case it was previously called before inflation
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java new file mode 100644 index 0000000..7394834 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java
@@ -0,0 +1,266 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.vr; + +import android.app.Activity; + +import org.chromium.base.BundleUtils; +import org.chromium.base.ContextUtils; +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.NativeMethods; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.infobar.InfoBarIdentifier; +import org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder; +import org.chromium.chrome.browser.modules.ModuleInstallUi; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.components.module_installer.ModuleInstaller; + +/** + * Installs AR DFM and ArCore runtimes. + */ +@JNINamespace("vr") +public class ArCoreInstallUtils implements ModuleInstallUi.FailureUiListener { + private static final String TAG = "ArCoreInstallUtils"; + + private long mNativeArCoreInstallUtils; + + private Tab mTab; + + // Instance that requested installation of ARCore. + // Should be non-null only if there is a pending request to install ARCore. + private static ArCoreInstallUtils sRequestInstallInstance; + + // Cached ArCoreShim instance - valid only after AR module was installed and + // getArCoreShimInstance() was called. + private static ArCoreShim sArCoreInstance; + + private static ArCoreShim getArCoreShimInstance() { + if (sArCoreInstance != null) return sArCoreInstance; + + try { + sArCoreInstance = + (ArCoreShim) Class.forName("org.chromium.chrome.browser.vr.ArCoreShimImpl") + .newInstance(); + } catch (ClassNotFoundException e) { + // shouldn't happen - we should only call this method once AR module is installed. + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + + return sArCoreInstance; + } + + private ArCoreInstallUtils(long nativeArCoreInstallUtils) { + mNativeArCoreInstallUtils = nativeArCoreInstallUtils; + // Need to be called before trying to access the AR module. + ModuleInstaller.getInstance().init(); + } + + @Override + public void onRetry() { + if (mNativeArCoreInstallUtils == 0) return; + requestInstallArModule(mTab); + } + + @Override + public void onCancel() { + if (mNativeArCoreInstallUtils == 0) return; + ArCoreInstallUtilsJni.get().onRequestInstallArModuleResult( + mNativeArCoreInstallUtils, false); + } + + @CalledByNative + private boolean canRequestInstallArModule() { + // We can only try to install the AR module if we are in a bundle mode. + return BundleUtils.isBundle(); + } + + @CalledByNative + private boolean shouldRequestInstallArModule() { + try { + // Try to find class in AR module that has not been obfuscated. + Class.forName("com.google.ar.core.ArCoreApk"); + return false; + } catch (ClassNotFoundException e) { + return true; + } + } + + @CalledByNative + private void requestInstallArModule(Tab tab) { + mTab = tab; + ModuleInstallUi ui = new ModuleInstallUi(mTab, R.string.ar_module_title, this); + ui.showInstallStartUi(); + ModuleInstaller.getInstance().install("ar", success -> { + assert shouldRequestInstallArModule() != success; + + if (success) { + // As per documentation, it's recommended to issue a call to + // ArCoreApk.checkAvailability() early in application lifecycle & ignore the result + // so that subsequent calls can return cached result: + // https://developers.google.com/ar/develop/java/enable-arcore + // This is as early in the app lifecycle as it gets for us - just after installing + // AR module. + getArCoreInstallStatus(); + } + + if (mNativeArCoreInstallUtils != 0) { + if (success) { + ui.showInstallSuccessUi(); + ArCoreInstallUtilsJni.get().onRequestInstallArModuleResult( + mNativeArCoreInstallUtils, success); + } else { + ui.showInstallFailureUi(); + // early exit - user will be offered a choice to retry & install flow will + // continue from onRetry / onCancel + return; + } + } + }); + } + + private @ArCoreShim.Availability int getArCoreInstallStatus() { + return getArCoreShimInstance().checkAvailability(ContextUtils.getApplicationContext()); + } + + @CalledByNative + private boolean shouldRequestInstallSupportedArCore() { + @ArCoreShim.Availability + int availability = getArCoreInstallStatus(); + // Skip ARCore installation if we are certain that it is already installed. + // In all other cases, we might as well try to install it and handle installation failures. + return availability != ArCoreShim.Availability.SUPPORTED_INSTALLED; + } + + @CalledByNative + private void requestInstallSupportedArCore(final Tab tab) { + assert shouldRequestInstallSupportedArCore(); + + @ArCoreShim.Availability + int arCoreAvailability = getArCoreInstallStatus(); + final Activity activity = tab.getActivity(); + String infobarText = null; + String buttonText = null; + switch (arCoreAvailability) { + case ArCoreShim.Availability.UNSUPPORTED_DEVICE_NOT_CAPABLE: + maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false); + break; + case ArCoreShim.Availability.UNKNOWN_CHECKING: + case ArCoreShim.Availability.UNKNOWN_ERROR: + case ArCoreShim.Availability.UNKNOWN_TIMED_OUT: + case ArCoreShim.Availability.SUPPORTED_NOT_INSTALLED: + infobarText = activity.getString(R.string.ar_core_check_infobar_install_text); + buttonText = activity.getString(R.string.app_banner_install); + break; + case ArCoreShim.Availability.SUPPORTED_APK_TOO_OLD: + infobarText = activity.getString(R.string.ar_core_check_infobar_update_text); + buttonText = activity.getString(R.string.update_from_market); + break; + case ArCoreShim.Availability.SUPPORTED_INSTALLED: + assert false; + break; + } + + SimpleConfirmInfoBarBuilder.Listener listener = new SimpleConfirmInfoBarBuilder.Listener() { + @Override + public void onInfoBarDismissed() { + maybeNotifyNativeOnRequestInstallSupportedArCoreResult( + !shouldRequestInstallSupportedArCore()); + } + + @Override + public boolean onInfoBarButtonClicked(boolean isPrimary) { + try { + assert sRequestInstallInstance == null; + @ArCoreShim.InstallStatus + int installStatus = getArCoreShimInstance().requestInstall(activity, true); + + if (installStatus == ArCoreShim.InstallStatus.INSTALL_REQUESTED) { + // Install flow will resume in onArCoreRequestInstallReturned, mark that + // there is active request. Native code notification will be deferred until + // our activity gets resumed. + sRequestInstallInstance = ArCoreInstallUtils.this; + } else if (installStatus == ArCoreShim.InstallStatus.INSTALLED) { + // No need to install - notify native code. + maybeNotifyNativeOnRequestInstallSupportedArCoreResult(true); + } + + } catch (ArCoreShim.UnavailableDeviceNotCompatibleException e) { + sRequestInstallInstance = null; + Log.w(TAG, "ARCore installation request failed with exception: %s", + e.toString()); + + maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false); + } catch (ArCoreShim.UnavailableUserDeclinedInstallationException e) { + maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false); + } + + return false; + } + + @Override + public boolean onInfoBarLinkClicked() { + return false; + } + }; + // TODO(ijamardo, https://crbug.com/838833): Add icon for AR info bar. + SimpleConfirmInfoBarBuilder.create(tab, listener, InfoBarIdentifier.AR_CORE_UPGRADE_ANDROID, + R.drawable.ic_error_outline_googblue_24dp, infobarText, buttonText, null, null, + true); + } + + /** + * Helper used to notify native code about the result of the request to install ARCore. + */ + private void maybeNotifyNativeOnRequestInstallSupportedArCoreResult(boolean success) { + if (mNativeArCoreInstallUtils != 0) { + ArCoreInstallUtilsJni.get().onRequestInstallSupportedArCoreResult( + mNativeArCoreInstallUtils, success); + } + } + + private void onArCoreRequestInstallReturned(Activity activity) { + try { + // Since |userRequestedInstall| parameter is false, the below call should + // throw if ARCore is still not installed - no need to check the result. + getArCoreShimInstance().requestInstall(activity, false); + maybeNotifyNativeOnRequestInstallSupportedArCoreResult(true); + } catch (ArCoreShim.UnavailableDeviceNotCompatibleException e) { + Log.w(TAG, "Exception thrown when trying to validate install state of ARCore: %s", + e.toString()); + maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false); + } catch (ArCoreShim.UnavailableUserDeclinedInstallationException e) { + maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false); + } + } + + /** + * This method should be called by the Activity that gets resumed. + * We are only interested in the cases where our current Activity got paused + * as a result of a call to ArCoreApk.requestInstall() method. + */ + public static void onResumeActivityWithNative(Activity activity) { + if (sRequestInstallInstance != null) { + sRequestInstallInstance.onArCoreRequestInstallReturned(activity); + sRequestInstallInstance = null; + } + } + + public static void installArCoreDeviceProviderFactory() { + ArCoreInstallUtilsJni.get().installArCoreDeviceProviderFactory(); + } + + @NativeMethods + /* package */ interface ArConsentPromptNative { + void onRequestInstallArModuleResult(long nativeArCoreConsentPrompt, boolean success); + void onRequestInstallSupportedArCoreResult(long nativeArCoreConsentPrompt, boolean success); + void installArCoreDeviceProviderFactory(); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java index ad81f10..8b8dc7c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
@@ -4,81 +4,31 @@ package org.chromium.chrome.browser.vr; -import android.app.Activity; import android.content.Context; import android.view.Surface; import dalvik.system.BaseDexClassLoader; -import org.chromium.base.BundleUtils; import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.StrictModeContext; import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; -import org.chromium.chrome.R; -import org.chromium.chrome.browser.infobar.InfoBarIdentifier; -import org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder; -import org.chromium.chrome.browser.modules.ModuleInstallUi; import org.chromium.chrome.browser.tab.Tab; -import org.chromium.components.module_installer.ModuleInstaller; /** * Provides ARCore classes access to java-related app functionality. */ @JNINamespace("vr") -public class ArCoreJavaUtils implements ModuleInstallUi.FailureUiListener { +public class ArCoreJavaUtils { private static final String TAG = "ArCoreJavaUtils"; private static final boolean DEBUG_LOGS = false; private long mNativeArCoreJavaUtils; - private boolean mAppInfoInitialized; - private Tab mTab; private ArImmersiveOverlay mArImmersiveOverlay; - // Instance that requested installation of ARCore. - // Should be non-null only if there is a pending request to install ARCore. - private static ArCoreJavaUtils sRequestInstallInstance; - - // Cached ArCoreShim instance - valid only after AR module was installed and - // getArCoreShimInstance() was called. - private static ArCoreShim sArCoreInstance; - - private static ArCoreShim getArCoreShimInstance() { - if (sArCoreInstance != null) return sArCoreInstance; - - try { - sArCoreInstance = - (ArCoreShim) Class.forName("org.chromium.chrome.browser.vr.ArCoreShimImpl") - .newInstance(); - } catch (ClassNotFoundException e) { - // shouldn't happen - we should only call this method once AR module is installed. - throw new RuntimeException(e); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - - return sArCoreInstance; - } - - public static void installArCoreDeviceProviderFactory() { - nativeInstallArCoreDeviceProviderFactory(); - } - - /** - * Gets the current application context. - * - * @return Context The application context. - */ - @CalledByNative - private static Context getApplicationContext() { - return ContextUtils.getApplicationContext(); - } - @CalledByNative private static ArCoreJavaUtils create(long nativeArCoreJavaUtils) { ThreadUtils.assertOnUiThread(); @@ -93,22 +43,19 @@ } } - @Override - public void onRetry() { - if (mNativeArCoreJavaUtils == 0) return; - requestInstallArModule(mTab); - } - - @Override - public void onCancel() { - if (mNativeArCoreJavaUtils == 0) return; - nativeOnRequestInstallArModuleResult(mNativeArCoreJavaUtils, /* success = */ false); + /** + * Gets the current application context. + * + * @return Context The application context. + */ + @CalledByNative + private static Context getApplicationContext() { + return ContextUtils.getApplicationContext(); } private ArCoreJavaUtils(long nativeArCoreJavaUtils) { if (DEBUG_LOGS) Log.i(TAG, "constructor, nativeArCoreJavaUtils=" + nativeArCoreJavaUtils); mNativeArCoreJavaUtils = nativeArCoreJavaUtils; - initializeAppInfo(); } @CalledByNative @@ -151,194 +98,6 @@ mNativeArCoreJavaUtils = 0; } - private void initializeAppInfo() { - mAppInfoInitialized = true; - - // Need to be called before trying to access the AR module. - ModuleInstaller.init(); - } - - private @ArCoreShim.Availability int getArCoreInstallStatus() { - return getArCoreShimInstance().checkAvailability(getApplicationContext()); - } - - @CalledByNative - private boolean shouldRequestInstallSupportedArCore() { - @ArCoreShim.Availability - int availability = getArCoreInstallStatus(); - // Skip ARCore installation if we are certain that it is already installed. - // In all other cases, we might as well try to install it and handle installation failures. - return availability != ArCoreShim.Availability.SUPPORTED_INSTALLED; - } - - @CalledByNative - private void requestInstallArModule(Tab tab) { - mTab = tab; - ModuleInstallUi ui = new ModuleInstallUi(mTab, R.string.ar_module_title, this); - ui.showInstallStartUi(); - ModuleInstaller.install("ar", success -> { - assert shouldRequestInstallArModule() != success; - - if (success) { - // As per documentation, it's recommended to issue a call to - // ArCoreApk.checkAvailability() early in application lifecycle & ignore the result - // so that subsequent calls can return cached result: - // https://developers.google.com/ar/develop/java/enable-arcore - // This is as early in the app lifecycle as it gets for us - just after installing - // AR module. - getArCoreInstallStatus(); - } - - if (mNativeArCoreJavaUtils != 0) { - if (success) { - ui.showInstallSuccessUi(); - nativeOnRequestInstallArModuleResult(mNativeArCoreJavaUtils, success); - } else { - ui.showInstallFailureUi(); - // early exit - user will be offered a choice to retry & install flow will - // continue from onRetry / onCancel - return; - } - } - }); - } - - @CalledByNative - private void requestInstallSupportedArCore(final Tab tab) { - assert shouldRequestInstallSupportedArCore(); - - @ArCoreShim.Availability - int arCoreAvailability = getArCoreInstallStatus(); - final Activity activity = tab.getActivity(); - String infobarText = null; - String buttonText = null; - switch (arCoreAvailability) { - case ArCoreShim.Availability.UNSUPPORTED_DEVICE_NOT_CAPABLE: - maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false); - break; - case ArCoreShim.Availability.UNKNOWN_CHECKING: - case ArCoreShim.Availability.UNKNOWN_ERROR: - case ArCoreShim.Availability.UNKNOWN_TIMED_OUT: - case ArCoreShim.Availability.SUPPORTED_NOT_INSTALLED: - infobarText = activity.getString(R.string.ar_core_check_infobar_install_text); - buttonText = activity.getString(R.string.app_banner_install); - break; - case ArCoreShim.Availability.SUPPORTED_APK_TOO_OLD: - infobarText = activity.getString(R.string.ar_core_check_infobar_update_text); - buttonText = activity.getString(R.string.update_from_market); - break; - case ArCoreShim.Availability.SUPPORTED_INSTALLED: - assert false; - break; - } - - SimpleConfirmInfoBarBuilder.Listener listener = new SimpleConfirmInfoBarBuilder.Listener() { - @Override - public void onInfoBarDismissed() { - maybeNotifyNativeOnRequestInstallSupportedArCoreResult( - !shouldRequestInstallSupportedArCore()); - } - - @Override - public boolean onInfoBarButtonClicked(boolean isPrimary) { - try { - assert sRequestInstallInstance == null; - @ArCoreShim.InstallStatus - int installStatus = getArCoreShimInstance().requestInstall(activity, true); - - if (installStatus == ArCoreShim.InstallStatus.INSTALL_REQUESTED) { - // Install flow will resume in onArCoreRequestInstallReturned, mark that - // there is active request. Native code notification will be deferred until - // our activity gets resumed. - sRequestInstallInstance = ArCoreJavaUtils.this; - } else if (installStatus == ArCoreShim.InstallStatus.INSTALLED) { - // No need to install - notify native code. - maybeNotifyNativeOnRequestInstallSupportedArCoreResult(true); - } - - } catch (ArCoreShim.UnavailableDeviceNotCompatibleException e) { - sRequestInstallInstance = null; - Log.w(TAG, "ARCore installation request failed with exception: %s", - e.toString()); - - maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false); - } catch (ArCoreShim.UnavailableUserDeclinedInstallationException e) { - maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false); - } - - return false; - } - - @Override - public boolean onInfoBarLinkClicked() { - return false; - } - }; - // TODO(ijamardo, https://crbug.com/838833): Add icon for AR info bar. - SimpleConfirmInfoBarBuilder.create(tab, listener, InfoBarIdentifier.AR_CORE_UPGRADE_ANDROID, - R.drawable.ic_error_outline_googblue_24dp, infobarText, buttonText, null, null, - true); - } - - @CalledByNative - private boolean canRequestInstallArModule() { - // We can only try to install the AR module if we are in a bundle mode. - return BundleUtils.isBundle(); - } - - @CalledByNative - private boolean shouldRequestInstallArModule() { - try { - // Try to find class in AR module that has not been obfuscated. - Class.forName("com.google.ar.core.ArCoreApk"); - return false; - } catch (ClassNotFoundException e) { - return true; - } - } - - private void onArCoreRequestInstallReturned(Activity activity) { - try { - // Since |userRequestedInstall| parameter is false, the below call should - // throw if ARCore is still not installed - no need to check the result. - getArCoreShimInstance().requestInstall(activity, false); - maybeNotifyNativeOnRequestInstallSupportedArCoreResult(true); - } catch (ArCoreShim.UnavailableDeviceNotCompatibleException e) { - Log.w(TAG, "Exception thrown when trying to validate install state of ARCore: %s", - e.toString()); - maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false); - } catch (ArCoreShim.UnavailableUserDeclinedInstallationException e) { - maybeNotifyNativeOnRequestInstallSupportedArCoreResult(false); - } - } - - /** - * This method should be called by the Activity that gets resumed. - * We are only interested in the cases where our current Activity got paused - * as a result of a call to ArCoreApk.requestInstall() method. - */ - public static void onResumeActivityWithNative(Activity activity) { - if (sRequestInstallInstance != null) { - sRequestInstallInstance.onArCoreRequestInstallReturned(activity); - sRequestInstallInstance = null; - } - } - - /** - * Helper used to notify native code about the result of the request to install ARCore. - */ - private void maybeNotifyNativeOnRequestInstallSupportedArCoreResult(boolean success) { - if (mNativeArCoreJavaUtils != 0) { - nativeOnRequestInstallSupportedArCoreResult(mNativeArCoreJavaUtils, success); - } - } - - private static native void nativeInstallArCoreDeviceProviderFactory(); - private native void nativeOnRequestInstallArModuleResult( - long nativeArCoreJavaUtils, boolean success); - private native void nativeOnRequestInstallSupportedArCoreResult( - long nativeArCoreJavaUtils, boolean success); - private native void nativeOnDrawingSurfaceReady( long nativeArCoreJavaUtils, Surface surface, int rotation, int width, int height); private native void nativeOnDrawingSurfaceTouch(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java index 9fc202e..500cb1c5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java
@@ -19,11 +19,11 @@ @Override public void init() { - ArCoreJavaUtils.installArCoreDeviceProviderFactory(); + ArCoreInstallUtils.installArCoreDeviceProviderFactory(); } @Override public void registerOnResumeActivity(Activity activity) { - ArCoreJavaUtils.onResumeActivityWithNative(activity); + ArCoreInstallUtils.onResumeActivityWithNative(activity); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java index d66d815..d1275006 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
@@ -110,6 +110,9 @@ @WebApkUpdateReason int updateReason = needsUpdate(mInfo, fetchedInfo, primaryIconUrl, badgeIconUrl); boolean needsUpgrade = (updateReason != WebApkUpdateReason.NONE); + if (mStorage.shouldForceUpdate() && needsUpgrade) { + updateReason = WebApkUpdateReason.MANUALLY_TRIGGERED; + } Log.i(TAG, "Got Manifest: " + gotManifest); Log.i(TAG, "WebAPK upgrade needed: " + needsUpgrade); @@ -130,7 +133,7 @@ } if (!needsUpgrade) { - if (!mStorage.didPreviousUpdateSucceed()) { + if (!mStorage.didPreviousUpdateSucceed() || mStorage.shouldForceUpdate()) { onFinishedUpdate(mStorage, WebApkInstallResult.SUCCESS, false /* relaxUpdates */); } return; @@ -178,18 +181,30 @@ /** Schedules update for when WebAPK is not running. */ private void scheduleUpdate() { WebApkUma.recordUpdateRequestQueued(1); + TaskInfo updateTask; + if (mStorage.shouldForceUpdate()) { + // Start an update task ASAP for forced updates. + updateTask = TaskInfo.createOneOffTask(TaskIds.WEBAPK_UPDATE_JOB_ID, + WebApkUpdateTask.class, 0 /* windowEndTimeMs */) + .setUpdateCurrent(true) + .setIsPersisted(true) + .build(); + mStorage.setUpdateScheduled(true); + mStorage.setShouldForceUpdate(false); + } else { + // The task deadline should be before {@link WebappDataStorage#RETRY_UPDATE_DURATION} + updateTask = + TaskInfo.createOneOffTask(TaskIds.WEBAPK_UPDATE_JOB_ID, WebApkUpdateTask.class, + DateUtils.HOUR_IN_MILLIS, DateUtils.HOUR_IN_MILLIS * 23) + .setRequiredNetworkType(TaskInfo.NetworkType.UNMETERED) + .setUpdateCurrent(true) + .setIsPersisted(true) + .setRequiresCharging(true) + .build(); + } - // The task deadline should be before {@link WebappDataStorage#RETRY_UPDATE_DURATION} - TaskInfo taskInfo = - TaskInfo.createOneOffTask(TaskIds.WEBAPK_UPDATE_JOB_ID, WebApkUpdateTask.class, - DateUtils.HOUR_IN_MILLIS, DateUtils.HOUR_IN_MILLIS * 23) - .setRequiredNetworkType(TaskInfo.NetworkType.UNMETERED) - .setUpdateCurrent(true) - .setIsPersisted(true) - .setRequiresCharging(true) - .build(); BackgroundTaskSchedulerFactory.getScheduler().schedule( - ContextUtils.getApplicationContext(), taskInfo); + ContextUtils.getApplicationContext(), updateTask); } /** Sends update request to the WebAPK Server. Should be called when WebAPK is not running. */ @@ -284,6 +299,8 @@ */ private static void onFinishedUpdate( WebappDataStorage storage, @WebApkInstallResult int result, boolean relaxUpdates) { + storage.setShouldForceUpdate(false); + storage.setUpdateScheduled(false); recordUpdate(storage, result, relaxUpdates); storage.deletePendingUpdateRequestFile(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java index 76d62c8..2a181020 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java
@@ -4,17 +4,15 @@ package org.chromium.chrome.browser.webapps; -import android.app.Activity; import android.content.Context; -import android.text.TextUtils; -import org.chromium.base.ApplicationStatus; import org.chromium.base.StrictModeContext; import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask; import org.chromium.components.background_task_scheduler.BackgroundTask.TaskFinishedCallback; import org.chromium.components.background_task_scheduler.TaskIds; import org.chromium.components.background_task_scheduler.TaskParameters; +import java.lang.ref.WeakReference; import java.util.List; /** @@ -41,7 +39,9 @@ List<String> ids = WebappRegistry.getInstance().findWebApksWithPendingUpdate(); for (String id : ids) { WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(id); - if (!isWebApkActivityRunning(storage.getWebApkPackageName())) { + WeakReference<WebappActivity> activity = + WebappActivity.findRunningWebappActivityWithId(storage.getId()); + if (activity == null || activity.get() == null) { mStorageToUpdate = storage; mMoreToUpdate = ids.size() > 1; return StartBeforeNativeResult.LOAD_NATIVE; @@ -79,19 +79,4 @@ @Override public void reschedule(Context context) {} - - /** Returns whether a WebApkActivity with {@link webApkPackageName} is running. */ - private static boolean isWebApkActivityRunning(String webApkPackageName) { - for (Activity activity : ApplicationStatus.getRunningActivities()) { - if (!(activity instanceof WebApkActivity)) { - continue; - } - WebApkActivity webApkActivity = (WebApkActivity) activity; - if (webApkActivity != null - && TextUtils.equals(webApkPackageName, webApkActivity.getWebApkPackageName())) { - return true; - } - } - return false; - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java index 09a30313..abfe27122 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -127,6 +127,21 @@ return null; } + /** Returns the WebappActivity with the given {@link webappId}. */ + public static WeakReference<WebappActivity> findRunningWebappActivityWithId(String webappId) { + for (Activity activity : ApplicationStatus.getRunningActivities()) { + if (!(activity instanceof WebappActivity)) { + continue; + } + WebappActivity webappActivity = (WebappActivity) activity; + if (webappActivity != null + && TextUtils.equals(webappId, webappActivity.getWebappInfo().id())) { + return new WeakReference<>(webappActivity); + } + } + return null; + } + /** * Construct all the variables that shouldn't change. We do it here both to clarify when the * objects are created and to ensure that they exist throughout the parallelized initialization
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java index b95b84c6..3228a615 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
@@ -77,6 +77,12 @@ // The path where serialized update data is written before uploading to the WebAPK server. static final String KEY_PENDING_UPDATE_FILE_PATH = "pending_update_file_path"; + // Whether to force an update. + static final String KEY_SHOULD_FORCE_UPDATE = "should_force_update"; + + // Whether an update has been scheduled. + static final String KEY_UPDATE_SCHEDULED = "update_scheduled"; + // Number of milliseconds between checks for whether the WebAPK's Web Manifest has changed. public static final long UPDATE_INTERVAL = DateUtils.DAY_IN_MILLIS; @@ -514,6 +520,33 @@ return mPreferences.getBoolean(KEY_RELAX_UPDATES, false); } + /** Sets whether an update has been scheduled. */ + public void setUpdateScheduled(boolean isUpdateScheduled) { + mPreferences.edit().putBoolean(KEY_UPDATE_SCHEDULED, isUpdateScheduled).apply(); + } + + /** Gets whether an update has been scheduled. */ + public boolean isUpdateScheduled() { + return mPreferences.getBoolean(KEY_UPDATE_SCHEDULED, false); + } + + /** Sets whether an update should be forced. */ + public void setShouldForceUpdate(boolean forceUpdate) { + mPreferences.edit().putBoolean(KEY_SHOULD_FORCE_UPDATE, forceUpdate).apply(); + } + + /** Whether to force an update. */ + public boolean shouldForceUpdate() { + return mPreferences.getBoolean(KEY_SHOULD_FORCE_UPDATE, false); + } + + /** Returns the update status. */ + public String getUpdateStatus() { + if (isUpdateScheduled()) return "Scheduled"; + if (shouldForceUpdate()) return "Pending"; + return didPreviousUpdateSucceed() ? "Succeeded" : "Failed"; + } + /** * Returns file where WebAPK update data should be stored and stores the file name in * SharedPreferences. @@ -556,6 +589,7 @@ /** Returns whether we should check for update. */ boolean shouldCheckForUpdate() { + if (shouldForceUpdate()) return true; long checkUpdatesInterval = shouldRelaxUpdates() ? RELAXED_UPDATE_INTERVAL : UPDATE_INTERVAL; long now = sClock.currentTimeMillis();
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index cadb698..0802da7 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1147,7 +1147,7 @@ <!-- Single site settings --> <message name="IDS_NO_SAVED_WEBSITE_SETTINGS" desc="Text to display when there are no saved website settings."> - You have no saved website settings. + No storage data here </message> <!-- Languages preferences --> @@ -1814,7 +1814,7 @@ <!-- Bluetooth Scanning Prompt strings --> <message name="IDS_BLUETOOTH_SCANNING_PROMPT_ORIGIN" desc="The label that is used to introduce Bluetooth scanning prompt details to the user when it is from a website."> - <ph name="SITE">%1$s<ex>www.google.com</ex></ph> wants to scan for nearby Bluetooth devices, the following devices have been found: + <ph name="SITE">%1$s<ex>www.google.com</ex></ph> wants to scan for nearby Bluetooth devices. The following devices have been found: </message> <message name="IDS_BLUETOOTH_SCANNING_DEVICE_UNKNOWN" desc="Text to identify Bluetooth devices of unknown or unsupported class."> Unknown or unsupported device (<ph name="DEVICE_ID">%1$s<ex>A1:B2:C3:D4:E5:F6</ex></ph>) @@ -2248,7 +2248,7 @@ <!-- Page info popup --> <message name="IDS_PAGE_INFO_SITE_SETTINGS_BUTTON" desc="Text in the button that opens a website's Site Settings from the Page Info dialog."> - Site Settings + Site settings </message> <message name="IDS_PAGE_INFO_INSTANT_APP_BUTTON" desc="Text in the button that opens an Android Instant app that is associated with the website's URL."> Open Instant App
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_NO_SAVED_WEBSITE_SETTINGS.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_NO_SAVED_WEBSITE_SETTINGS.png.sha1 new file mode 100644 index 0000000..4d3c5db --- /dev/null +++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_NO_SAVED_WEBSITE_SETTINGS.png.sha1
@@ -0,0 +1 @@ +61c67160243523857d934b35eb74acf104e05675 \ No newline at end of file
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index a1b751d..a860903c6 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -44,6 +44,7 @@ if (enable_arcore) { chrome_java_sources += [ + "java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java", "java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java", "java/src/org/chromium/chrome/browser/vr/ArDelegateImpl.java", "java/src/org/chromium/chrome/browser/vr/ArCoreShim.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderViewTest.java index 41879a7..00f0b40 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderViewTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderViewTest.java
@@ -43,6 +43,7 @@ private View mHeaderView; private TextView mTitle; private TextView mUrl; + private View mTitleAndUrl; private RoundedCornerImageView mImage; private View mCircleBg; private PropertyModel mModel; @@ -61,6 +62,7 @@ mHeaderView = getActivity().findViewById(android.R.id.content); mTitle = mHeaderView.findViewById(R.id.menu_header_title); mUrl = mHeaderView.findViewById(R.id.menu_header_url); + mTitleAndUrl = mHeaderView.findViewById(R.id.title_and_url); mImage = mHeaderView.findViewById(R.id.menu_header_image); mCircleBg = mHeaderView.findViewById(R.id.circle_background); }); @@ -131,8 +133,10 @@ @SmallTest @UiThreadTest public void testUrlClick() { + // Even though the click event expands/shrinks the url, the click target is the LinearLayout + // that contains the title and the url to give the user more area to touch. assertFalse("URL has onClickListeners when it shouldn't, yet, have.", - mUrl.hasOnClickListeners()); + mTitleAndUrl.hasOnClickListeners()); TestThreadUtils.runOnUiThreadBlocking(() -> { mModel.set(RevampedContextMenuHeaderProperties.URL, URL_STRING); @@ -146,14 +150,14 @@ RevampedContextMenuHeaderProperties.URL_MAX_LINES, Integer.MAX_VALUE); } }); - mUrl.callOnClick(); + mTitleAndUrl.callOnClick(); }); assertThat("Incorrect max line count for URL.", mUrl.getMaxLines(), equalTo(Integer.MAX_VALUE)); assertNull("URL is ellipsized when it shouldn't be.", mUrl.getEllipsize()); - TestThreadUtils.runOnUiThreadBlocking(() -> { mUrl.callOnClick(); }); + TestThreadUtils.runOnUiThreadBlocking(() -> { mTitleAndUrl.callOnClick(); }); assertThat("Incorrect max line count for URL.", mUrl.getMaxLines(), equalTo(URL_MAX_COUNT)); assertThat("Incorrect URL ellipsize mode.", mUrl.getEllipsize(),
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialogTest.java similarity index 98% rename from chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java rename to chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialogTest.java index 2904da0e..6d59149b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothChooserDialogTest.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.chrome.browser; +package org.chromium.chrome.browser.device_dialog; import android.Manifest; import android.app.Dialog; @@ -24,6 +24,8 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.RetryOnFailure; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.components.location.LocationUtils;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothScanningPermissionDialogTest.java similarity index 96% rename from chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java rename to chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothScanningPermissionDialogTest.java index 5d431fc..f984d86 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothScanningPermissionDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/BluetoothScanningPermissionDialogTest.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.chrome.browser; +package org.chromium.chrome.browser.device_dialog; import android.app.Dialog; import android.support.test.filters.LargeTest; @@ -20,6 +20,8 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.components.security_state.ConnectionSecurityLevel;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/ItemChooserDialogTest.java similarity index 99% rename from chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java rename to chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/ItemChooserDialogTest.java index 6dafc3af..c5986a6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/ItemChooserDialogTest.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.chrome.browser; +package org.chromium.chrome.browser.device_dialog; import android.app.Dialog; import android.graphics.drawable.Drawable; @@ -26,6 +26,8 @@ import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.RetryOnFailure; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.test.util.Criteria;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/OWNERS new file mode 100644 index 0000000..19c774f --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/OWNERS
@@ -0,0 +1 @@ +file://chrome/android/java/src/org/chromium/chrome/browser/device_dialog/OWNERS
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/UsbChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialogTest.java similarity index 97% rename from chrome/android/javatests/src/org/chromium/chrome/browser/UsbChooserDialogTest.java rename to chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialogTest.java index 69b47c943..4f40fb4 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/UsbChooserDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/device_dialog/UsbChooserDialogTest.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.chrome.browser; +package org.chromium.chrome.browser.device_dialog; import android.app.Dialog; import android.support.test.filters.LargeTest; @@ -19,6 +19,8 @@ import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.RetryOnFailure; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.components.security_state.ConnectionSecurityLevel;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandlerTest.java index 26714cd..a318f90c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandlerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandlerTest.java
@@ -257,6 +257,9 @@ public @ColorRes int getSecurityIconColorStateList() { return 0; } + + @Override + public void setShouldShowGoogleLogo(boolean shouldShowGoogleLogo) {} } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java index 3036629..127ae5b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java
@@ -94,6 +94,10 @@ // PaymentAppCreatedCallback @Override + public void onGetPaymentAppsError(String errorMessage) {} + + // PaymentAppCreatedCallback + @Override public void onAllPaymentAppsCreated() { mAllPaymentAppsCreated = true; }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java index 0b8aadd5..cb687dd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java
@@ -62,6 +62,7 @@ private boolean mDownloadPaymentMethodManifestSuccess; private boolean mDownloadWebAppManifestSuccess; private boolean mDownloadFailure; + private String mErrorMessage; private String mPaymentMethodManifest; private String mWebAppManifest; @@ -80,9 +81,10 @@ } @Override - public void onManifestDownloadFailure() { + public void onManifestDownloadFailure(String errorMessage) { mDownloadComplete = true; mDownloadFailure = true; + mErrorMessage = errorMessage; } @Before @@ -96,6 +98,7 @@ mDownloadPaymentMethodManifestSuccess = false; mDownloadWebAppManifestSuccess = false; mDownloadFailure = false; + mErrorMessage = ""; mPaymentMethodManifest = null; mWebAppManifest = null; } @@ -139,6 +142,8 @@ }); Assert.assertTrue("Web app manifest should not have been downloaded.", mDownloadFailure); + Assert.assertEquals( + "Unable to download payment manifest \"" + uri.toString() + "\".", mErrorMessage); } @Test @@ -174,6 +179,9 @@ Assert.assertTrue( "Payment method manifest should have not have been downloaded.", mDownloadFailure); + Assert.assertEquals("Unable to make a HEAD request to \"" + uri.toString() + + "\" for payment method manifest.", + mErrorMessage); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferencesTest.java index 9535cf9..558e913 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferencesTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill_assistant/AutofillAssistantPreferencesTest.java
@@ -23,7 +23,7 @@ import org.chromium.base.test.util.Feature; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.history.HistoryActivity; -import org.chromium.chrome.browser.preferences.ChromeSwitchPreference; +import org.chromium.chrome.browser.preferences.ChromeSwitchPreferenceCompat; import org.chromium.chrome.browser.preferences.MainPreferences; import org.chromium.chrome.browser.preferences.Preferences; import org.chromium.chrome.browser.preferences.PreferencesTest; @@ -85,15 +85,15 @@ TestThreadUtils.runOnUiThreadBlocking(() -> { AutofillAssistantPreferences autofillAssistantPrefs = - (AutofillAssistantPreferences) preferences.getMainFragment(); - ChromeSwitchPreference onOffSwitch = - (ChromeSwitchPreference) autofillAssistantPrefs.findPreference( + (AutofillAssistantPreferences) preferences.getMainFragmentCompat(); + ChromeSwitchPreferenceCompat onOffSwitch = + (ChromeSwitchPreferenceCompat) autofillAssistantPrefs.findPreference( AutofillAssistantPreferences.PREF_AUTOFILL_ASSISTANT_SWITCH); Assert.assertTrue(onOffSwitch.isChecked()); - PreferencesTest.clickPreference(autofillAssistantPrefs, onOffSwitch); + onOffSwitch.performClick(); Assert.assertFalse(getAutofillAssistantSwitch(true)); - PreferencesTest.clickPreference(autofillAssistantPrefs, onOffSwitch); + onOffSwitch.performClick(); Assert.assertTrue(getAutofillAssistantSwitch(false)); preferences.finish(); @@ -105,9 +105,9 @@ AutofillAssistantPreferences.class.getName()); TestThreadUtils.runOnUiThreadBlocking(() -> { AutofillAssistantPreferences autofillAssistantPrefs = - (AutofillAssistantPreferences) preferences2.getMainFragment(); - ChromeSwitchPreference onOffSwitch = - (ChromeSwitchPreference) autofillAssistantPrefs.findPreference( + (AutofillAssistantPreferences) preferences2.getMainFragmentCompat(); + ChromeSwitchPreferenceCompat onOffSwitch = + (ChromeSwitchPreferenceCompat) autofillAssistantPrefs.findPreference( AutofillAssistantPreferences.PREF_AUTOFILL_ASSISTANT_SWITCH); Assert.assertFalse(onOffSwitch.isChecked()); });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrDaydreamReadyModuleInstallTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrDaydreamReadyModuleInstallTest.java index 0d6109b..175f5dd5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrDaydreamReadyModuleInstallTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrDaydreamReadyModuleInstallTest.java
@@ -29,12 +29,17 @@ import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; import org.chromium.components.module_installer.ModuleInstaller; +import org.chromium.components.module_installer.ModuleInstallerRule; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.Callable; /** * End-to-end tests for installing the VR DFM on Daydream-ready phones on startup. + * + * TODO(agrieve): This test may be better as a robolectric test. */ @RunWith(ParameterizedRunner.class) @UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) @@ -48,12 +53,24 @@ @Rule public RuleChain mRuleChain; + private ModuleInstallerRule mModuleInstallerRule; + private ChromeActivityTestRule mVrTestRule; + private final Set<String> mModulesRequestedDeferred = new HashSet<>(); + public VrDaydreamReadyModuleInstallTest(Callable<ChromeActivityTestRule> callable) throws Exception { mVrTestRule = callable.call(); - mRuleChain = VrTestRuleUtils.wrapRuleInActivityRestrictionRule(mVrTestRule); + mModuleInstallerRule = new ModuleInstallerRule(new ModuleInstaller() { + @Override + public void installDeferred(String moduleName) { + mModulesRequestedDeferred.add(moduleName); + } + }); + mRuleChain = + RuleChain.outerRule(mModuleInstallerRule) + .around(VrTestRuleUtils.wrapRuleInActivityRestrictionRule(mVrTestRule)); } /** Tests that the install is requested deferred. */ @@ -62,8 +79,8 @@ @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL}) @Restriction({RESTRICTION_TYPE_DEVICE_DAYDREAM}) @VrModuleNotInstalled - public void testDeferredRequestOnStartup() throws InterruptedException { + public void testDeferredRequestOnStartup() { Assert.assertTrue("VR module should have been deferred installed at startup", - ModuleInstaller.didRequestDeferred("vr")); + mModulesRequestedDeferred.contains("vr")); } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/payments/PaymentManifestVerifierTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/payments/PaymentManifestVerifierTest.java index 3ac117c4..7d432e4 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/payments/PaymentManifestVerifierTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/payments/PaymentManifestVerifierTest.java
@@ -32,6 +32,8 @@ @RunWith(RobolectricTestRunner.class) @Config(sdk = 21, manifest = Config.NONE) public class PaymentManifestVerifierTest { + private static final String ERROR_MESSAGE = "This is an error message."; + private final URI mMethodName; private final ResolveInfo mAlicePay; private final ResolveInfo mBobPay; @@ -139,7 +141,7 @@ @Override public void downloadPaymentMethodManifest( URI uri, ManifestDownloadCallback callback) { - callback.onManifestDownloadFailure(); + callback.onManifestDownloadFailure(ERROR_MESSAGE); } @Override @@ -167,7 +169,7 @@ @Override public void downloadWebAppManifest(URI uri, ManifestDownloadCallback callback) { - callback.onManifestDownloadFailure(); + callback.onManifestDownloadFailure(ERROR_MESSAGE); } @Override @@ -288,7 +290,7 @@ @Override public void downloadWebAppManifest(URI uri, ManifestDownloadCallback callback) { if (mDownloadWebAppManifestCounter++ == 0) { - callback.onManifestDownloadFailure(); + callback.onManifestDownloadFailure(ERROR_MESSAGE); } else { callback.onWebAppManifestDownloadSuccess("some content"); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java index 7bd08e103..942de06 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
@@ -1094,4 +1094,68 @@ onGotManifestData(updateManager, defaultManifestData()); assertTrue(updateManager.updateRequested()); } + + /** + * Tests that a forced update is requested and performed immediately if there is a material + * change to the manifest. + */ + @Test + public void testForcedUpdateSuccess() throws Exception { + WebappDataStorage storage = getStorage(WEBAPK_PACKAGE_NAME); + storage.setShouldForceUpdate(true); + TestWebApkUpdateManager updateManager = new TestWebApkUpdateManager(storage); + updateIfNeeded(updateManager); + assertTrue(updateManager.updateCheckStarted()); + onGotDifferentData(updateManager); + assertTrue(updateManager.updateRequested()); + tryCompletingUpdate(updateManager, storage, WebApkInstallResult.SUCCESS); + assertEquals(false, storage.shouldForceUpdate()); + } + + /** + * Tests that a forced update is requested, but not performed if there is no material change to + * the manifest. + */ + @Test + public void testForcedUpdateNotNeeded() throws Exception { + WebappDataStorage storage = getStorage(WEBAPK_PACKAGE_NAME); + storage.setShouldForceUpdate(true); + TestWebApkUpdateManager updateManager = new TestWebApkUpdateManager(storage); + updateIfNeeded(updateManager); + assertTrue(updateManager.updateCheckStarted()); + onGotManifestData(updateManager, defaultManifestData()); + assertFalse(updateManager.updateRequested()); + assertEquals(false, storage.shouldForceUpdate()); + } + + /** + * Tests that a forced update handles failure gracefully. + */ + @Test + public void testForcedUpdateFailure() throws Exception { + WebappDataStorage storage = getStorage(WEBAPK_PACKAGE_NAME); + storage.setShouldForceUpdate(true); + TestWebApkUpdateManager updateManager = new TestWebApkUpdateManager(storage); + updateIfNeeded(updateManager); + assertTrue(updateManager.updateCheckStarted()); + onGotDifferentData(updateManager); + assertTrue(updateManager.updateRequested()); + tryCompletingUpdate(updateManager, storage, WebApkInstallResult.FAILURE); + assertEquals(false, storage.shouldForceUpdate()); + } + + /** + * Tests that a forced update handles failing to retrieve the manifest. + */ + @Test + public void testForcedUpdateManifestNotRetrieved() throws Exception { + WebappDataStorage storage = getStorage(WEBAPK_PACKAGE_NAME); + storage.setShouldForceUpdate(true); + TestWebApkUpdateManager updateManager = new TestWebApkUpdateManager(storage); + updateIfNeeded(updateManager); + assertTrue(updateManager.updateCheckStarted()); + onGotManifestData(updateManager, null); + assertFalse(updateManager.updateRequested()); + assertEquals(false, storage.shouldForceUpdate()); + } }
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index a295d15..6a82b52 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-77.0.3849.0_rc-r1-merged.afdo.bz2 \ No newline at end of file +chromeos-chrome-amd64-77.0.3850.0_rc-r1-merged.afdo.bz2 \ No newline at end of file
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java index ef04459..d3cd6e7 100644 --- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
@@ -241,8 +241,9 @@ Tab tab = getActivityTab(); if (tab == null || tab.getUrl() == null || tab.getUrl().isEmpty()) return; long time = SystemClock.elapsedRealtime(); - outState.putInt(BUNDLE_TAB_ID, tab.getId()); - TabState.saveState(outState, TabState.from(tab)); + if (TabState.saveState(outState, TabState.from(tab))) { + outState.putInt(BUNDLE_TAB_ID, tab.getId()); + } RecordHistogram.recordTimesHistogram("Android.StrictMode.NoTouchActivitySaveState", SystemClock.elapsedRealtime() - time); }
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessContextMenuManager.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessContextMenuManager.java index 1afba35..ceaf2212 100644 --- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessContextMenuManager.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessContextMenuManager.java
@@ -13,7 +13,6 @@ import org.chromium.chrome.browser.AppHooks; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.native_page.ContextMenuManager; -import org.chromium.chrome.browser.native_page.ContextMenuManager.ContextMenuItemId; import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate; import org.chromium.chrome.browser.touchless.dialog.TouchlessDialogProperties; import org.chromium.chrome.browser.touchless.dialog.TouchlessDialogProperties.ActionNames; @@ -63,6 +62,8 @@ private final ChromeActivity mActivity; private final ModalDialogManager mDialogManager; + // This field should be set when showing a dialog, and nulled out when the dialog is closed. We + // can check if it is null to determine whether we're currently showing our dialog. private PropertyModel mTouchlessMenuModel; private ModalDialogManager mModalDialogManager; @@ -84,6 +85,11 @@ */ public void showTouchlessContextMenu( ModalDialogManager modalDialogManager, ContextMenuManager.Delegate delegate) { + // Don't create a new dialog if we're already showing one. + if (mTouchlessMenuModel != null) { + return; + } + ArrayList<PropertyModel> menuItems = new ArrayList<>(); for (@ContextMenuItemId int itemId = 0; itemId < ContextMenuItemId.NUM_ENTRIES; itemId++) { if (!shouldShowItem(itemId, delegate)) continue; @@ -195,7 +201,9 @@ public void onClick(PropertyModel model, int buttonType) {} @Override - public void onDismiss(PropertyModel model, int dismissalCause) {} + public void onDismiss(PropertyModel model, int dismissalCause) { + mTouchlessMenuModel = null; + } }) .with(TouchlessDialogProperties.ACTION_NAMES, names) .with(TouchlessDialogProperties.CANCEL_ACTION, (v) -> closeTouchlessContextMenu())
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediator.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediator.java index 439993b..5c497ff 100644 --- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediator.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/progressbar/ProgressBarMediator.java
@@ -28,6 +28,7 @@ private boolean mSkipShowingOnNextActivityStart; private static final int MINIMUM_DISPLAY_DURATION_MS = 3 * 1000; + private static final int MAXIMUM_PROGRESS = 100; ProgressBarMediator(PropertyModel model, ActivityTabProvider activityTabProvider) { mProgressBarTabObserver = new ProgressBarTabObserver(activityTabProvider); @@ -73,11 +74,16 @@ show(); } - private void stopLoadProgress() { + private void finishLoadProgress() { mCanHideProgressBar = true; hide(); } + private void updateLoadProgress(int progress) { + mModel.set(ProgressBarProperties.PROGRESS_FRACTION, progress / ((float) MAXIMUM_PROGRESS)); + if (progress == MAXIMUM_PROGRESS) finishLoadProgress(); + } + void destroy() { if (mHideTask != null) mHideTask.cancel(false); mProgressBarTabObserver.destroy(); @@ -94,15 +100,23 @@ public void onDidStartNavigation(Tab tab, NavigationHandle navigation) { if (!navigation.isInMainFrame()) return; + if (tab.getWebContents() != null + && tab.getWebContents().getNavigationController() != null + && tab.getWebContents().getNavigationController().isInitialNavigation()) { + updateUrl(tab); + } + + if (navigation.isSameDocument()) return; + if (NativePageFactory.isNativePageUrl(navigation.getUrl(), tab.isIncognito())) { mModel.set(ProgressBarProperties.IS_ENABLED, false); - stopLoadProgress(); + finishLoadProgress(); return; } mModel.set(ProgressBarProperties.IS_ENABLED, true); - updateUrl(tab); startLoadProgress(); + updateLoadProgress(tab.getProgress()); } @Override @@ -117,15 +131,21 @@ @Override public void onLoadStopped(Tab tab, boolean toDifferentDocument) { - updateUrl(tab); - stopLoadProgress(); + if (!toDifferentDocument) return; + + // If we made some progress, fast-forward to complete. + if (tab.getProgress() < MAXIMUM_PROGRESS) { + updateLoadProgress(MAXIMUM_PROGRESS); + } else { + finishLoadProgress(); + } } @Override public void onLoadProgressChanged(Tab tab, int progress) { if (NativePageFactory.isNativePageUrl(tab.getUrl(), tab.isIncognito())) return; - mModel.set(ProgressBarProperties.PROGRESS_FRACTION, progress / 100f); + updateLoadProgress(progress); } @Override @@ -133,12 +153,12 @@ if (!didStartLoad) return; updateUrl(tab); - if (didFinishLoad) stopLoadProgress(); + if (didFinishLoad) finishLoadProgress(); } @Override public void onCrash(Tab tab) { - stopLoadProgress(); + finishLoadProgress(); } private void updateUrl(Tab tab) {
diff --git a/chrome/android/trichrome.gni b/chrome/android/trichrome.gni index 758f1ca..abefaaf 100644 --- a/chrome/android/trichrome.gni +++ b/chrome/android/trichrome.gni
@@ -49,6 +49,8 @@ "apk_name", "min_sdk_version", "proguard_jar_path", + "shared_resources_whitelist_target", + "shared_resources_whitelist_locales", "static_library_dependent_targets", "target_sdk_version", ]) @@ -59,8 +61,12 @@ no_build_hooks = true alternative_android_sdk_dep = webview_framework_dep - app_as_shared_lib = true - r_java_root_package_name = "trichrome_lib" + if (!trichrome_synchronized_proguard) { + # TODO(crbug.com/901465): Remove r_java_root_package_name once shared + # Java code is moved to the shared library even in debug. + r_java_root_package_name = "trichrome_lib" + app_as_shared_lib = true + } use_chromium_linker = false uncompress_shared_libraries = true uncompress_dex = use_uncompressed_dex
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index aeb27b76..2f1700b 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -9203,7 +9203,7 @@ No nearby devices found. </message> <message name="IDS_BLUETOOTH_SCANNING_PROMPT_ORIGIN" desc="The label that is used to introduce Bluetooth scanning prompt details to the user when it is from a website."> - <ph name="Origin">$1<ex>www.google.com</ex></ph> wants to scan for nearby Bluetooth devices, the following devices have been found: + <ph name="Origin">$1<ex>www.google.com</ex></ph> wants to scan for nearby Bluetooth devices. The following devices have been found: </message> <message name="IDS_BLUETOOTH_SCANNING_PROMPT_ALLOW_BUTTON_TEXT" desc="Label on the button that allows Bluetooth scanning." formatter_data="android_java"> Allow
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index a69266f..e404aef1 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -15,7 +15,7 @@ Languages and input </message> - <!-- Personalizaton Page (OS settings) --> + <!-- Personalization Page (OS settings) --> <message name="IDS_OS_SETTINGS_PERSONALIZATION" desc="Name of the OS settings page which displays personalization preferences."> Personalization </message> @@ -32,5 +32,10 @@ <message name="IDS_OS_SETTINGS_ASSISTANT" desc="Name of the settings section for the Google Assistant."> Assistant </message> + + <!-- Files Page (OS settings) --> + <message name="IDS_OS_SETTINGS_FILES" desc="Name of the settings page which displays file preferences."> + Files + </message> </if> </grit-part>
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index 1a4b27e..64705d8a 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -262,7 +262,7 @@ <structure type="chrome_scaled_image" name="IDR_LOGO_AVATAR_CIRCLE_BLUE_COLOR" file="cros/logo_avatar_circle_blue_color.png" /> <structure type="chrome_scaled_image" name="IDR_LOGO_GOOGLE_COLOR_90" file="cros/logo_google_color_90.png" /> </if> - <if expr="not_is_android"> + <if expr="not is_android"> <structure type="chrome_scaled_image" name="IDR_SUPERVISED_USER_THEME_FRAME" file="common/supervised_user_theme/theme_frame_supervised.png" /> <structure type="chrome_scaled_image" name="IDR_SUPERVISED_USER_THEME_FRAME_INACTIVE" file="common/supervised_user_theme/theme_frame_supervised_inactive.png" /> <structure type="chrome_scaled_image" name="IDR_SUPERVISED_USER_THEME_TAB_BACKGROUND" file="common/supervised_user_theme/theme_tab_background_supervised.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 3a7ca7f..3d7c37f 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -814,6 +814,8 @@ "native_file_system/chrome_native_file_system_permission_context.h", "native_file_system/native_file_system_permission_context_factory.cc", "native_file_system/native_file_system_permission_context_factory.h", + "native_file_system/native_file_system_permission_request_manager.cc", + "native_file_system/native_file_system_permission_request_manager.h", "native_window_notification_source.h", "navigation_predictor/navigation_predictor.cc", "navigation_predictor/navigation_predictor.h", @@ -1078,6 +1080,8 @@ "performance_manager/persistence/site_data/feature_usage.h", "performance_manager/persistence/site_data/leveldb_site_data_store.cc", "performance_manager/persistence/site_data/leveldb_site_data_store.h", + "performance_manager/persistence/site_data/non_recording_site_data_cache.cc", + "performance_manager/persistence/site_data/non_recording_site_data_cache.h", "performance_manager/persistence/site_data/noop_site_data_writer.cc", "performance_manager/persistence/site_data/noop_site_data_writer.h", "performance_manager/persistence/site_data/site_data_cache.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 3c73a70..aab04ed1 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2333,6 +2333,12 @@ flag_descriptions::kArcVpnDescription, kOsCrOS, FEATURE_VALUE_TYPE(arc::kVpnFeature)}, #endif // OS_CHROMEOS +#if defined(OS_WIN) + {"enable-winrt-sensor-implementation", + flag_descriptions::kWinrtSensorsImplementationName, + flag_descriptions::kWinrtSensorsImplementationDescription, kOsWin, + FEATURE_VALUE_TYPE(features::kWinrtSensorsImplementation)}, +#endif {"enable-generic-sensor", flag_descriptions::kEnableGenericSensorName, flag_descriptions::kEnableGenericSensorDescription, kOsAll, FEATURE_VALUE_TYPE(features::kGenericSensor)}, @@ -2503,6 +2509,11 @@ flag_descriptions::kOmniboxOnDeviceHeadSuggestionsName, flag_descriptions::kOmniboxOnDeviceHeadSuggestionsDescription, kOsAndroid, FEATURE_VALUE_TYPE(omnibox::kOnDeviceHeadProvider)}, + + {"omnibox-search-engine-logo", + flag_descriptions::kOmniboxSearchEngineLogoName, + flag_descriptions::kOmniboxSearchEngineLogoDescription, kOsAndroid, + FEATURE_VALUE_TYPE(omnibox::kOmniboxSearchEngineLogo)}, #endif // defined(OS_ANDROID) {"omnibox-rich-entity-suggestions", @@ -4093,6 +4104,10 @@ flag_descriptions::kEnableAutofillSaveCardShowNoThanksDescription, kOsAll, FEATURE_VALUE_TYPE(autofill::features::kAutofillSaveCardShowNoThanks)}, + {"enable-defer-all-script", flag_descriptions::kEnableDeferAllScriptName, + flag_descriptions::kEnableDeferAllScriptDescription, kOsAll, + FEATURE_VALUE_TYPE(previews::features::kDeferAllScriptPreviews)}, + // NOTE: Adding a new flag requires adding a corresponding entry to enum // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index 993cb504..1c52b61 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -208,6 +208,7 @@ &omnibox::kOmniboxRichEntitySuggestions, &omnibox::kQueryInOmnibox, &omnibox::kUIExperimentShowSuggestionFavicons, + &omnibox::kOmniboxSearchEngineLogo, &password_manager::features::kGooglePasswordManager, &password_manager::features::kPasswordEditingAndroid, &password_manager::features::kTouchToFillAndroid,
diff --git a/chrome/browser/android/find_in_page/find_in_page_bridge.cc b/chrome/browser/android/find_in_page/find_in_page_bridge.cc index 84b237df..6bcdff4 100644 --- a/chrome/browser/android/find_in_page/find_in_page_bridge.cc +++ b/chrome/browser/android/find_in_page/find_in_page_bridge.cc
@@ -7,6 +7,7 @@ #include "base/android/jni_string.h" #include "chrome/android/chrome_jni_headers/FindInPageBridge_jni.h" #include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "content/public/browser/web_contents.h" using base::android::ConvertUTF16ToJavaString; @@ -40,9 +41,9 @@ void FindInPageBridge::StopFinding(JNIEnv* env, const JavaParamRef<jobject>& obj, jboolean clearSelection) { - FindTabHelper::FromWebContents(web_contents_)-> - StopFinding(clearSelection ? FindBarController::kClearSelectionOnPage - : FindBarController::kKeepSelectionOnPage); + FindTabHelper::FromWebContents(web_contents_) + ->StopFinding(clearSelection ? FindOnPageSelectionAction::kClear + : FindOnPageSelectionAction::kKeep); } ScopedJavaLocalRef<jstring> FindInPageBridge::GetPreviousFindText(
diff --git a/chrome/browser/android/payments/service_worker_payment_app_bridge.cc b/chrome/browser/android/payments/service_worker_payment_app_bridge.cc index 5e44a549..656b87f 100644 --- a/chrome/browser/android/payments/service_worker_payment_app_bridge.cc +++ b/chrome/browser/android/payments/service_worker_payment_app_bridge.cc
@@ -59,9 +59,15 @@ const JavaRef<jobject>& jcallback, content::PaymentAppProvider::PaymentApps apps, payments::ServiceWorkerPaymentAppFactory::InstallablePaymentApps - installable_apps) { + installable_apps, + const std::string& error_message) { JNIEnv* env = AttachCurrentThread(); + if (!error_message.empty()) { + Java_ServiceWorkerPaymentAppBridge_onGetPaymentAppsError( + env, jcallback, ConvertUTF8ToJavaString(env, error_message)); + } + for (const auto& app_info : apps) { // Sends related application Ids to java side if the app prefers related // applications.
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc index 10704ea..4da3d1e 100644 --- a/chrome/browser/android/shortcut_helper.cc +++ b/chrome/browser/android/shortcut_helper.cc
@@ -358,6 +358,7 @@ const JavaParamRef<jobjectArray>& jnames, const JavaParamRef<jobjectArray>& jshort_names, const JavaParamRef<jobjectArray>& jpackage_names, + const JavaParamRef<jobjectArray>& jids, const JavaParamRef<jintArray>& jshell_apk_versions, const JavaParamRef<jintArray>& jversion_codes, const JavaParamRef<jobjectArray>& juris, @@ -369,7 +370,8 @@ const JavaParamRef<jlongArray>& jtheme_colors, const JavaParamRef<jlongArray>& jbackground_colors, const JavaParamRef<jlongArray>& jlast_update_check_times_ms, - const JavaParamRef<jbooleanArray>& jrelax_updates) { + const JavaParamRef<jbooleanArray>& jrelax_updates, + const JavaParamRef<jobjectArray>& jupdateStatuses) { DCHECK(jcallback_pointer); std::vector<std::string> names; base::android::AppendJavaStringArrayToStringVector(env, jnames, &names); @@ -379,6 +381,8 @@ std::vector<std::string> package_names; base::android::AppendJavaStringArrayToStringVector(env, jpackage_names, &package_names); + std::vector<std::string> ids; + base::android::AppendJavaStringArrayToStringVector(env, jids, &ids); std::vector<int> shell_apk_versions; base::android::JavaIntArrayToIntVector(env, jshell_apk_versions, &shell_apk_versions); @@ -409,9 +413,13 @@ std::vector<bool> relax_updates; base::android::JavaBooleanArrayToBoolVector(env, jrelax_updates, &relax_updates); + std::vector<std::string> update_statuses; + base::android::AppendJavaStringArrayToStringVector(env, jupdateStatuses, + &update_statuses); DCHECK(short_names.size() == names.size()); DCHECK(short_names.size() == package_names.size()); + DCHECK(short_names.size() == ids.size()); DCHECK(short_names.size() == shell_apk_versions.size()); DCHECK(short_names.size() == version_codes.size()); DCHECK(short_names.size() == uris.size()); @@ -424,21 +432,22 @@ DCHECK(short_names.size() == background_colors.size()); DCHECK(short_names.size() == last_update_check_times_ms.size()); DCHECK(short_names.size() == relax_updates.size()); + DCHECK(short_names.size() == update_statuses.size()); std::vector<WebApkInfo> webapk_list; webapk_list.reserve(short_names.size()); for (size_t i = 0; i < short_names.size(); ++i) { webapk_list.push_back(WebApkInfo( std::move(names[i]), std::move(short_names[i]), - std::move(package_names[i]), shell_apk_versions[i], version_codes[i], - std::move(uris[i]), std::move(scopes[i]), std::move(manifest_urls[i]), - std::move(manifest_start_urls[i]), + std::move(package_names[i]), std::move(ids[i]), shell_apk_versions[i], + version_codes[i], std::move(uris[i]), std::move(scopes[i]), + std::move(manifest_urls[i]), std::move(manifest_start_urls[i]), static_cast<blink::WebDisplayMode>(display_modes[i]), static_cast<blink::WebScreenOrientationLockType>(orientations[i]), JavaColorToOptionalSkColor(theme_colors[i]), JavaColorToOptionalSkColor(background_colors[i]), base::Time::FromJavaTime(last_update_check_times_ms[i]), - relax_updates[i])); + relax_updates[i], std::move(update_statuses[i]))); } ShortcutHelper::WebApkInfoCallback* webapk_list_callback = @@ -446,3 +455,9 @@ webapk_list_callback->Run(webapk_list); delete webapk_list_callback; } + +void ShortcutHelper::SetForceWebApkUpdate(const std::string& id) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_ShortcutHelper_setForceWebApkUpdate( + env, base::android::ConvertUTF8ToJavaString(env, id)); +}
diff --git a/chrome/browser/android/shortcut_helper.h b/chrome/browser/android/shortcut_helper.h index 3edc5160..126359a 100644 --- a/chrome/browser/android/shortcut_helper.h +++ b/chrome/browser/android/shortcut_helper.h
@@ -104,6 +104,10 @@ // the info to the |callback|. static void RetrieveWebApks(const WebApkInfoCallback& callback); + // Sets a flag to force an update for the WebAPK corresponding to |id| on next + // launch. + static void SetForceWebApkUpdate(const std::string& id); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(ShortcutHelper); };
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc index 54a9427..9936197 100644 --- a/chrome/browser/android/signin/signin_manager_android.cc +++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -11,12 +11,11 @@ #include "base/bind.h" #include "base/feature_list.h" #include "chrome/android/chrome_jni_headers/SigninManager_jni.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #include "components/signin/core/browser/primary_account_manager.h" #include "components/signin/public/base/account_consistency_method.h" +#include "components/signin/public/base/signin_client.h" #include "components/signin/public/base/signin_pref_names.h" #include "components/signin/public/identity_manager/primary_account_mutator.h" #include "google_apis/gaia/gaia_auth_util.h" @@ -25,28 +24,34 @@ namespace { // Clears the information about the last signed-in user from |profile|. -void ClearLastSignedInUserForProfile(Profile* profile) { - profile->GetPrefs()->ClearPref(prefs::kGoogleServicesLastAccountId); - profile->GetPrefs()->ClearPref(prefs::kGoogleServicesLastUsername); +void ClearLastSignedInUserForProfile(SigninClient* signin_client) { + signin_client->GetPrefs()->ClearPref(prefs::kGoogleServicesLastAccountId); + signin_client->GetPrefs()->ClearPref(prefs::kGoogleServicesLastUsername); } } // namespace SigninManagerAndroid::SigninManagerAndroid( - Profile* profile, + SigninClient* signin_client, + PrefService* local_state_pref_service, identity::IdentityManager* identity_manager, std::unique_ptr<SigninManagerDelegate> signin_manager_delegate) - : profile_(profile), + : signin_client_(signin_client), identity_manager_(identity_manager), signin_manager_delegate_(std::move(signin_manager_delegate)) { - DCHECK(profile_); + DCHECK(signin_client_); + DCHECK(local_state_pref_service); DCHECK(identity_manager_); DCHECK(signin_manager_delegate_); identity_manager_->AddObserver(this); - pref_change_registrar_.Init(profile_->GetPrefs()); - pref_change_registrar_.Add( - prefs::kSigninAllowed, + + signin_allowed_.Init( + prefs::kSigninAllowed, signin_client_->GetPrefs(), base::Bind(&SigninManagerAndroid::OnSigninAllowedPrefChanged, base::Unretained(this))); + + force_browser_signin_.Init(prefs::kForceBrowserSignin, + local_state_pref_service); + java_signin_manager_ = Java_SigninManager_create( base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this), signin_manager_delegate_->GetJavaObject(), @@ -98,7 +103,7 @@ void SigninManagerAndroid::ClearLastSignedInUser( JNIEnv* env, const JavaParamRef<jobject>& obj) { - ClearLastSignedInUserForProfile(profile_); + ClearLastSignedInUserForProfile(signin_client_); } void SigninManagerAndroid::LogInSignedInUser(JNIEnv* env, @@ -109,18 +114,20 @@ identity_manager_->LegacyReloadAccountsFromSystem(); } +bool SigninManagerAndroid::IsSigninAllowed() const { + return signin_allowed_.GetValue(); +} + jboolean SigninManagerAndroid::IsSigninAllowedByPolicy( JNIEnv* env, - const JavaParamRef<jobject>& obj) { - return profile_->GetPrefs()->GetBoolean(prefs::kSigninAllowed); + const JavaParamRef<jobject>& obj) const { + return IsSigninAllowed(); } jboolean SigninManagerAndroid::IsForceSigninEnabled( JNIEnv* env, const JavaParamRef<jobject>& obj) { - // prefs::kForceBrowserSignin is set in Local State, not in user prefs. - PrefService* prefs = g_browser_process->local_state(); - return prefs->GetBoolean(prefs::kForceBrowserSignin); + return force_browser_signin_.GetValue(); } jboolean SigninManagerAndroid::IsSignedInOnNative( @@ -136,10 +143,10 @@ java_signin_manager_); } -void SigninManagerAndroid::OnSigninAllowedPrefChanged() { +void SigninManagerAndroid::OnSigninAllowedPrefChanged() const { Java_SigninManager_onSigninAllowedByPolicyChanged( base::android::AttachCurrentThread(), java_signin_manager_, - profile_->GetPrefs()->GetBoolean(prefs::kSigninAllowed)); + IsSigninAllowed()); } base::android::ScopedJavaLocalRef<jstring> JNI_SigninManager_ExtractDomainName(
diff --git a/chrome/browser/android/signin/signin_manager_android.h b/chrome/browser/android/signin/signin_manager_android.h index 47de7dc..a03d97e 100644 --- a/chrome/browser/android/signin/signin_manager_android.h +++ b/chrome/browser/android/signin/signin_manager_android.h
@@ -13,9 +13,10 @@ #include "base/threading/thread_checker.h" #include "chrome/browser/android/signin/signin_manager_delegate.h" #include "components/prefs/pref_change_registrar.h" +#include "components/prefs/pref_member.h" #include "components/signin/public/identity_manager/identity_manager.h" -class Profile; +class SigninClient; // Android wrapper of Chrome's C++ identity management code which provides // access from the Java layer. Note that on Android, there's only a single @@ -28,7 +29,8 @@ class SigninManagerAndroid : public identity::IdentityManager::Observer { public: SigninManagerAndroid( - Profile* profile, + SigninClient* signin_client, + PrefService* local_state_prefs_service, identity::IdentityManager* identity_manager, std::unique_ptr<SigninManagerDelegate> signin_manager_delegate); @@ -56,7 +58,7 @@ jboolean IsSigninAllowedByPolicy( JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj); + const base::android::JavaParamRef<jobject>& obj) const; jboolean IsForceSigninEnabled( JNIEnv* env, @@ -70,9 +72,17 @@ const CoreAccountInfo& previous_primary_account_info) override; private: - void OnSigninAllowedPrefChanged(); + void OnSigninAllowedPrefChanged() const; + bool IsSigninAllowed() const; - Profile* profile_; + SigninClient* signin_client_; + + // Handler for prefs::kSigninAllowed set in user's profile. + BooleanPrefMember signin_allowed_; + + // Handler for prefs::kForceBrowserSignin. This preference is set in Local + // State, not in user prefs. + BooleanPrefMember force_browser_signin_; identity::IdentityManager* identity_manager_; @@ -81,8 +91,6 @@ // Java-side SigninManager object. base::android::ScopedJavaGlobalRef<jobject> java_signin_manager_; - PrefChangeRegistrar pref_change_registrar_; - base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(SigninManagerAndroid);
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc index 2449a42..4dc70e81 100644 --- a/chrome/browser/android/tab_web_contents_delegate_android.cc +++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -20,7 +20,6 @@ #include "chrome/browser/android/feature_utilities.h" #include "chrome/browser/android/hung_renderer_infobar_delegate.h" #include "chrome/browser/banners/app_banner_manager_android.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/content_settings/sound_content_setting_observer.h" #include "chrome/browser/file_select_helper.h" #include "chrome/browser/infobars/infobar_service.h" @@ -32,8 +31,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/resource_coordinator/tab_load_tracker.h" #include "chrome/browser/ssl/security_state_tab_helper.h" -#include "chrome/browser/ui/android/bluetooth_chooser_android.h" -#include "chrome/browser/ui/android/bluetooth_scanning_prompt_android.h" +#include "chrome/browser/ui/android/device_dialog/bluetooth_chooser_android.h" +#include "chrome/browser/ui/android/device_dialog/bluetooth_scanning_prompt_android.h" #include "chrome/browser/ui/android/infobars/framebust_block_infobar.h" #include "chrome/browser/ui/android/tab_model/tab_model_list.h" #include "chrome/browser/ui/blocked_content/popup_blocker.h" @@ -53,9 +52,6 @@ #include "components/security_state/content/content_utils.h" #include "content/public/browser/file_select_listener.h" #include "content/public/browser/navigation_entry.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_source.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" @@ -135,9 +131,7 @@ : WebContentsDelegateAndroid(env, obj) { } -TabWebContentsDelegateAndroid::~TabWebContentsDelegateAndroid() { - notification_registrar_.RemoveAll(); -} +TabWebContentsDelegateAndroid::~TabWebContentsDelegateAndroid() = default; void TabWebContentsDelegateAndroid::RunFileChooser( content::RenderFrameHost* render_frame_host, @@ -174,14 +168,9 @@ void TabWebContentsDelegateAndroid::CloseContents( WebContents* web_contents) { - // Prevent dangling registrations assigned to closed web contents. - if (notification_registrar_.IsRegistered(this, - chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, - content::Source<WebContents>(web_contents))) { - notification_registrar_.Remove(this, - chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, - content::Source<WebContents>(web_contents)); - } + FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(web_contents); + if (find_result_observer_.IsObserving(find_tab_helper)) + find_result_observer_.Remove(find_tab_helper); WebContentsDelegateAndroid::CloseContents(web_contents); } @@ -202,16 +191,6 @@ return false; } -void TabWebContentsDelegateAndroid::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK_EQ(chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, type); - OnFindResultAvailable( - content::Source<WebContents>(source).ptr(), - content::Details<FindNotificationDetails>(details).ptr()); -} - blink::WebDisplayMode TabWebContentsDelegateAndroid::GetDisplayMode( const WebContents* web_contents) { JNIEnv* env = base::android::AttachCurrentThread(); @@ -231,15 +210,10 @@ const gfx::Rect& selection_rect, int active_match_ordinal, bool final_update) { - if (!notification_registrar_.IsRegistered(this, - chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, - content::Source<WebContents>(web_contents))) { - notification_registrar_.Add(this, - chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, - content::Source<WebContents>(web_contents)); - } - FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(web_contents); + if (!find_result_observer_.IsObserving(find_tab_helper)) + find_result_observer_.Add(find_tab_helper); + find_tab_helper->HandleFindReply(request_id, number_of_matches, selection_rect, @@ -247,28 +221,6 @@ final_update); } -void TabWebContentsDelegateAndroid::OnFindResultAvailable( - WebContents* web_contents, - const FindNotificationDetails* find_result) { - JNIEnv* env = base::android::AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env); - if (obj.is_null()) - return; - - ScopedJavaLocalRef<jobject> selection_rect = - JNI_TabWebContentsDelegateAndroid_CreateJavaRect( - env, find_result->selection_rect()); - - // Create the details object. - ScopedJavaLocalRef<jobject> details_object = - Java_TabWebContentsDelegateAndroid_createFindNotificationDetails( - env, find_result->number_of_matches(), selection_rect, - find_result->active_match_ordinal(), find_result->final_update()); - - Java_TabWebContentsDelegateAndroid_onFindResultAvailable(env, obj, - details_object); -} - void TabWebContentsDelegateAndroid::FindMatchRectsReply( WebContents* web_contents, int version, @@ -508,6 +460,30 @@ } #endif +void TabWebContentsDelegateAndroid::OnFindResultAvailable( + WebContents* web_contents) { + JNIEnv* env = base::android::AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env); + if (obj.is_null()) + return; + + const FindNotificationDetails& find_result = + FindTabHelper::FromWebContents(web_contents)->find_result(); + + ScopedJavaLocalRef<jobject> selection_rect = + JNI_TabWebContentsDelegateAndroid_CreateJavaRect( + env, find_result.selection_rect()); + + // Create the details object. + ScopedJavaLocalRef<jobject> details_object = + Java_TabWebContentsDelegateAndroid_createFindNotificationDetails( + env, find_result.number_of_matches(), selection_rect, + find_result.active_match_ordinal(), find_result.final_update()); + + Java_TabWebContentsDelegateAndroid_onFindResultAvailable(env, obj, + details_object); +} + bool TabWebContentsDelegateAndroid::ShouldEnableEmbeddedMediaExperience() const { JNIEnv* env = base::android::AttachCurrentThread();
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.h b/chrome/browser/android/tab_web_contents_delegate_android.h index bf26bb54..bd8141e3 100644 --- a/chrome/browser/android/tab_web_contents_delegate_android.h +++ b/chrome/browser/android/tab_web_contents_delegate_android.h
@@ -6,15 +6,15 @@ #define CHROME_BROWSER_ANDROID_TAB_WEB_CONTENTS_DELEGATE_ANDROID_H_ #include "base/files/file_path.h" +#include "base/macros.h" +#include "base/scoped_observer.h" +#include "chrome/browser/ui/find_bar/find_result_observer.h" +#include "chrome/browser/ui/find_bar/find_tab_helper.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" #include "printing/buildflags/buildflags.h" #include "third_party/blink/public/common/frame/blocked_navigation_types.h" -class FindNotificationDetails; - namespace content { struct FileChooserParams; class WebContents; @@ -32,7 +32,7 @@ // the Chromium Android port but not to be shared with WebView. class TabWebContentsDelegateAndroid : public web_contents_delegate_android::WebContentsDelegateAndroid, - public content::NotificationObserver { + public FindResultObserver { public: TabWebContentsDelegateAndroid(JNIEnv* env, jobject obj); ~TabWebContentsDelegateAndroid() override; @@ -112,21 +112,18 @@ content::RenderFrameHost* subframe_host) const override; #endif + // FindResultObserver: + void OnFindResultAvailable(content::WebContents* web_contents) override; + bool ShouldEnableEmbeddedMediaExperience() const; bool IsPictureInPictureEnabled() const; bool IsNightModeEnabled() const; const GURL GetManifestScope() const; private: - // NotificationObserver implementation. - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; + ScopedObserver<FindTabHelper, FindResultObserver> find_result_observer_{this}; - void OnFindResultAvailable(content::WebContents* web_contents, - const FindNotificationDetails* find_result); - - content::NotificationRegistrar notification_registrar_; + DISALLOW_COPY_AND_ASSIGN(TabWebContentsDelegateAndroid); }; } // namespace android
diff --git a/chrome/browser/android/usb/web_usb_chooser_android.cc b/chrome/browser/android/usb/web_usb_chooser_android.cc index d715f49b..62f5c70 100644 --- a/chrome/browser/android/usb/web_usb_chooser_android.cc +++ b/chrome/browser/android/usb/web_usb_chooser_android.cc
@@ -7,7 +7,7 @@ #include <utility> #include "base/bind.h" -#include "chrome/browser/ui/android/usb_chooser_dialog_android.h" +#include "chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.h" #include "chrome/browser/usb/usb_chooser_controller.h" WebUsbChooserAndroid::WebUsbChooserAndroid(
diff --git a/chrome/browser/android/vr/BUILD.gn b/chrome/browser/android/vr/BUILD.gn index e17977b..d6c5c83 100644 --- a/chrome/browser/android/vr/BUILD.gn +++ b/chrome/browser/android/vr/BUILD.gn
@@ -83,9 +83,9 @@ "arcore_device/arcore_gl_thread.h", "arcore_device/arcore_impl.cc", "arcore_device/arcore_impl.h", - "arcore_device/arcore_install_utils.h", "arcore_device/arcore_java_utils.cc", "arcore_device/arcore_java_utils.h", + "arcore_device/arcore_session_utils.h", "arcore_device/arcore_shim.cc", "arcore_device/arcore_shim.h", "arcore_device/type_converters.cc", @@ -222,6 +222,7 @@ if (enable_arcore) { generate_jni("ar_jni_headers") { sources = [ + "//chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreInstallUtils.java", "//chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java", ] }
diff --git a/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.cc b/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.cc index b1fe89a5..5b368c01 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.cc
@@ -4,13 +4,17 @@ #include "chrome/browser/android/vr/arcore_device/arcore_consent_prompt.h" +#include <memory> #include <utility> #include "base/bind.h" #include "chrome/android/features/vr/jni_headers/ArConsentDialog_jni.h" #include "chrome/browser/android/tab_android.h" +#include "chrome/browser/android/vr/ar_jni_headers/ArCoreInstallUtils_jni.h" +#include "chrome/browser/android/vr/arcore_device/arcore_device_provider.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" +#include "device/vr/android/arcore/arcore_device_provider_factory.h" using base::android::AttachCurrentThread; using base::android::ScopedJavaLocalRef; @@ -19,7 +23,23 @@ namespace { -ArcoreConsentPrompt* g_instance = nullptr; +ArCoreConsentPrompt* g_instance = nullptr; + +class ArCoreDeviceProviderFactoryImpl + : public device::ArCoreDeviceProviderFactory { + public: + ArCoreDeviceProviderFactoryImpl() = default; + ~ArCoreDeviceProviderFactoryImpl() override = default; + std::unique_ptr<device::VRDeviceProvider> CreateDeviceProvider() override; + + private: + DISALLOW_COPY_AND_ASSIGN(ArCoreDeviceProviderFactoryImpl); +}; + +std::unique_ptr<device::VRDeviceProvider> +ArCoreDeviceProviderFactoryImpl::CreateDeviceProvider() { + return std::make_unique<device::ArCoreDeviceProvider>(); +} base::android::ScopedJavaLocalRef<jobject> GetTabFromRenderer( int render_process_id, @@ -44,42 +64,173 @@ } // namespace -ArcoreConsentPrompt::ArcoreConsentPrompt() = default; +ArCoreConsentPrompt::ArCoreConsentPrompt() : weak_ptr_factory_(this) {} -ArcoreConsentPrompt::~ArcoreConsentPrompt() = default; +ArCoreConsentPrompt::~ArCoreConsentPrompt() = default; -void ArcoreConsentPrompt::GetUserPermission( +void ArCoreConsentPrompt::GetUserPermission( int render_process_id, int render_frame_id, base::OnceCallback<void(bool)> response_callback) { on_user_consent_callback_ = std::move(response_callback); + render_process_id_ = render_process_id; + render_frame_id_ = render_frame_id; JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> jdelegate = Java_ArConsentDialog_showDialog( + jdelegate_ = Java_ArConsentDialog_showDialog( env, reinterpret_cast<jlong>(this), - GetTabFromRenderer(render_process_id, render_frame_id)); - if (jdelegate.is_null()) { + GetTabFromRenderer(render_process_id_, render_frame_id_)); + if (jdelegate_.is_null()) { std::move(on_user_consent_callback_).Run(false); } } -void ArcoreConsentPrompt::OnUserConsentResult( +void ArCoreConsentPrompt::OnUserConsentResult( JNIEnv* env, const base::android::JavaParamRef<jobject>& j_caller, jboolean is_granted) { - DCHECK(on_user_consent_callback_); - std::move(on_user_consent_callback_).Run(is_granted); + jdelegate_.Reset(); + + if (!on_user_consent_callback_) + return; + + if (!is_granted) { + CallDeferredUserConsentCallback(false); + return; + } + + RequestArModule(); } // static -void ArcoreConsentPrompt::ShowConsentPrompt( +void ArCoreConsentPrompt::ShowConsentPrompt( int render_process_id, int render_frame_id, base::OnceCallback<void(bool)> response_callback) { if (!g_instance) - g_instance = new ArcoreConsentPrompt(); + g_instance = new ArCoreConsentPrompt(); g_instance->GetUserPermission(render_process_id, render_frame_id, std::move(response_callback)); } +bool ArCoreConsentPrompt::CanRequestInstallArModule() { + return Java_ArCoreInstallUtils_canRequestInstallArModule( + AttachCurrentThread(), java_install_utils_); +} + +bool ArCoreConsentPrompt::ShouldRequestInstallArModule() { + return Java_ArCoreInstallUtils_shouldRequestInstallArModule( + AttachCurrentThread(), java_install_utils_); +} + +void ArCoreConsentPrompt::RequestInstallArModule() { + Java_ArCoreInstallUtils_requestInstallArModule( + AttachCurrentThread(), java_install_utils_, + GetTabFromRenderer(render_process_id_, render_frame_id_)); +} + +bool ArCoreConsentPrompt::ShouldRequestInstallSupportedArCore() { + JNIEnv* env = AttachCurrentThread(); + return Java_ArCoreInstallUtils_shouldRequestInstallSupportedArCore( + env, java_install_utils_); +} + +void ArCoreConsentPrompt::RequestInstallSupportedArCore() { + DCHECK(ShouldRequestInstallSupportedArCore()); + + JNIEnv* env = AttachCurrentThread(); + Java_ArCoreInstallUtils_requestInstallSupportedArCore( + env, java_install_utils_, + GetTabFromRenderer(render_process_id_, render_frame_id_)); +} + +void ArCoreConsentPrompt::OnRequestInstallArModuleResult( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + bool success) { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (on_request_ar_module_result_callback_) { + std::move(on_request_ar_module_result_callback_).Run(success); + } +} + +void ArCoreConsentPrompt::OnRequestInstallSupportedArCoreResult( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + bool success) { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(on_request_arcore_install_or_update_result_callback_); + + std::move(on_request_arcore_install_or_update_result_callback_).Run(success); +} + +void ArCoreConsentPrompt::RequestArModule() { + DVLOG(1) << __func__; + if (ShouldRequestInstallArModule()) { + if (!CanRequestInstallArModule()) { + OnRequestArModuleResult(false); + return; + } + + on_request_ar_module_result_callback_ = base::BindOnce( + &ArCoreConsentPrompt::OnRequestArModuleResult, GetWeakPtr()); + RequestInstallArModule(); + return; + } + + OnRequestArModuleResult(true); +} + +void ArCoreConsentPrompt::OnRequestArModuleResult(bool success) { + DVLOG(3) << __func__ << ": success=" << success; + + if (!success) { + CallDeferredUserConsentCallback(false); + return; + } + + RequestArCoreInstallOrUpdate(); +} + +void ArCoreConsentPrompt::RequestArCoreInstallOrUpdate() { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!on_request_arcore_install_or_update_result_callback_); + + if (ShouldRequestInstallSupportedArCore()) { + // ARCore is not installed or requires an update. Store the callback to be + // processed later once installation/update is complete or got cancelled. + on_request_arcore_install_or_update_result_callback_ = base::BindOnce( + &ArCoreConsentPrompt::OnRequestArCoreInstallOrUpdateResult, + GetWeakPtr()); + + RequestInstallSupportedArCore(); + return; + } + + OnRequestArCoreInstallOrUpdateResult(true); +} + +void ArCoreConsentPrompt::OnRequestArCoreInstallOrUpdateResult(bool success) { + DVLOG(1) << __func__; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + CallDeferredUserConsentCallback(success); +} + +void ArCoreConsentPrompt::CallDeferredUserConsentCallback( + bool is_permission_granted) { + if (on_user_consent_callback_) + std::move(on_user_consent_callback_).Run(is_permission_granted); +} + +static void JNI_ArCoreInstallUtils_InstallArCoreDeviceProviderFactory( + JNIEnv* env) { + device::ArCoreDeviceProviderFactory::Install( + std::make_unique<ArCoreDeviceProviderFactoryImpl>()); +} + } // namespace vr
diff --git a/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.h b/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.h index 257d5abc..3e24ec6 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.h +++ b/chrome/browser/android/vr/arcore_device/arcore_consent_prompt.h
@@ -7,21 +7,24 @@ #include "base/android/jni_android.h" #include "base/android/jni_weak_ref.h" +#include "base/android/scoped_java_ref.h" #include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "base/threading/thread_checker.h" #include "chrome/browser/vr/service/arcore_consent_prompt_interface.h" #include "chrome/browser/vr/vr_export.h" namespace vr { -class VR_EXPORT ArcoreConsentPrompt : public ArcoreConsentPromptInterface { +class VR_EXPORT ArCoreConsentPrompt : public ArCoreConsentPromptInterface { public: void ShowConsentPrompt( int render_process_id, int render_frame_id, base::OnceCallback<void(bool)> response_callback) override; - ArcoreConsentPrompt(); - ~ArcoreConsentPrompt(); + ArCoreConsentPrompt(); + ~ArCoreConsentPrompt(); // device::VrDevicePermissionProvider: void GetUserPermission(int render_process_id, @@ -32,8 +35,51 @@ const base::android::JavaParamRef<jobject>& j_caller, jboolean is_granted); + // Returns true if AR module installation is supported, false otherwise. + virtual bool CanRequestInstallArModule(); + // Returns true if AR module is not installed, false otherwise. + virtual bool ShouldRequestInstallArModule(); + virtual void RequestInstallArModule(); + virtual bool ShouldRequestInstallSupportedArCore(); + virtual void RequestInstallSupportedArCore(); + + // Called from Java end. + void OnRequestInstallArModuleResult( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + bool success); + void OnRequestInstallSupportedArCoreResult( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + bool success); + private: + void RequestArModule(); + void OnRequestArModuleResult(bool success); + void RequestArCoreInstallOrUpdate(); + void OnRequestArCoreInstallOrUpdateResult(bool success); + + void CallDeferredUserConsentCallback(bool is_permission_granted); + + base::WeakPtr<ArCoreConsentPrompt> GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); + } + base::OnceCallback<void(bool)> on_user_consent_callback_; + + base::OnceCallback<void(bool)> on_request_ar_module_result_callback_; + base::OnceCallback<void(bool)> + on_request_arcore_install_or_update_result_callback_; + + base::android::ScopedJavaLocalRef<jobject> jdelegate_; + int render_process_id_; + int render_frame_id_; + + base::android::ScopedJavaGlobalRef<jobject> java_install_utils_; + THREAD_CHECKER(thread_checker_); + + base::WeakPtrFactory<ArCoreConsentPrompt> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(ArCoreConsentPrompt); }; } // namespace vr
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device.cc b/chrome/browser/android/vr/arcore_device/arcore_device.cc index 535231c7..205e130c 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_device.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_device.cc
@@ -14,8 +14,8 @@ #include "chrome/browser/android/vr/arcore_device/arcore_gl.h" #include "chrome/browser/android/vr/arcore_device/arcore_gl_thread.h" #include "chrome/browser/android/vr/arcore_device/arcore_impl.h" -#include "chrome/browser/android/vr/arcore_device/arcore_install_utils.h" #include "chrome/browser/android/vr/arcore_device/arcore_java_utils.h" +#include "chrome/browser/android/vr/arcore_device/arcore_session_utils.h" #include "chrome/browser/android/vr/mailbox_to_surface_bridge.h" #include "chrome/browser/permissions/permission_manager.h" #include "chrome/browser/permissions/permission_result.h" @@ -74,13 +74,13 @@ std::unique_ptr<ArCoreFactory> arcore_factory, std::unique_ptr<ArImageTransportFactory> ar_image_transport_factory, std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_to_surface_bridge, - std::unique_ptr<vr::ArCoreInstallUtils> arcore_install_utils) + std::unique_ptr<vr::ArCoreSessionUtils> arcore_session_utils) : VRDeviceBase(mojom::XRDeviceId::ARCORE_DEVICE_ID), main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), arcore_factory_(std::move(arcore_factory)), ar_image_transport_factory_(std::move(ar_image_transport_factory)), mailbox_bridge_(std::move(mailbox_to_surface_bridge)), - arcore_install_utils_(std::move(arcore_install_utils)), + arcore_session_utils_(std::move(arcore_session_utils)), session_state_(std::make_unique<ArCoreDevice::SessionState>()), weak_ptr_factory_(this) { // Ensure display_info_ is set to avoid crash in CallDeferredSessionCallback @@ -97,25 +97,16 @@ } ArCoreDevice::ArCoreDevice() - : ArCoreDevice( - std::make_unique<ArCoreImplFactory>(), - std::make_unique<ArImageTransportFactory>(), - std::make_unique<vr::MailboxToSurfaceBridge>(), - std::make_unique<vr::ArCoreJavaUtils>( - base::BindRepeating( - &ArCoreDevice::OnRequestInstallArModuleResult, - base::Unretained(this)), // unretained is fine for callbacks - // since ArCoreDevice owns the - // ArCoreJavaUtils instance - base::BindRepeating( - &ArCoreDevice::OnRequestInstallSupportedArCoreResult, - base::Unretained(this)))) {} + : ArCoreDevice(std::make_unique<ArCoreImplFactory>(), + std::make_unique<ArImageTransportFactory>(), + std::make_unique<vr::MailboxToSurfaceBridge>(), + std::make_unique<vr::ArCoreJavaUtils>()) {} ArCoreDevice::~ArCoreDevice() { CallDeferredRequestSessionCallback(/*success=*/false); // The GL thread must be terminated since it uses our members. For example, // there might still be a posted Initialize() call in flight that uses - // arcore_install_utils_ and arcore_factory_. Ensure that the thread is + // arcore_session_utils_ and arcore_factory_. Ensure that the thread is // stopped before other members get destructed. Don't call Stop() here, // destruction calls Stop() and doing so twice is illegal (null pointer // dereference). @@ -190,15 +181,6 @@ void ArCoreDevice::RequestSessionAfterInitialization(int render_process_id, int render_frame_id) { - session_state_->start_immersive_activity_callback_ = - base::BindOnce(&ArCoreDevice::RequestArSessionConsent, GetWeakPtr(), - render_process_id, render_frame_id); - - RequestArModule(render_process_id, render_frame_id); -} - -void ArCoreDevice::RequestArSessionConsent(int render_process_id, - int render_frame_id) { auto ready_callback = base::BindRepeating(&ArCoreDevice::OnDrawingSurfaceReady, GetWeakPtr()); auto touch_callback = @@ -206,7 +188,7 @@ auto destroyed_callback = base::BindOnce(&ArCoreDevice::OnDrawingSurfaceDestroyed, GetWeakPtr()); - arcore_install_utils_->RequestArSession( + arcore_session_utils_->RequestArSession( render_process_id, render_frame_id, std::move(ready_callback), std::move(touch_callback), std::move(destroyed_callback)); } @@ -250,7 +232,7 @@ DVLOG(1) << __func__; // This may be a no-op in case it's destroyed already. - arcore_install_utils_->DestroyDrawingSurface(); + arcore_session_utils_->DestroyDrawingSurface(); // The GL thread had initialized its context with a drawing_widget based on // the ArImmersiveOverlay's Surface, and the one it has is no longer valid. @@ -276,88 +258,6 @@ mailbox_bridge_ = nullptr; } -void ArCoreDevice::RequestArModule(int render_process_id, int render_frame_id) { - DVLOG(1) << __func__; - if (arcore_install_utils_->ShouldRequestInstallArModule()) { - if (!arcore_install_utils_->CanRequestInstallArModule()) { - OnRequestArModuleResult(render_process_id, render_frame_id, false); - return; - } - - on_request_ar_module_result_callback_ = - base::BindOnce(&ArCoreDevice::OnRequestArModuleResult, GetWeakPtr(), - render_process_id, render_frame_id); - arcore_install_utils_->RequestInstallArModule(render_process_id, - render_frame_id); - return; - } - - OnRequestArModuleResult(render_process_id, render_frame_id, true); -} - -void ArCoreDevice::OnRequestArModuleResult(int render_process_id, - int render_frame_id, - bool success) { - DVLOG(3) << __func__ << ": success=" << success; - - if (!success) { - CallDeferredRequestSessionCallback(/*success=*/false); - return; - } - - RequestArCoreInstallOrUpdate(render_process_id, render_frame_id); -} - -void ArCoreDevice::RequestArCoreInstallOrUpdate(int render_process_id, - int render_frame_id) { - DVLOG(1) << __func__; - DCHECK(IsOnMainThread()); - DCHECK(!on_request_arcore_install_or_update_result_callback_); - - if (arcore_install_utils_->ShouldRequestInstallSupportedArCore()) { - // ARCore is not installed or requires an update. Store the callback to be - // processed later once installation/update is complete or got cancelled. - on_request_arcore_install_or_update_result_callback_ = base::BindOnce( - &ArCoreDevice::OnRequestArCoreInstallOrUpdateResult, GetWeakPtr()); - - arcore_install_utils_->RequestInstallSupportedArCore(render_process_id, - render_frame_id); - return; - } - - OnRequestArCoreInstallOrUpdateResult(true); -} - -void ArCoreDevice::OnRequestArCoreInstallOrUpdateResult(bool success) { - DVLOG(1) << __func__; - DCHECK(IsOnMainThread()); - - if (!success) { - CallDeferredRequestSessionCallback(/*success=*/false); - return; - } - - DCHECK(session_state_->start_immersive_activity_callback_); - std::move(session_state_->start_immersive_activity_callback_).Run(); -} - -void ArCoreDevice::OnRequestInstallArModuleResult(bool success) { - DVLOG(1) << __func__; - DCHECK(IsOnMainThread()); - - if (on_request_ar_module_result_callback_) { - std::move(on_request_ar_module_result_callback_).Run(success); - } -} - -void ArCoreDevice::OnRequestInstallSupportedArCoreResult(bool success) { - DVLOG(1) << __func__; - DCHECK(IsOnMainThread()); - DCHECK(on_request_arcore_install_or_update_result_callback_); - - std::move(on_request_arcore_install_or_update_result_callback_).Run(success); -} - void ArCoreDevice::CallDeferredRequestSessionCallback(bool success) { DVLOG(1) << __func__ << " success=" << success; DCHECK(IsOnMainThread()); @@ -430,7 +330,7 @@ DCHECK(IsOnMainThread()); DCHECK(session_state_->is_arcore_gl_thread_initialized_); - if (!arcore_install_utils_->EnsureLoaded()) { + if (!arcore_session_utils_->EnsureLoaded()) { DLOG(ERROR) << "ARCore was not loaded properly."; OnArCoreGlInitializationComplete(false); return; @@ -445,7 +345,7 @@ PostTaskToGlThread(base::BindOnce( &ArCoreGl::Initialize, session_state_->arcore_gl_thread_->GetArCoreGl()->GetWeakPtr(), - arcore_install_utils_.get(), arcore_factory_.get(), drawing_widget, + arcore_session_utils_.get(), arcore_factory_.get(), drawing_widget, frame_size, rotation, CreateMainThreadCallback(base::BindOnce( &ArCoreDevice::OnArCoreGlInitializationComplete, GetWeakPtr()))));
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device.h b/chrome/browser/android/vr/arcore_device/arcore_device.h index fc2560b..64a4e79 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_device.h +++ b/chrome/browser/android/vr/arcore_device/arcore_device.h
@@ -22,7 +22,7 @@ namespace vr { class MailboxToSurfaceBridge; -class ArCoreInstallUtils; +class ArCoreSessionUtils; } // namespace vr namespace device { @@ -37,7 +37,7 @@ std::unique_ptr<ArCoreFactory> arcore_factory, std::unique_ptr<ArImageTransportFactory> ar_image_transport_factory, std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_to_surface_bridge, - std::unique_ptr<vr::ArCoreInstallUtils> arcore_install_utils); + std::unique_ptr<vr::ArCoreSessionUtils> arcore_session_utils); ArCoreDevice(); ~ArCoreDevice() override; @@ -51,9 +51,6 @@ } private: - void OnRequestInstallArModuleResult(bool success); - void OnRequestInstallSupportedArCoreResult(bool success); - // VRDeviceBase implementation void OnMailboxBridgeReady(); void OnArCoreGlThreadInitialized(); @@ -102,7 +99,6 @@ int rotation, const gfx::Size& size); void OnArCoreGlInitializationComplete(bool success); - void RequestArSessionConsent(int render_process_id, int render_frame_id); void OnCreateSessionCallback( mojom::XRRuntime::RequestSessionCallback deferred_callback, @@ -115,7 +111,7 @@ std::unique_ptr<ArCoreFactory> arcore_factory_; std::unique_ptr<ArImageTransportFactory> ar_image_transport_factory_; std::unique_ptr<vr::MailboxToSurfaceBridge> mailbox_bridge_; - std::unique_ptr<vr::ArCoreInstallUtils> arcore_install_utils_; + std::unique_ptr<vr::ArCoreSessionUtils> arcore_session_utils_; // Encapsulates data with session lifetime. struct SessionState {
diff --git a/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc b/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc index cc514c7..72706d61 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_device_unittest.cc
@@ -11,9 +11,8 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "chrome/browser/android/vr/arcore_device/ar_image_transport.h" -#include "chrome/browser/android/vr/arcore_device/arcore_device.h" #include "chrome/browser/android/vr/arcore_device/arcore_gl.h" -#include "chrome/browser/android/vr/arcore_device/arcore_install_utils.h" +#include "chrome/browser/android/vr/arcore_device/arcore_session_utils.h" #include "chrome/browser/android/vr/arcore_device/fake_arcore.h" #include "chrome/browser/android/vr/mailbox_to_surface_bridge.h" #include "device/vr/public/mojom/vr_service.mojom.h" @@ -82,18 +81,10 @@ base::OnceClosure callback_; }; -class StubArCoreInstallUtils : public vr::ArCoreInstallUtils { +class StubArCoreSessionUtils : public vr::ArCoreSessionUtils { public: - StubArCoreInstallUtils() = default; + StubArCoreSessionUtils() = default; - bool CanRequestInstallArModule() override { return false; } - bool ShouldRequestInstallArModule() override { return false; } - - void RequestInstallArModule(int render_process_id, - int render_frame_id) override {} - bool ShouldRequestInstallSupportedArCore() override { return false; } - void RequestInstallSupportedArCore(int render_process_id, - int render_frame_id) override {} void RequestArSession( int render_process_id, int render_frame_id, @@ -148,7 +139,7 @@ } StubMailboxToSurfaceBridge* bridge; - StubArCoreInstallUtils* install_utils; + StubArCoreSessionUtils* session_utils; mojom::XRFrameDataProviderPtr frame_provider; mojom::XREnvironmentIntegrationProviderAssociatedPtr environment_provider; std::unique_ptr<base::RunLoop> run_loop; @@ -159,13 +150,13 @@ std::unique_ptr<StubMailboxToSurfaceBridge> bridge_ptr = std::make_unique<StubMailboxToSurfaceBridge>(); bridge = bridge_ptr.get(); - std::unique_ptr<StubArCoreInstallUtils> install_utils_ptr = - std::make_unique<StubArCoreInstallUtils>(); - install_utils = install_utils_ptr.get(); + std::unique_ptr<StubArCoreSessionUtils> session_utils_ptr = + std::make_unique<StubArCoreSessionUtils>(); + session_utils = session_utils_ptr.get(); device_ = std::make_unique<ArCoreDevice>( std::make_unique<FakeArCoreFactory>(), std::make_unique<StubArImageTransportFactory>(), std::move(bridge_ptr), - std::move(install_utils_ptr)); + std::move(session_utils_ptr)); } void CreateSession() { @@ -245,7 +236,7 @@ base::BindOnce(callback, &hit_results)); // Have to get frame data to trigger the hit-test calculation. GetFrameData(); - EXPECT_TRUE(hit_results.size() > 0); + EXPECT_FALSE(hit_results.empty()); } } // namespace device
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc index 1bfb8e0..a466b51 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -20,7 +20,7 @@ #include "base/trace_event/traced_value.h" #include "chrome/browser/android/vr/arcore_device/ar_image_transport.h" #include "chrome/browser/android/vr/arcore_device/arcore_impl.h" -#include "chrome/browser/android/vr/arcore_device/arcore_install_utils.h" +#include "chrome/browser/android/vr/arcore_device/arcore_session_utils.h" #include "chrome/browser/android/vr/web_xr_presentation_state.h" #include "device/vr/public/mojom/vr_service.mojom.h" #include "gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.h" @@ -119,7 +119,7 @@ CloseBindingsIfOpen(); } -void ArCoreGl::Initialize(vr::ArCoreInstallUtils* install_utils, +void ArCoreGl::Initialize(vr::ArCoreSessionUtils* session_utils, ArCoreFactory* arcore_factory, gfx::AcceleratedWidget drawing_widget, const gfx::Size& frame_size, @@ -141,7 +141,7 @@ // Get the activity context. base::android::ScopedJavaLocalRef<jobject> application_context = - install_utils->GetApplicationContext(); + session_utils->GetApplicationContext(); if (!application_context.obj()) { DLOG(ERROR) << "Unable to retrieve the Java context/activity!"; std::move(callback).Run(false);
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.h b/chrome/browser/android/vr/arcore_device/arcore_gl.h index 0e13a647..0121a4d8 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl.h +++ b/chrome/browser/android/vr/arcore_device/arcore_gl.h
@@ -36,7 +36,7 @@ } // namespace gl namespace vr { -class ArCoreInstallUtils; +class ArCoreSessionUtils; class WebXrPresentationState; } // namespace vr @@ -63,7 +63,7 @@ explicit ArCoreGl(std::unique_ptr<ArImageTransport> ar_image_transport); ~ArCoreGl() override; - void Initialize(vr::ArCoreInstallUtils* install_utils, + void Initialize(vr::ArCoreSessionUtils* session_utils, ArCoreFactory* arcore_factory, gfx::AcceleratedWidget drawing_widget, const gfx::Size& frame_size,
diff --git a/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc b/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc index 111e9a31..54392cd 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc
@@ -10,11 +10,9 @@ #include "base/android/jni_string.h" #include "chrome/browser/android/tab_android.h" #include "chrome/browser/android/vr/ar_jni_headers/ArCoreJavaUtils_jni.h" -#include "chrome/browser/android/vr/arcore_device/arcore_device_provider.h" #include "chrome/browser/android/vr/arcore_device/arcore_shim.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" -#include "device/vr/android/arcore/arcore_device_provider_factory.h" using base::android::AttachCurrentThread; using base::android::ScopedJavaLocalRef; @@ -23,29 +21,9 @@ namespace { -class ArCoreDeviceProviderFactoryImpl - : public device::ArCoreDeviceProviderFactory { - public: - ArCoreDeviceProviderFactoryImpl() = default; - ~ArCoreDeviceProviderFactoryImpl() override = default; - std::unique_ptr<device::VRDeviceProvider> CreateDeviceProvider() override; - - private: - DISALLOW_COPY_AND_ASSIGN(ArCoreDeviceProviderFactoryImpl); -}; - -std::unique_ptr<device::VRDeviceProvider> -ArCoreDeviceProviderFactoryImpl::CreateDeviceProvider() { - return std::make_unique<device::ArCoreDeviceProvider>(); -} - } // namespace -ArCoreJavaUtils::ArCoreJavaUtils( - base::RepeatingCallback<void(bool)> ar_module_installation_callback, - base::RepeatingCallback<void(bool)> ar_core_installation_callback) - : ar_module_installation_callback_(ar_module_installation_callback), - ar_core_installation_callback_(ar_core_installation_callback) { +ArCoreJavaUtils::ArCoreJavaUtils() { JNIEnv* env = AttachCurrentThread(); if (!env) return; @@ -61,46 +39,6 @@ Java_ArCoreJavaUtils_onNativeDestroy(env, j_arcore_java_utils_); } -void ArCoreJavaUtils::OnRequestInstallSupportedArCoreResult( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - bool success) { - ar_core_installation_callback_.Run(success); -} - -bool ArCoreJavaUtils::CanRequestInstallArModule() { - return Java_ArCoreJavaUtils_canRequestInstallArModule(AttachCurrentThread(), - j_arcore_java_utils_); -} - -bool ArCoreJavaUtils::ShouldRequestInstallArModule() { - return Java_ArCoreJavaUtils_shouldRequestInstallArModule( - AttachCurrentThread(), j_arcore_java_utils_); -} - -void ArCoreJavaUtils::RequestInstallArModule(int render_process_id, - int render_frame_id) { - Java_ArCoreJavaUtils_requestInstallArModule( - AttachCurrentThread(), j_arcore_java_utils_, - getTabFromRenderer(render_process_id, render_frame_id)); -} - -bool ArCoreJavaUtils::ShouldRequestInstallSupportedArCore() { - JNIEnv* env = AttachCurrentThread(); - return Java_ArCoreJavaUtils_shouldRequestInstallSupportedArCore( - env, j_arcore_java_utils_); -} - -void ArCoreJavaUtils::RequestInstallSupportedArCore(int render_process_id, - int render_frame_id) { - DCHECK(ShouldRequestInstallSupportedArCore()); - - JNIEnv* env = AttachCurrentThread(); - Java_ArCoreJavaUtils_requestInstallSupportedArCore( - env, j_arcore_java_utils_, - getTabFromRenderer(render_process_id, render_frame_id)); -} - void ArCoreJavaUtils::RequestArSession( int render_process_id, int render_frame_id, @@ -161,13 +99,6 @@ } } -void ArCoreJavaUtils::OnRequestInstallArModuleResult( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - bool success) { - ar_module_installation_callback_.Run(success); -} - bool ArCoreJavaUtils::EnsureLoaded() { DCHECK(vr::IsArCoreSupported()); @@ -206,10 +137,4 @@ return j_tab_android; } -static void JNI_ArCoreJavaUtils_InstallArCoreDeviceProviderFactory( - JNIEnv* env) { - device::ArCoreDeviceProviderFactory::Install( - std::make_unique<ArCoreDeviceProviderFactoryImpl>()); -} - } // namespace vr
diff --git a/chrome/browser/android/vr/arcore_device/arcore_java_utils.h b/chrome/browser/android/vr/arcore_device/arcore_java_utils.h index 5a5afe5..9e9ac15b 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_java_utils.h +++ b/chrome/browser/android/vr/arcore_device/arcore_java_utils.h
@@ -11,39 +11,26 @@ #include "base/android/scoped_java_ref.h" #include "base/callback.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/android/vr/arcore_device/arcore_install_utils.h" +#include "chrome/browser/android/vr/arcore_device/arcore_session_utils.h" namespace vr { -class ArCoreJavaUtils : public ArCoreInstallUtils { +class ArCoreJavaUtils : public ArCoreSessionUtils { public: - explicit ArCoreJavaUtils( - base::RepeatingCallback<void(bool)> ar_module_installation_callback, - base::RepeatingCallback<void(bool)> ar_core_installation_callback); + ArCoreJavaUtils(); ~ArCoreJavaUtils() override; - bool ShouldRequestInstallArModule() override; - bool CanRequestInstallArModule() override; - void RequestInstallArModule(int render_process_id, - int render_frame_id) override; - bool ShouldRequestInstallSupportedArCore() override; - void RequestInstallSupportedArCore(int render_process_id, - int render_frame_id) override; + + // ArCoreSessionUtils: void RequestArSession(int render_process_id, int render_frame_id, SurfaceReadyCallback ready_callback, SurfaceTouchCallback touch_callback, SurfaceDestroyedCallback destroyed_callback) override; void DestroyDrawingSurface() override; + bool EnsureLoaded() override; + base::android::ScopedJavaLocalRef<jobject> GetApplicationContext() override; // Methods called from the Java side. - void OnRequestInstallArModuleResult( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - bool success); - void OnRequestInstallSupportedArCoreResult( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - bool success); void OnDrawingSurfaceReady( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, @@ -60,17 +47,11 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); - bool EnsureLoaded() override; - base::android::ScopedJavaLocalRef<jobject> GetApplicationContext() override; - private: base::android::ScopedJavaLocalRef<jobject> getTabFromRenderer( int render_process_id, int render_frame_id); - base::RepeatingCallback<void(bool)> ar_module_installation_callback_; - base::RepeatingCallback<void(bool)> ar_core_installation_callback_; - base::android::ScopedJavaGlobalRef<jobject> j_arcore_java_utils_; SurfaceReadyCallback surface_ready_callback_;
diff --git a/chrome/browser/android/vr/arcore_device/arcore_install_utils.h b/chrome/browser/android/vr/arcore_device/arcore_session_utils.h similarity index 64% rename from chrome/browser/android/vr/arcore_device/arcore_install_utils.h rename to chrome/browser/android/vr/arcore_device/arcore_session_utils.h index f1156983..1573fbe4 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_install_utils.h +++ b/chrome/browser/android/vr/arcore_device/arcore_session_utils.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 CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_INSTALL_UTILS_H_ -#define CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_INSTALL_UTILS_H_ +#ifndef CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_SESSION_UTILS_H_ +#define CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_SESSION_UTILS_H_ #include "base/android/scoped_java_ref.h" #include "base/memory/weak_ptr.h" @@ -30,18 +30,9 @@ base::RepeatingCallback<void(bool touching, const gfx::PointF& location)>; using SurfaceDestroyedCallback = base::OnceClosure; -class ArCoreInstallUtils { +class ArCoreSessionUtils { public: - virtual ~ArCoreInstallUtils() = default; - // Returns true if AR module installation is supported, false otherwise. - virtual bool CanRequestInstallArModule() = 0; - // Returns true if AR module is not installed, false otherwise. - virtual bool ShouldRequestInstallArModule() = 0; - virtual void RequestInstallArModule(int render_process_id, - int render_frame_id) = 0; - virtual bool ShouldRequestInstallSupportedArCore() = 0; - virtual void RequestInstallSupportedArCore(int render_process_id, - int render_frame_id) = 0; + virtual ~ArCoreSessionUtils() = default; virtual bool EnsureLoaded() = 0; virtual base::android::ScopedJavaLocalRef<jobject> GetApplicationContext() = 0; @@ -56,4 +47,4 @@ } // namespace vr -#endif // CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_INSTALL_UTILS_H_ +#endif // CHROME_BROWSER_ANDROID_VR_ARCORE_DEVICE_ARCORE_SESSION_UTILS_H_
diff --git a/chrome/browser/android/vr/vr_module_provider.cc b/chrome/browser/android/vr/vr_module_provider.cc index 1004ae4..92abcf8 100644 --- a/chrome/browser/android/vr/vr_module_provider.cc +++ b/chrome/browser/android/vr/vr_module_provider.cc
@@ -88,7 +88,7 @@ static void JNI_VrModuleProvider_Init(JNIEnv* env) { GvrConsentHelper::SetInstance(std::make_unique<vr::GvrConsentHelperImpl>()); #if BUILDFLAG(ENABLE_ARCORE) - ArcoreConsentPromptInterface::SetInstance(new ArcoreConsentPrompt()); + ArCoreConsentPromptInterface::SetInstance(new ArCoreConsentPrompt()); #endif }
diff --git a/chrome/browser/android/webapk/webapk.proto b/chrome/browser/android/webapk/webapk.proto index 3afd167..e75cc63 100644 --- a/chrome/browser/android/webapk/webapk.proto +++ b/chrome/browser/android/webapk/webapk.proto
@@ -46,6 +46,7 @@ ORIENTATION_DIFFERS = 11; DISPLAY_MODE_DIFFERS = 12; WEB_SHARE_TARGET_DIFFERS = 13; + MANUALLY_TRIGGERED = 14; } // Package name of the WebAPK.
diff --git a/chrome/browser/android/webapk/webapk_info.cc b/chrome/browser/android/webapk/webapk_info.cc index 9c77db24..f2d36b59 100644 --- a/chrome/browser/android/webapk/webapk_info.cc +++ b/chrome/browser/android/webapk/webapk_info.cc
@@ -9,6 +9,7 @@ WebApkInfo::WebApkInfo(std::string name, std::string short_name, std::string package_name, + std::string id, int shell_apk_version, int version_code, std::string uri, @@ -20,10 +21,12 @@ base::Optional<SkColor> theme_color, base::Optional<SkColor> background_color, base::Time last_update_check_time, - bool relax_updates) + bool relax_updates, + std::string update_status) : name(std::move(name)), short_name(std::move(short_name)), package_name(std::move(package_name)), + id(std::move(id)), shell_apk_version(shell_apk_version), version_code(version_code), uri(std::move(uri)), @@ -35,7 +38,8 @@ theme_color(theme_color), background_color(background_color), last_update_check_time(last_update_check_time), - relax_updates(relax_updates) {} + relax_updates(relax_updates), + update_status(std::move(update_status)) {} WebApkInfo::~WebApkInfo() {}
diff --git a/chrome/browser/android/webapk/webapk_info.h b/chrome/browser/android/webapk/webapk_info.h index d2d8fb0..d035bb3 100644 --- a/chrome/browser/android/webapk/webapk_info.h +++ b/chrome/browser/android/webapk/webapk_info.h
@@ -23,6 +23,7 @@ WebApkInfo(std::string name, std::string short_name, std::string package_name, + std::string id, int shell_apk_version, int version_code, std::string uri, @@ -34,7 +35,8 @@ base::Optional<SkColor> theme_color, base::Optional<SkColor> background_color, base::Time last_update_check_time, - bool relax_updates); + bool relax_updates, + std::string update_status); ~WebApkInfo(); WebApkInfo& operator=(WebApkInfo&& other) noexcept; @@ -49,6 +51,9 @@ // Package name of the WebAPK. std::string package_name; + // Internal ID of the WebAPK. + std::string id; + // Shell APK version of the WebAPK. int shell_apk_version; @@ -66,6 +71,9 @@ base::Time last_update_check_time; bool relax_updates; + // Update Status of the WebAPK. + std::string update_status; + private: DISALLOW_COPY_AND_ASSIGN(WebApkInfo); };
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc index 004c369a..f27f3e5 100644 --- a/chrome/browser/android/webapk/webapk_installer.cc +++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -140,6 +140,8 @@ return webapk::WebApk::DISPLAY_MODE_DIFFERS; case WebApkUpdateReason::WEB_SHARE_TARGET_DIFFERS: return webapk::WebApk::WEB_SHARE_TARGET_DIFFERS; + case WebApkUpdateReason::MANUALLY_TRIGGERED: + return webapk::WebApk::MANUALLY_TRIGGERED; } }
diff --git a/chrome/browser/android/webapk/webapk_types.h b/chrome/browser/android/webapk/webapk_types.h index 5269faf0..73d202f9 100644 --- a/chrome/browser/android/webapk/webapk_types.h +++ b/chrome/browser/android/webapk/webapk_types.h
@@ -23,6 +23,7 @@ ORIENTATION_DIFFERS, DISPLAY_MODE_DIFFERS, WEB_SHARE_TARGET_DIFFERS, + MANUALLY_TRIGGERED, }; #endif // CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_TYPES_H_
diff --git a/chrome/browser/autofill/address_accessory_controller_impl.cc b/chrome/browser/autofill/address_accessory_controller_impl.cc index debb8e0..72aff540 100644 --- a/chrome/browser/autofill/address_accessory_controller_impl.cc +++ b/chrome/browser/autofill/address_accessory_controller_impl.cc
@@ -27,10 +27,7 @@ // Defines which types to load from the Personal data manager and add as field // to the address sheet. Order matters. constexpr ServerFieldType kTypesToInclude[] = { - // TODO(crbug.com/965494): Possibly, the names should be in a single chip. - ServerFieldType::NAME_FIRST, - ServerFieldType::NAME_MIDDLE, - ServerFieldType::NAME_LAST, + ServerFieldType::NAME_FULL, ServerFieldType::COMPANY_NAME, ServerFieldType::ADDRESS_HOME_LINE1, ServerFieldType::ADDRESS_HOME_LINE2,
diff --git a/chrome/browser/autofill/address_accessory_controller_impl_unittest.cc b/chrome/browser/autofill/address_accessory_controller_impl_unittest.cc index bbf7e26..b13d681 100644 --- a/chrome/browser/autofill/address_accessory_controller_impl_unittest.cc +++ b/chrome/browser/autofill/address_accessory_controller_impl_unittest.cc
@@ -114,9 +114,7 @@ result, AddressAccessorySheetDataBuilder(base::string16()) .AddUserInfo() - .AppendSimpleField(canadian.GetRawInfo(ServerFieldType::NAME_FIRST)) - .AppendSimpleField(canadian.GetRawInfo(ServerFieldType::NAME_MIDDLE)) - .AppendSimpleField(canadian.GetRawInfo(ServerFieldType::NAME_LAST)) + .AppendSimpleField(canadian.GetRawInfo(ServerFieldType::NAME_FULL)) .AppendSimpleField(canadian.GetRawInfo(ServerFieldType::COMPANY_NAME)) .AppendSimpleField( canadian.GetRawInfo(ServerFieldType::ADDRESS_HOME_LINE1)) @@ -163,11 +161,7 @@ personal_data_manager()->AddProfile(email); ASSERT_EQ(result, AddressAccessorySheetDataBuilder(base::string16()) .AddUserInfo() - /*name first:*/ - .AppendSimpleField(base::string16()) - /*name middle:*/ - .AppendSimpleField(base::string16()) - /*name last:*/ + /*name full:*/ .AppendSimpleField(base::string16()) /*company name:*/ .AppendSimpleField(base::string16())
diff --git a/chrome/browser/autofill/autofill_keyboard_accessory_adapter.cc b/chrome/browser/autofill/autofill_keyboard_accessory_adapter.cc index 4caa854..339addef 100644 --- a/chrome/browser/autofill/autofill_keyboard_accessory_adapter.cc +++ b/chrome/browser/autofill/autofill_keyboard_accessory_adapter.cc
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/memory/weak_ptr.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/autofill/autofill_popup_controller.h" #include "chrome/browser/ui/autofill/autofill_popup_layout_model.h" #include "components/autofill/core/browser/ui/popup_item_ids.h" @@ -17,6 +18,22 @@ namespace autofill { +constexpr base::char16 kLabelSeparator = ' '; +constexpr size_t kMaxBulletCount = 8; + +namespace { +base::string16 CreateLabel(const Suggestion& suggestion) { + base::string16 password = + suggestion.additional_label.substr(0, kMaxBulletCount); + // The label contains the signon_realm or is empty. The additional_label can + // never be empty since it must contain a password. + if (suggestion.label.empty()) + return password; + return suggestion.label + kLabelSeparator + password; +} + +} // namespace + AutofillKeyboardAccessoryAdapter::AutofillKeyboardAccessoryAdapter( AutofillPopupController* controller, unsigned int animation_duration_millis, @@ -49,12 +66,15 @@ DCHECK(controller_) << "Call OnSuggestionsChanged only from its owner!"; DCHECK(view_) << "OnSuggestionsChanged called before a View was set!"; + labels_.clear(); front_element_ = base::nullopt; for (int i = 0; i < GetLineCount(); ++i) { const Suggestion& suggestion = controller_->GetSuggestionAt(i); if (suggestion.frontend_id != POPUP_ITEM_ID_CLEAR_FORM && - suggestion.frontend_id != POPUP_ITEM_ID_CREATE_HINT) + suggestion.frontend_id != POPUP_ITEM_ID_CREATE_HINT) { + labels_.push_back(CreateLabel(suggestion)); continue; + } DCHECK(!front_element_.has_value()) << "Additional front item at: " << i; front_element_ = base::Optional<int>(i); } @@ -88,11 +108,7 @@ const base::string16& AutofillKeyboardAccessoryAdapter::GetElidedLabelAt( int row) const { DCHECK(controller_) << "Call OnSuggestionsChanged only from its owner!"; - const base::string16& label = - controller_->GetElidedLabelAt(OffsetIndexFor(row)); - if (label.empty()) - return GetSuggestionAt(row).additional_label; - return label; + return labels_[row]; } bool AutofillKeyboardAccessoryAdapter::GetRemovalConfirmationText(
diff --git a/chrome/browser/autofill/autofill_keyboard_accessory_adapter.h b/chrome/browser/autofill/autofill_keyboard_accessory_adapter.h index 8ad5806..c8b597d4 100644 --- a/chrome/browser/autofill/autofill_keyboard_accessory_adapter.h +++ b/chrome/browser/autofill/autofill_keyboard_accessory_adapter.h
@@ -100,6 +100,9 @@ AutofillPopupController* controller_; // weak. std::unique_ptr<AutofillKeyboardAccessoryAdapter::AccessoryView> view_; + // The labels to be used for the input chips. + std::vector<base::string16> labels_; + // If 0, don't animate suggestion view. const unsigned int animation_duration_millis_;
diff --git a/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc b/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc index 12ef283..cb78884 100644 --- a/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc +++ b/chrome/browser/autofill/autofill_keyboard_accessory_adapter_unittest.cc
@@ -5,6 +5,7 @@ #include <cstddef> #include <memory> +#include <string> #include <utility> #include <vector> @@ -51,13 +52,20 @@ DISALLOW_COPY_AND_ASSIGN(MockAccessoryView); }; +Suggestion createPasswordEntry(std::string password, + std::string username, + std::string psl_origin) { + Suggestion s(/*value=*/username, /*label=*/psl_origin, /*icon=*/"", + PopupItemId::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY); + s.additional_label = ASCIIToUTF16(password); + return s; +} + std::vector<Suggestion> createSuggestions() { std::vector<Suggestion> suggestions = { - Suggestion("*", "A", "", PopupItemId::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY), - Suggestion("**", "", "", PopupItemId::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY), - Suggestion("***", "C", "", - PopupItemId::POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY)}; - suggestions[1].additional_label = ASCIIToUTF16("B"); + createPasswordEntry("****************", "Alf", ""), + createPasswordEntry("****************", "Berta", "psl.origin.eg"), + createPasswordEntry("***", "Carl", "")}; return suggestions; } @@ -174,14 +182,19 @@ } TEST_F(AutofillKeyboardAccessoryAdapterTest, UseAdditionalLabelForElidedLabel) { - controller()->set_suggestions(createSuggestions()); + controller()->set_suggestions(createSuggestions(/*clearItemOffset=*/1)); NotifyAboutSuggestions(); - // If there is a label, use it. - EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(0), ASCIIToUTF16("A")); + // If there is a label, use it but cap at 8 bullets. + EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(0), + ASCIIToUTF16("********")); // If the label is empty, use the additional label: - EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(1), ASCIIToUTF16("B")); + EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(1), + ASCIIToUTF16("psl.origin.eg ********")); + + // If the password has less than 8 bullets, show the exact amount. + EXPECT_EQ(adapter_as_controller()->GetElidedLabelAt(2), ASCIIToUTF16("***")); } TEST_F(AutofillKeyboardAccessoryAdapterTest, ProvideReorderedSuggestions) {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index a8017edc..68ff588 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3515,6 +3515,9 @@ web_prefs->text_track_text_shadow = style->text_shadow; web_prefs->text_track_font_family = style->font_family; web_prefs->text_track_font_variant = style->font_variant; + web_prefs->text_track_window_color = style->window_color; + web_prefs->text_track_window_padding = style->window_padding; + web_prefs->text_track_window_radius = style->window_radius; } for (size_t i = 0; i < extra_parts_.size(); ++i)
diff --git a/chrome/browser/chrome_notification_types.h b/chrome/browser/chrome_notification_types.h index 9176955..763f2fa 100644 --- a/chrome/browser/chrome_notification_types.h +++ b/chrome/browser/chrome_notification_types.h
@@ -118,14 +118,6 @@ // the WebContents containing the NavigationController is destroyed. NOTIFICATION_TAB_CLOSING, - // Stuff inside the tabs --------------------------------------------------- - - // This notification is sent when the result of a find-in-page search is - // available with the browser process. The source is a Source<WebContents>. - // Details encompass a FindNotificationDetail object that tells whether the - // match was found or not found. - NOTIFICATION_FIND_RESULT_AVAILABLE, - // Authentication ---------------------------------------------------------- // This is sent when a login prompt is shown. The source is the
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 1ccbe0a7..104e5ff 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -736,6 +736,7 @@ "crostini/crostini_remover.h", "crostini/crostini_reporting_util.cc", "crostini/crostini_reporting_util.h", + "crostini/crostini_simple_types.h", "crostini/crostini_terminal.cc", "crostini/crostini_terminal.h", "crostini/crostini_util.cc", @@ -1256,12 +1257,12 @@ "login/reauth_stats.h", "login/saml/in_session_password_change_manager.cc", "login/saml/in_session_password_change_manager.h", + "login/saml/password_expiry_notification.cc", + "login/saml/password_expiry_notification.h", "login/saml/saml_offline_signin_limiter.cc", "login/saml/saml_offline_signin_limiter.h", "login/saml/saml_offline_signin_limiter_factory.cc", "login/saml/saml_offline_signin_limiter_factory.h", - "login/saml/saml_password_expiry_notification.cc", - "login/saml/saml_password_expiry_notification.h", "login/saml/saml_profile_prefs.cc", "login/saml/saml_profile_prefs.h", "login/screen_manager.cc", @@ -2514,8 +2515,9 @@ "login/quick_unlock/fingerprint_storage_unittest.cc", "login/quick_unlock/pin_storage_prefs_unittest.cc", "login/quick_unlock/quick_unlock_storage_unittest.cc", + "login/saml/in_session_password_change_manager_unittest.cc", + "login/saml/password_expiry_notification_unittest.cc", "login/saml/saml_offline_signin_limiter_unittest.cc", - "login/saml/saml_password_expiry_notification_unittest.cc", "login/screens/multidevice_setup_screen_unittest.cc", "login/screens/network_screen_unittest.cc", "login/screens/recommend_apps/recommend_apps_fetcher_impl_unittest.cc",
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h index 81f1716c..18d5739 100644 --- a/chrome/browser/chromeos/crostini/crostini_manager.h +++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -15,6 +15,7 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/optional.h" +#include "chrome/browser/chromeos/crostini/crostini_simple_types.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/component_updater/cros_component_installer_chromeos.h" #include "chrome/browser/ui/browser.h" @@ -29,137 +30,6 @@ namespace crostini { -// Result types for various callbacks etc. - -// WARNING: Do not remove or re-order these values, as they are used in user -// visible error messages and logs. New entries should only be added to the end. -// This message was added during development of M74, error codes from prior -// versions may differ from the numbering here. -enum class CrostiniResult { - SUCCESS = 0, - // DBUS_ERROR = 1, - // UNPARSEABLE_RESPONSE = 2, - // INSUFFICIENT_DISK = 3, - CREATE_DISK_IMAGE_FAILED = 4, - VM_START_FAILED = 5, - VM_STOP_FAILED = 6, - DESTROY_DISK_IMAGE_FAILED = 7, - LIST_VM_DISKS_FAILED = 8, - CLIENT_ERROR = 9, - // DISK_TYPE_ERROR = 10, - CONTAINER_DOWNLOAD_TIMED_OUT = 11, - CONTAINER_CREATE_CANCELLED = 12, - CONTAINER_CREATE_FAILED = 13, - CONTAINER_START_CANCELLED = 14, - CONTAINER_START_FAILED = 15, - // LAUNCH_CONTAINER_APPLICATION_FAILED = 16, - INSTALL_LINUX_PACKAGE_FAILED = 17, - BLOCKING_OPERATION_ALREADY_ACTIVE = 18, - UNINSTALL_PACKAGE_FAILED = 19, - // SSHFS_MOUNT_ERROR = 20, - OFFLINE_WHEN_UPGRADE_REQUIRED = 21, - LOAD_COMPONENT_FAILED = 22, - // PERMISSION_BROKER_ERROR = 23, - // ATTACH_USB_FAILED = 24, - // DETACH_USB_FAILED = 25, - // LIST_USB_FAILED = 26, - CROSTINI_UNINSTALLER_RUNNING = 27, - // UNKNOWN_USB_DEVICE = 28, - UNKNOWN_ERROR = 29, - CONTAINER_EXPORT_IMPORT_FAILED = 30, - CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED = 31, - CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED = 32, - CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE = 33, - NOT_ALLOWED = 34, - CONTAINER_EXPORT_IMPORT_FAILED_SPACE = 35, - GET_CONTAINER_SSH_KEYS_FAILED = 36, -}; - -enum class InstallLinuxPackageProgressStatus { - SUCCEEDED, - FAILED, - DOWNLOADING, - INSTALLING, -}; - -enum class VmState { - STARTING, - STARTED, - STOPPING, -}; - -enum class UninstallPackageProgressStatus { - SUCCEEDED, - FAILED, - UNINSTALLING, // In progress -}; - -// TODO(juwa): delete this once the new version of tremplin has shipped. -enum class ExportContainerProgressStatus { - // Deprecated. Has been replaced by STREAMING. - PACK, - // Deprecated. Has been replaced by STREAMING. - DOWNLOAD, - STREAMING, -}; - -enum class ImportContainerProgressStatus { - UPLOAD, - UNPACK, - FAILURE_ARCHITECTURE, - FAILURE_SPACE, -}; - -struct VmInfo { - VmState state; - vm_tools::concierge::VmInfo info; -}; - -struct StreamingExportStatus { - uint32_t total_files; - uint64_t total_bytes; - uint32_t exported_files; - uint64_t exported_bytes; -}; - -struct ContainerInfo { - ContainerInfo(std::string name, std::string username, std::string homedir); - ~ContainerInfo(); - ContainerInfo(const ContainerInfo&); - - std::string name; - std::string username; - base::FilePath homedir; - bool sshfs_mounted = false; -}; - -// Return type when getting app icons from within a container. -struct Icon { - std::string desktop_file_id; - - // Icon file content in PNG format. - std::string content; -}; - -struct LinuxPackageInfo { - LinuxPackageInfo(); - LinuxPackageInfo(const LinuxPackageInfo&); - ~LinuxPackageInfo(); - - bool success; - - // A textual reason for the failure, only set when success is false. - std::string failure_reason; - - // The remaining fields are only set when success is true. - // package_id is given as "name;version;arch;data". - std::string package_id; - std::string name; - std::string version; - std::string summary; - std::string description; -}; - class LinuxPackageOperationProgressObserver { public: // A successfully started package install will continually fire progress
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service.cc b/chrome/browser/chromeos/crostini/crostini_registry_service.cc index e017ce1..3e389a7 100644 --- a/chrome/browser/chromeos/crostini/crostini_registry_service.cc +++ b/chrome/browser/chromeos/crostini/crostini_registry_service.cc
@@ -18,6 +18,7 @@ #include "base/time/default_clock.h" #include "base/time/time.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/crostini/crostini_manager.h" #include "chrome/browser/chromeos/crostini/crostini_pref_names.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service.h b/chrome/browser/chromeos/crostini/crostini_registry_service.h index 4f4c2e8..6211d8a2 100644 --- a/chrome/browser/chromeos/crostini/crostini_registry_service.h +++ b/chrome/browser/chromeos/crostini/crostini_registry_service.h
@@ -15,7 +15,7 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/values.h" -#include "chrome/browser/chromeos/crostini/crostini_manager.h" +#include "chrome/browser/chromeos/crostini/crostini_simple_types.h" #include "components/keyed_service/core/keyed_service.h" #include "ui/base/resource/scale_factor.h"
diff --git a/chrome/browser/chromeos/crostini/crostini_simple_types.h b/chrome/browser/chromeos/crostini/crostini_simple_types.h new file mode 100644 index 0000000..b496414f9 --- /dev/null +++ b/chrome/browser/chromeos/crostini/crostini_simple_types.h
@@ -0,0 +1,152 @@ +// 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_CHROMEOS_CROSTINI_CROSTINI_SIMPLE_TYPES_H_ +#define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_SIMPLE_TYPES_H_ + +#include <string> + +#include "base/files/file_path.h" +#include "chromeos/dbus/concierge/service.pb.h" + +// This file contains simple C++ types (enums and Plain-Old-Data structs). +// Importantly, #include'ing this file will not depend on eventually executing +// "#include <dbus/dbus.h>", + +namespace crostini { + +// Result types for various callbacks etc. + +// WARNING: Do not remove or re-order these values, as they are used in user +// visible error messages and logs. New entries should only be added to the end. +// This message was added during development of M74, error codes from prior +// versions may differ from the numbering here. +enum class CrostiniResult { + SUCCESS = 0, + // DBUS_ERROR = 1, + // UNPARSEABLE_RESPONSE = 2, + // INSUFFICIENT_DISK = 3, + CREATE_DISK_IMAGE_FAILED = 4, + VM_START_FAILED = 5, + VM_STOP_FAILED = 6, + DESTROY_DISK_IMAGE_FAILED = 7, + LIST_VM_DISKS_FAILED = 8, + CLIENT_ERROR = 9, + // DISK_TYPE_ERROR = 10, + CONTAINER_DOWNLOAD_TIMED_OUT = 11, + CONTAINER_CREATE_CANCELLED = 12, + CONTAINER_CREATE_FAILED = 13, + CONTAINER_START_CANCELLED = 14, + CONTAINER_START_FAILED = 15, + // LAUNCH_CONTAINER_APPLICATION_FAILED = 16, + INSTALL_LINUX_PACKAGE_FAILED = 17, + BLOCKING_OPERATION_ALREADY_ACTIVE = 18, + UNINSTALL_PACKAGE_FAILED = 19, + // SSHFS_MOUNT_ERROR = 20, + OFFLINE_WHEN_UPGRADE_REQUIRED = 21, + LOAD_COMPONENT_FAILED = 22, + // PERMISSION_BROKER_ERROR = 23, + // ATTACH_USB_FAILED = 24, + // DETACH_USB_FAILED = 25, + // LIST_USB_FAILED = 26, + CROSTINI_UNINSTALLER_RUNNING = 27, + // UNKNOWN_USB_DEVICE = 28, + UNKNOWN_ERROR = 29, + CONTAINER_EXPORT_IMPORT_FAILED = 30, + CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED = 31, + CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED = 32, + CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE = 33, + NOT_ALLOWED = 34, + CONTAINER_EXPORT_IMPORT_FAILED_SPACE = 35, + GET_CONTAINER_SSH_KEYS_FAILED = 36, +}; + +enum class InstallLinuxPackageProgressStatus { + SUCCEEDED, + FAILED, + DOWNLOADING, + INSTALLING, +}; + +enum class VmState { + STARTING, + STARTED, + STOPPING, +}; + +enum class UninstallPackageProgressStatus { + SUCCEEDED, + FAILED, + UNINSTALLING, // In progress +}; + +// TODO(juwa): delete this once the new version of tremplin has shipped. +enum class ExportContainerProgressStatus { + // Deprecated. Has been replaced by STREAMING. + PACK, + // Deprecated. Has been replaced by STREAMING. + DOWNLOAD, + STREAMING, +}; + +enum class ImportContainerProgressStatus { + UPLOAD, + UNPACK, + FAILURE_ARCHITECTURE, + FAILURE_SPACE, +}; + +struct VmInfo { + VmState state; + vm_tools::concierge::VmInfo info; +}; + +struct StreamingExportStatus { + uint32_t total_files; + uint64_t total_bytes; + uint32_t exported_files; + uint64_t exported_bytes; +}; + +struct ContainerInfo { + ContainerInfo(std::string name, std::string username, std::string homedir); + ~ContainerInfo(); + ContainerInfo(const ContainerInfo&); + + std::string name; + std::string username; + base::FilePath homedir; + bool sshfs_mounted = false; +}; + +// Return type when getting app icons from within a container. +struct Icon { + std::string desktop_file_id; + + // Icon file content in PNG format. + std::string content; +}; + +struct LinuxPackageInfo { + LinuxPackageInfo(); + LinuxPackageInfo(const LinuxPackageInfo&); + ~LinuxPackageInfo(); + + bool success; + + // A textual reason for the failure, only set when success is false. + std::string failure_reason; + + // The remaining fields are only set when success is true. + // package_id is given as "name;version;arch;data". + std::string package_id; + std::string name; + std::string version; + std::string summary; + std::string description; +}; + +} // namespace crostini + +#endif // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_SIMPLE_TYPES_H_
diff --git a/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc b/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc index 9a8ea1f..51a3fb4 100644 --- a/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc +++ b/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/chrome_features.h" +#include "components/arc/arc_features.h" #include "dbus/bus.h" #include "dbus/message.h" #include "third_party/cros_system_api/dbus/service_constants.h" @@ -106,7 +107,10 @@ dbus::MethodCall* method_call, dbus::ExportedObject::ResponseSender response_sender) { static const base::Feature constexpr* kFeatureLookup[] = { - &features::kUsbbouncer, &features::kUsbguard}; + &features::kUsbbouncer, &features::kUsbguard, + &arc::kNativeBridgeExperimentFeature, &arc::kFilePickerExperimentFeature, + &arc::kCustomTabsExperimentFeature, &arc::kPrintSpoolerExperimentFeature, + }; dbus::MessageReader reader(method_call); std::string feature_name;
diff --git a/chrome/browser/chromeos/login/saml/in_session_password_change_manager.cc b/chrome/browser/chromeos/login/saml/in_session_password_change_manager.cc index 23602b9..62bd7de 100644 --- a/chrome/browser/chromeos/login/saml/in_session_password_change_manager.cc +++ b/chrome/browser/chromeos/login/saml/in_session_password_change_manager.cc
@@ -4,24 +4,85 @@ #include "chrome/browser/chromeos/login/saml/in_session_password_change_manager.h" +#include "ash/public/cpp/session/session_activation_observer.h" +#include "ash/public/cpp/session/session_controller.h" +#include "base/feature_list.h" +#include "base/task/post_task.h" +#include "base/task/task_traits.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part_chromeos.h" #include "chrome/browser/chromeos/login/auth/chrome_cryptohome_authenticator.h" -#include "chrome/browser/chromeos/login/saml/saml_password_expiry_notification.h" +#include "chrome/browser/chromeos/login/saml/password_expiry_notification.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chromeos/login/auth/user_context.h" #include "components/prefs/pref_service.h" #include "components/user_manager/user_manager.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" namespace chromeos { +namespace { + +InSessionPasswordChangeManager* g_test_instance = nullptr; + +// Traits for running RecheckPasswordExpiryTask. +// Runs from the UI thread to show notification. +const base::TaskTraits kRecheckTaskTraits = { + content::BrowserThread::UI, base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}; + +// A time delta of length one hour. +const base::TimeDelta kOneHour = base::TimeDelta::FromHours(1); + +// A time delta of length one day. +const base::TimeDelta kOneDay = base::TimeDelta::FromDays(1); + +// When the password will expire in |kUrgentWarningDays| or less, the +// UrgentPasswordExpiryNotification will be used - which is larger and actually +// a dialog (not a true notification) - instead of the normal notification. +const int kUrgentWarningDays = 3; + +} // namespace + +RecheckPasswordExpiryTask::RecheckPasswordExpiryTask() = default; + +RecheckPasswordExpiryTask::~RecheckPasswordExpiryTask() = default; + +void RecheckPasswordExpiryTask::Recheck() { + CancelPendingRecheck(); + InSessionPasswordChangeManager::Get()->MaybeShowExpiryNotification(); +} + +void RecheckPasswordExpiryTask::RecheckAfter(base::TimeDelta delay) { + CancelPendingRecheck(); + base::PostDelayedTaskWithTraits( + FROM_HERE, kRecheckTaskTraits, + base::BindOnce(&RecheckPasswordExpiryTask::Recheck, + weak_ptr_factory_.GetWeakPtr()), + std::max(delay, kOneHour)); + // This always waits at least one hour before calling Recheck again - we don't + // want some bug to cause this code to run every millisecond. +} + +void RecheckPasswordExpiryTask::CancelPendingRecheck() { + weak_ptr_factory_.InvalidateWeakPtrs(); +} + // static std::unique_ptr<InSessionPasswordChangeManager> InSessionPasswordChangeManager::CreateIfEnabled(Profile* primary_profile) { - if (primary_profile->GetPrefs()->GetBoolean( + if (base::FeatureList::IsEnabled(features::kInSessionPasswordChange) && + primary_profile->GetPrefs()->GetBoolean( prefs::kSamlInSessionPasswordChangeEnabled)) { - return std::make_unique<InSessionPasswordChangeManager>(primary_profile); + std::unique_ptr<InSessionPasswordChangeManager> manager = + std::make_unique<InSessionPasswordChangeManager>(primary_profile); + manager->MaybeShowExpiryNotification(); + return manager; } else { // If the policy is disabled, clear the SAML password attributes. SamlPasswordAttributes::DeleteFromPrefs(primary_profile->GetPrefs()); @@ -29,18 +90,120 @@ } } +// static +bool InSessionPasswordChangeManager::IsInitialized() { + return GetNullable(); +} + +// static +InSessionPasswordChangeManager* InSessionPasswordChangeManager::Get() { + InSessionPasswordChangeManager* result = GetNullable(); + CHECK(result); + return result; +} + InSessionPasswordChangeManager::InSessionPasswordChangeManager( Profile* primary_profile) : primary_profile_(primary_profile), primary_user_(ProfileHelper::Get()->GetUserByProfile(primary_profile)), - authenticator_(new ChromeCryptohomeAuthenticator(this)) { + authenticator_(new ChromeCryptohomeAuthenticator(this)), + urgent_warning_days_(kUrgentWarningDays) { DCHECK(primary_user_); + + // Add |this| as a SessionActivationObserver to see when the screen is locked. + auto* session_controller = ash::SessionController::Get(); + if (session_controller) { + session_controller->AddSessionActivationObserverForAccountId( + primary_user_->GetAccountId(), this); + } } -InSessionPasswordChangeManager::~InSessionPasswordChangeManager() {} +InSessionPasswordChangeManager::~InSessionPasswordChangeManager() { + // Remove |this| as a SessionActivationObserver. + auto* session_controller = ash::SessionController::Get(); + if (session_controller) { + session_controller->AddSessionActivationObserverForAccountId( + primary_user_->GetAccountId(), this); + } +} + +void InSessionPasswordChangeManager::MaybeShowExpiryNotification() { + // We are checking password expiry now, and this function will decide if we + // want to check again in the future, so for now, make sure there are no other + // pending tasks to check aggain. + recheck_task_.CancelPendingRecheck(); + + PrefService* prefs = primary_profile_->GetPrefs(); + if (!prefs->GetBoolean(prefs::kSamlInSessionPasswordChangeEnabled)) { + DismissExpiryNotification(); + return; + } + + SamlPasswordAttributes attrs = SamlPasswordAttributes::LoadFromPrefs(prefs); + if (!attrs.has_expiration_time()) { + DismissExpiryNotification(); + return; + } + + // Calculate how many days until the password will expire. + const base::TimeDelta time_until_expiry = + attrs.expiration_time() - base::Time::Now(); + const int less_than_n_days = + std::max(0, time_until_expiry.InDaysFloored() + 1); + const int advance_warning_days = std::max( + 0, prefs->GetInteger(prefs::kSamlPasswordExpirationAdvanceWarningDays)); + + if (less_than_n_days <= advance_warning_days) { + // The password is expired, or expires in less than |advance_warning_days|. + // So we show a notification immediately. + ShowExpiryNotification(less_than_n_days); + // We check again whether to reshow / update the notification after one day: + recheck_task_.RecheckAfter(kOneDay); + + } else { + // We have not yet reached the advance warning threshold. Check again + // once we have arrived at expiry_time minus advance_warning_days... + base::TimeDelta recheck_delay = + time_until_expiry - base::TimeDelta::FromDays(advance_warning_days); + // But, wait an extra hour so that when this code is next run, it is clear + // we are now inside advance_warning_days (and not right on the boundary). + recheck_delay += kOneHour; + recheck_task_.RecheckAfter(recheck_delay); + } +} + +void InSessionPasswordChangeManager::ShowExpiryNotification( + int less_than_n_days) { + // Show a notification, and reshow it each time the screen is unlocked. + renotify_on_unlock_ = true; + + less_than_n_days = std::max(0, less_than_n_days); + if (less_than_n_days < urgent_warning_days_) { + UrgentPasswordExpiryNotificationDialog::Show(less_than_n_days); + } else { + PasswordExpiryNotification::Show(primary_profile_, less_than_n_days); + } +} + +void InSessionPasswordChangeManager::DismissExpiryNotification() { + UrgentPasswordExpiryNotificationDialog::Dismiss(); + PasswordExpiryNotification::Dismiss(primary_profile_); +} + +void InSessionPasswordChangeManager::OnExpiryNotificationDismissedByUser() { + // When a notification is dismissed, we then don't pop it up again each time + // the user unlocks the screen. + renotify_on_unlock_ = false; +} + +void InSessionPasswordChangeManager::OnScreenUnlocked() { + if (renotify_on_unlock_) { + MaybeShowExpiryNotification(); + } +} void InSessionPasswordChangeManager::StartInSessionPasswordChange() { - UrgentPasswordExpiryNotificationDialog::Dismiss(); + DismissExpiryNotification(); PasswordChangeDialog::Show(primary_profile_); } @@ -86,6 +249,11 @@ observer_list_.RemoveObserver(observer); } +void InSessionPasswordChangeManager::OnAuthFailure(const AuthFailure& error) { + VLOG(1) << "Failed to change cryptohome password: " << error.GetErrorString(); + NotifyObservers(CHANGE_PASSWORD_AUTH_FAILURE); +} + void InSessionPasswordChangeManager::OnAuthSuccess( const UserContext& user_context) { VLOG(3) << "Cryptohome password is changed."; @@ -101,14 +269,38 @@ loaded.password_change_url()) .SaveToPrefs(primary_profile_->GetPrefs()); - DismissSamlPasswordExpiryNotification(primary_profile_); + DismissExpiryNotification(); PasswordChangeDialog::Dismiss(); ConfirmPasswordChangeDialog::Dismiss(); } -void InSessionPasswordChangeManager::OnAuthFailure(const AuthFailure& error) { - VLOG(1) << "Failed to change cryptohome password: " << error.GetErrorString(); - NotifyObservers(CHANGE_PASSWORD_AUTH_FAILURE); +void InSessionPasswordChangeManager::OnSessionActivated(bool activated) { + // Not needed. +} + +void InSessionPasswordChangeManager::OnLockStateChanged(bool locked) { + if (!locked) { + OnScreenUnlocked(); + } +} + +// static +InSessionPasswordChangeManager* InSessionPasswordChangeManager::GetNullable() { + return g_test_instance ? g_test_instance + : g_browser_process->platform_part() + ->in_session_password_change_manager(); +} + +// static +void InSessionPasswordChangeManager::SetForTesting( + InSessionPasswordChangeManager* instance) { + CHECK(!g_test_instance); + g_test_instance = instance; +} + +// static +void InSessionPasswordChangeManager::ResetForTesting() { + g_test_instance = nullptr; } void InSessionPasswordChangeManager::NotifyObservers(Event event) {
diff --git a/chrome/browser/chromeos/login/saml/in_session_password_change_manager.h b/chrome/browser/chromeos/login/saml/in_session_password_change_manager.h index 041fe69..ba9ba83 100644 --- a/chrome/browser/chromeos/login/saml/in_session_password_change_manager.h +++ b/chrome/browser/chromeos/login/saml/in_session_password_change_manager.h
@@ -8,6 +8,7 @@ #include <memory> #include <string> +#include "ash/public/cpp/session/session_activation_observer.h" #include "base/memory/scoped_refptr.h" #include "base/observer_list.h" #include "chromeos/login/auth/auth_status_consumer.h" @@ -22,9 +23,42 @@ class CryptohomeAuthenticator; class UserContext; +// There is at most one instance of this task, which is part of the +// InSessionPasswordChangeManager singleton. Having a separate class means that +// pointers to this class can be invalidated without affecting the manager. +// Calling Recheck or RecheckAfter invalidates the existing pointers before +// rerunning the task or posting the task to be re-run, which means that there +// is only ever one of task that is scheduled to be run. +class RecheckPasswordExpiryTask { + private: + RecheckPasswordExpiryTask(); + ~RecheckPasswordExpiryTask(); + + // Delegates to InSessionPasswordChangeManager::MaybeShowExpiryNotification. + void Recheck(); + + // Calls Recheck after the given |delay|. + void RecheckAfter(base::TimeDelta delay); + + // Cancels any pending calls to Recheck that are scheduled.. + void CancelPendingRecheck(); + + base::WeakPtrFactory<RecheckPasswordExpiryTask> weak_ptr_factory_{this}; + + // Only InSessionPasswordChangeManager can use this class. + friend class InSessionPasswordChangeManager; + + DISALLOW_COPY_AND_ASSIGN(RecheckPasswordExpiryTask); +}; + // Manages the flow of changing a password in-session - handles user // response from dialogs, and callbacks from subsystems. -class InSessionPasswordChangeManager : public AuthStatusConsumer { +// This singleton is scoped to the primary user session - it will exist for as +// long as the primary user session exists (but only if the primary user's +// InSessionPasswordChange policy is enabled and the kInSessionPasswordChange +// feature is enabled). +class InSessionPasswordChangeManager : public AuthStatusConsumer, + public ash::SessionActivationObserver { public: // Events in the in-session SAML password change flow. enum Event { @@ -42,9 +76,40 @@ static std::unique_ptr<InSessionPasswordChangeManager> CreateIfEnabled( Profile* primary_profile); + // Returns true if the InSessionPasswordChangeManager is both enabled and + // ready, so Get() can safely be called. + static bool IsInitialized(); + + // Checks that the InSessionPasswordChangeManager is both enabled and ready, + // then returns it. + static InSessionPasswordChangeManager* Get(); + explicit InSessionPasswordChangeManager(Profile* primary_profile); ~InSessionPasswordChangeManager() override; + // Checks if the primary user's password has expired or will soon expire, and + // shows a notification if needed. If the password will expire in the distant + // future, posts a task to check again in the distant future. + void MaybeShowExpiryNotification(); + + // Shows a password expiry notification. |less_than_n_days| should be 1 if the + // password expires in less than 1 day, 0 if it has already expired, etc. + // Negative numbers are treated the same as zero. + void ShowExpiryNotification(int less_than_n_days); + + // Dismiss password expiry notification and dismiss urgent password expiry + // notification, if either are shown. + void DismissExpiryNotification(); + + // User dismissed a notification - make sure not to show it again immediately, + // even if the password is still scheduled to expire soon. + void OnExpiryNotificationDismissedByUser(); + + // When the screen is unlocked, password expiry notifications are reshown (if + // they are not already dismissed). On each unlock, the notification pops + // out of the system tray and is visible on screen again for a few seconds. + void OnScreenUnlocked(); + // Start the in-session password change flow by showing a dialog that embeds // the user's SAML IdP change-password page: void StartInSessionPasswordChange(); @@ -70,14 +135,28 @@ void OnAuthFailure(const AuthFailure& error) override; void OnAuthSuccess(const UserContext& user_context) override; + // ash::SessionActivationObserver: + void OnSessionActivated(bool activated) override; + void OnLockStateChanged(bool locked) override; + private: + static InSessionPasswordChangeManager* GetNullable(); + + // Sets the given instance as the singleton for testing. + static void SetForTesting(InSessionPasswordChangeManager* instance); + static void ResetForTesting(); + void NotifyObservers(Event event); Profile* primary_profile_; const user_manager::User* primary_user_; base::ObserverList<Observer> observer_list_; - + RecheckPasswordExpiryTask recheck_task_; scoped_refptr<CryptohomeAuthenticator> authenticator_; + int urgent_warning_days_; + bool renotify_on_unlock_ = false; + + friend class InSessionPasswordChangeManagerTest; DISALLOW_COPY_AND_ASSIGN(InSessionPasswordChangeManager); };
diff --git a/chrome/browser/chromeos/login/saml/saml_password_expiry_notification_unittest.cc b/chrome/browser/chromeos/login/saml/in_session_password_change_manager_unittest.cc similarity index 77% rename from chrome/browser/chromeos/login/saml/saml_password_expiry_notification_unittest.cc rename to chrome/browser/chromeos/login/saml/in_session_password_change_manager_unittest.cc index 077b9df3..9a585bf 100644 --- a/chrome/browser/chromeos/login/saml/saml_password_expiry_notification_unittest.cc +++ b/chrome/browser/chromeos/login/saml/in_session_password_change_manager_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/login/saml/saml_password_expiry_notification.h" +#include "chrome/browser/chromeos/login/saml/in_session_password_change_manager.h" #include "ash/public/cpp/session/session_activation_observer.h" #include "ash/public/cpp/session/session_controller.h" @@ -41,7 +41,9 @@ return base::ASCIIToUTF16(ascii); } -class SamlPasswordExpiryNotificationTest : public testing::Test { +} // namespace + +class InSessionPasswordChangeManagerTest : public testing::Test { public: void SetUp() override { ASSERT_TRUE(profile_manager_.SetUp()); @@ -62,11 +64,17 @@ display_service_tester_ = std::make_unique<NotificationDisplayServiceTester>(profile_); + manager_ = std::make_unique<InSessionPasswordChangeManager>(profile_); + + // urgent_warning_days_ = -1: This means we only ever show a standard + // notification, instead of an urgent one, because it is simpler to test. + // TODO(https://crbug.com/930109): Test both types of notification. + manager_->urgent_warning_days_ = -1; + InSessionPasswordChangeManager::SetForTesting(manager_.get()); } void TearDown() override { - display_service_tester_.reset(); - expiry_notification_test_helper_.ResetForTesting(); + InSessionPasswordChangeManager::ResetForTesting(); } protected: @@ -82,7 +90,7 @@ void ExpectNotificationAndDismiss() { EXPECT_TRUE(Notification().has_value()); - DismissSamlPasswordExpiryNotification(profile_); + manager_->DismissExpiryNotification(); EXPECT_FALSE(Notification().has_value()); } @@ -92,49 +100,23 @@ TestingProfileManager profile_manager_{TestingBrowserProcess::GetGlobal()}; TestingProfile* profile_; - SamlPasswordExpiryNotificationTestHelper expiry_notification_test_helper_; - std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_; std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_; + std::unique_ptr<InSessionPasswordChangeManager> manager_; }; -} // namespace - -TEST_F(SamlPasswordExpiryNotificationTest, ShowAlreadyExpired) { - ShowSamlPasswordExpiryNotification(profile_, 0); - ASSERT_TRUE(Notification().has_value()); - - EXPECT_EQ(utf16("Password is expired"), Notification()->title()); - EXPECT_EQ(utf16("Choose a new one immediately"), Notification()->message()); - - DismissSamlPasswordExpiryNotification(profile_); - EXPECT_FALSE(Notification().has_value()); -} - -TEST_F(SamlPasswordExpiryNotificationTest, ShowWillSoonExpire) { - ShowSamlPasswordExpiryNotification(profile_, 14); - ASSERT_TRUE(Notification().has_value()); - - EXPECT_EQ(utf16("Password expires in less than 14 days"), - Notification()->title()); - EXPECT_EQ(utf16("Choose a new one now"), Notification()->message()); - - DismissSamlPasswordExpiryNotification(profile_); - EXPECT_FALSE(Notification().has_value()); -} - -TEST_F(SamlPasswordExpiryNotificationTest, MaybeShow_PolicyDisabled) { +TEST_F(InSessionPasswordChangeManagerTest, MaybeShow_PolicyDisabled) { SetExpirationTime(base::Time::Now()); profile_->GetPrefs()->SetBoolean(prefs::kSamlInSessionPasswordChangeEnabled, false); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); EXPECT_FALSE(Notification().has_value()); } -TEST_F(SamlPasswordExpiryNotificationTest, MaybeShow_WillNotExpire) { +TEST_F(InSessionPasswordChangeManagerTest, MaybeShow_WillNotExpire) { SamlPasswordAttributes::DeleteFromPrefs(profile_->GetPrefs()); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); EXPECT_FALSE(Notification().has_value()); // No notification shown now and nothing shown in the next 10 years. @@ -142,18 +124,18 @@ EXPECT_FALSE(Notification().has_value()); } -TEST_F(SamlPasswordExpiryNotificationTest, MaybeShow_AlreadyExpired) { +TEST_F(InSessionPasswordChangeManagerTest, MaybeShow_AlreadyExpired) { SetExpirationTime(base::Time::Now() - kOneYear); // Expired last year. - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); // Notification is shown immediately since password has expired. EXPECT_TRUE(Notification().has_value()); EXPECT_EQ(utf16("Password is expired"), Notification()->title()); } -TEST_F(SamlPasswordExpiryNotificationTest, MaybeShow_WillSoonExpire) { +TEST_F(InSessionPasswordChangeManagerTest, MaybeShow_WillSoonExpire) { SetExpirationTime(base::Time::Now() + (kAdvanceWarningTime / 2) - kOneHour); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); // Notification is shown immediately since password will soon expire. EXPECT_TRUE(Notification().has_value()); @@ -161,9 +143,9 @@ Notification()->title()); } -TEST_F(SamlPasswordExpiryNotificationTest, MaybeShow_WillEventuallyExpire) { +TEST_F(InSessionPasswordChangeManagerTest, MaybeShow_WillEventuallyExpire) { SetExpirationTime(base::Time::Now() + kOneYear + kAdvanceWarningTime); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); // Notification is not shown when expiration is still over a year away. EXPECT_FALSE(Notification().has_value()); @@ -175,9 +157,9 @@ Notification()->title()); } -TEST_F(SamlPasswordExpiryNotificationTest, MaybeShow_DeleteExpirationTime) { +TEST_F(InSessionPasswordChangeManagerTest, MaybeShow_DeleteExpirationTime) { SetExpirationTime(base::Time::Now() + kOneYear); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); // Notification is not shown immediately. EXPECT_FALSE(Notification().has_value()); @@ -188,9 +170,9 @@ EXPECT_FALSE(Notification().has_value()); } -TEST_F(SamlPasswordExpiryNotificationTest, MaybeShow_PasswordChanged) { +TEST_F(InSessionPasswordChangeManagerTest, MaybeShow_PasswordChanged) { SetExpirationTime(base::Time::Now() + (kAdvanceWarningTime / 2) - kOneHour); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); // Notification is shown immediately since password will soon expire. EXPECT_TRUE(Notification().has_value()); @@ -199,35 +181,35 @@ // Password is changed and notification is dismissed. SamlPasswordAttributes::DeleteFromPrefs(profile_->GetPrefs()); - DismissSamlPasswordExpiryNotification(profile_); + manager_->DismissExpiryNotification(); // From now on, notification will not be reshown. test_environment_.FastForwardBy(kTenYears); EXPECT_FALSE(Notification().has_value()); } -TEST_F(SamlPasswordExpiryNotificationTest, MaybeShow_Idempotent) { +TEST_F(InSessionPasswordChangeManagerTest, MaybeShow_Idempotent) { SetExpirationTime(base::Time::Now() + kOneYear); // Calling MaybeShowSamlPasswordExpiryNotification should only add one task - // to maybe show the notification in about a year. int baseline_task_count = test_environment_.GetPendingMainThreadTaskCount(); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); int new_task_count = test_environment_.GetPendingMainThreadTaskCount(); EXPECT_EQ(1, new_task_count - baseline_task_count); // Calling it many times shouldn't create more tasks - we only need one task // to show the notification in about a year. for (int i = 0; i < 10; i++) { - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); } new_task_count = test_environment_.GetPendingMainThreadTaskCount(); EXPECT_EQ(1, new_task_count - baseline_task_count); } -TEST_F(SamlPasswordExpiryNotificationTest, TimePasses_NoUserActionTaken) { +TEST_F(InSessionPasswordChangeManagerTest, TimePasses_NoUserActionTaken) { SetExpirationTime(base::Time::Now() + kOneYear + kAdvanceWarningTime); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); // Notification is not shown immediately. EXPECT_FALSE(Notification().has_value()); @@ -253,17 +235,17 @@ test_environment_.FastForwardBy(kAdvanceWarningTime / 2); EXPECT_TRUE(Notification().has_value()); EXPECT_EQ(utf16("Password is expired"), Notification()->title()); - EXPECT_EQ(utf16("Choose a new one immediately"), Notification()->message()); + EXPECT_EQ(utf16("Choose a new one now"), Notification()->message()); test_environment_.FastForwardBy(kOneYear); EXPECT_TRUE(Notification().has_value()); EXPECT_EQ(utf16("Password is expired"), Notification()->title()); - EXPECT_EQ(utf16("Choose a new one immediately"), Notification()->message()); + EXPECT_EQ(utf16("Choose a new one now"), Notification()->message()); } -TEST_F(SamlPasswordExpiryNotificationTest, TimePasses_NotificationDismissed) { +TEST_F(InSessionPasswordChangeManagerTest, TimePasses_NotificationDismissed) { SetExpirationTime(base::Time::Now() + kOneYear + kAdvanceWarningTime / 2); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); // Notification is not shown immediately. EXPECT_FALSE(Notification().has_value()); @@ -284,9 +266,9 @@ ExpectNotificationAndDismiss(); } -TEST_F(SamlPasswordExpiryNotificationTest, ReshowOnUnlock) { +TEST_F(InSessionPasswordChangeManagerTest, ReshowOnUnlock) { SetExpirationTime(base::Time::Now() + kAdvanceWarningTime / 2); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); // Notification is shown immediately. EXPECT_TRUE(Notification().has_value()); @@ -300,26 +282,27 @@ // But when the screen is unlocked, the old notification is replaced with a // newer one. The new one is prominently shown on screen for a few seconds. - expiry_notification_test_helper_.SimulateUnlockForTesting(); + manager_->OnScreenUnlocked(); EXPECT_TRUE(Notification().has_value()); EXPECT_NE(first_shown_at, Notification()->timestamp()); } -TEST_F(SamlPasswordExpiryNotificationTest, DontReshowWhenDismissed) { +TEST_F(InSessionPasswordChangeManagerTest, DontReshowWhenDismissed) { SetExpirationTime(base::Time::Now() + kAdvanceWarningTime / 2); - MaybeShowSamlPasswordExpiryNotification(profile_); + manager_->MaybeShowExpiryNotification(); // Notification is shown immediately. EXPECT_TRUE(Notification().has_value()); // If dismissed, the notification won't reappear within the next hour, since // we don't want to nag the user continuously. - DismissSamlPasswordExpiryNotification(profile_); + manager_->DismissExpiryNotification(); + manager_->OnExpiryNotificationDismissedByUser(); test_environment_.FastForwardBy(kOneHour); EXPECT_FALSE(Notification().has_value()); // Nor will it reappear if the user unlocks the screen. - expiry_notification_test_helper_.SimulateUnlockForTesting(); + manager_->OnScreenUnlocked(); EXPECT_FALSE(Notification().has_value()); // But it will eventually reappear the next day.
diff --git a/chrome/browser/chromeos/login/saml/password_expiry_notification.cc b/chrome/browser/chromeos/login/saml/password_expiry_notification.cc new file mode 100644 index 0000000..d0eac107 --- /dev/null +++ b/chrome/browser/chromeos/login/saml/password_expiry_notification.cc
@@ -0,0 +1,164 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/login/saml/password_expiry_notification.h" + +#include "ash/public/cpp/notification_utils.h" +#include "ash/public/cpp/session/session_activation_observer.h" +#include "ash/public/cpp/session/session_controller.h" +#include "base/bind.h" +#include "base/strings/string16.h" +#include "base/strings/string_util.h" +#include "base/task/post_task.h" +#include "base/task/task_traits.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/login/saml/in_session_password_change_manager.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/notifications/notification_common.h" +#include "chrome/browser/notifications/notification_display_service.h" +#include "chrome/browser/notifications/notification_display_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h" +#include "chrome/common/pref_names.h" +#include "chromeos/login/auth/saml_password_attributes.h" +#include "chromeos/strings/grit/chromeos_strings.h" +#include "components/prefs/pref_service.h" +#include "components/vector_icons/vector_icons.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/message_center/public/cpp/notification.h" +#include "ui/message_center/public/cpp/notification_delegate.h" + +using message_center::ButtonInfo; +using message_center::HandleNotificationClickDelegate; +using message_center::Notification; +using message_center::NotificationDelegate; +using message_center::NotificationObserver; +using message_center::NotificationType; +using message_center::NotifierId; +using message_center::NotifierType; +using message_center::RichNotificationData; +using message_center::SystemNotificationWarningLevel; +using message_center::ThunkNotificationDelegate; + +namespace chromeos { + +namespace { + +// Unique ID for this notification. +const char kNotificationId[] = "saml.password-expiry-notification"; + +// NotifierId for histogram reporting. +const base::NoDestructor<NotifierId> kNotifierId( + message_center::NotifierType::SYSTEM_COMPONENT, + kNotificationId); + +// Simplest type of notification UI - no progress bars, images etc. +const NotificationType kNotificationType = + message_center::NOTIFICATION_TYPE_SIMPLE; + +// Generic type for notifications that are not from web pages etc. +const NotificationHandler::Type kNotificationHandlerType = + NotificationHandler::Type::TRANSIENT; + +// The icon to use for this notification - looks like an office building. +const gfx::VectorIcon& kIcon = vector_icons::kBusinessIcon; + +// Leaving this empty means the notification is attributed to the system - +// ie "Chromium OS" or similar. +const base::NoDestructor<base::string16> kEmptyDisplaySource; + +// No origin URL is needed since the notification comes from the system. +const base::NoDestructor<GURL> kEmptyOriginUrl; + +// Warning level of WARNING makes the title orange. +const SystemNotificationWarningLevel kWarningLevel = + SystemNotificationWarningLevel::WARNING; + +base::string16 GetTitleText(int less_than_n_days) { + return l10n_util::GetPluralStringFUTF16(IDS_PASSWORD_EXPIRY_DAYS_TITLE, + less_than_n_days); +} + +base::string16 GetBodyText() { + return l10n_util::GetStringUTF16(IDS_PASSWORD_EXPIRY_CALL_TO_ACTION); +} + +RichNotificationData GetRichNotificationData() { + RichNotificationData result; + result.buttons = std::vector<ButtonInfo>{ButtonInfo( + l10n_util::GetStringUTF16(IDS_PASSWORD_EXPIRY_CHANGE_PASSWORD_BUTTON))}; + return result; +} + +// Delegate for handling clicks on the notification. +class PasswordExpiryNotificationDelegate : public NotificationDelegate { + public: + PasswordExpiryNotificationDelegate(); + + protected: + ~PasswordExpiryNotificationDelegate() override; + + // message_center::NotificationDelegate: + void Close(bool by_user) override; + void Click(const base::Optional<int>& button_index, + const base::Optional<base::string16>& reply) override; +}; + +PasswordExpiryNotificationDelegate::PasswordExpiryNotificationDelegate() = + default; +PasswordExpiryNotificationDelegate::~PasswordExpiryNotificationDelegate() = + default; + +void PasswordExpiryNotificationDelegate::Close(bool by_user) { + if (by_user) { + InSessionPasswordChangeManager::Get() + ->OnExpiryNotificationDismissedByUser(); + } +} + +void PasswordExpiryNotificationDelegate::Click( + const base::Optional<int>& button_index, + const base::Optional<base::string16>& reply) { + bool clicked_on_button = button_index.has_value(); + if (clicked_on_button) { + InSessionPasswordChangeManager::Get()->StartInSessionPasswordChange(); + } +} + +} // namespace + +// static +void PasswordExpiryNotification::Show(Profile* profile, int less_than_n_days) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + const base::string16 title = GetTitleText(less_than_n_days); + const base::string16 body = GetBodyText(); + const RichNotificationData rich_notification_data = GetRichNotificationData(); + const scoped_refptr<PasswordExpiryNotificationDelegate> delegate = + base::MakeRefCounted<PasswordExpiryNotificationDelegate>(); + + std::unique_ptr<Notification> notification = ash::CreateSystemNotification( + kNotificationType, kNotificationId, title, body, *kEmptyDisplaySource, + *kEmptyOriginUrl, *kNotifierId, rich_notification_data, delegate, kIcon, + kWarningLevel); + + NotificationDisplayService* nds = + NotificationDisplayServiceFactory::GetForProfile(profile); + // Calling close before display ensures that the notification pops up again + // even if it is already shown. + nds->Close(kNotificationHandlerType, kNotificationId); + nds->Display(kNotificationHandlerType, *notification, /*metadata=*/nullptr); +} + +// static +void PasswordExpiryNotification::Dismiss(Profile* profile) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + NotificationDisplayServiceFactory::GetForProfile(profile)->Close( + kNotificationHandlerType, kNotificationId); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/saml/password_expiry_notification.h b/chrome/browser/chromeos/login/saml/password_expiry_notification.h new file mode 100644 index 0000000..f306604 --- /dev/null +++ b/chrome/browser/chromeos/login/saml/password_expiry_notification.h
@@ -0,0 +1,26 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_EXPIRY_NOTIFICATION_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_EXPIRY_NOTIFICATION_H_ + +class Profile; + +namespace chromeos { + +// Utility functions to show or hide a password expiry notification. +class PasswordExpiryNotification { + public: + // Shows a password expiry notification. |less_than_n_days| should be 1 if the + // password expires in less than 1 day, 0 if it has already expired, etc. + // Negative numbers are treated the same as zero. + static void Show(Profile* profile, int less_than_n_days); + + // Hides the password expiry notification if it is currently shown. + static void Dismiss(Profile* profile); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_EXPIRY_NOTIFICATION_H_
diff --git a/chrome/browser/chromeos/login/saml/password_expiry_notification_unittest.cc b/chrome/browser/chromeos/login/saml/password_expiry_notification_unittest.cc new file mode 100644 index 0000000..bd085d1 --- /dev/null +++ b/chrome/browser/chromeos/login/saml/password_expiry_notification_unittest.cc
@@ -0,0 +1,75 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/login/saml/password_expiry_notification.h" + +#include "ash/public/cpp/session/session_activation_observer.h" +#include "ash/public/cpp/session/session_controller.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_task_environment.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/notifications/notification_display_service_impl.h" +#include "chrome/browser/notifications/notification_display_service_tester.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "chromeos/login/auth/saml_password_attributes.h" +#include "components/user_manager/scoped_user_manager.h" +#include "components/user_manager/user_names.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using message_center::Notification; + +namespace chromeos { + +namespace { + +inline base::string16 utf16(const char* ascii) { + return base::ASCIIToUTF16(ascii); +} + +class SamlPasswordExpiryNotificationTest : public testing::Test { + protected: + base::Optional<Notification> Notification() { + return NotificationDisplayServiceTester::Get()->GetNotification( + "saml.password-expiry-notification"); + } + + content::TestBrowserThreadBundle thread_bundle_; + TestingProfile profile_; + NotificationDisplayServiceTester display_service_tester_{&profile_}; +}; + +} // namespace + +TEST_F(SamlPasswordExpiryNotificationTest, ShowWillSoonExpire) { + PasswordExpiryNotification::Show(&profile_, 14); + ASSERT_TRUE(Notification().has_value()); + + EXPECT_EQ(utf16("Password expires in less than 14 days"), + Notification()->title()); + EXPECT_EQ(utf16("Choose a new one now"), Notification()->message()); + + PasswordExpiryNotification::Dismiss(&profile_); + EXPECT_FALSE(Notification().has_value()); +} + +TEST_F(SamlPasswordExpiryNotificationTest, ShowAlreadyExpired) { + PasswordExpiryNotification::Show(&profile_, 0); + ASSERT_TRUE(Notification().has_value()); + + EXPECT_EQ(utf16("Password is expired"), Notification()->title()); + EXPECT_EQ(utf16("Choose a new one now"), Notification()->message()); + + PasswordExpiryNotification::Dismiss(&profile_); + EXPECT_FALSE(Notification().has_value()); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/saml/saml_password_expiry_notification.cc b/chrome/browser/chromeos/login/saml/saml_password_expiry_notification.cc deleted file mode 100644 index 697e69bc..0000000 --- a/chrome/browser/chromeos/login/saml/saml_password_expiry_notification.cc +++ /dev/null
@@ -1,385 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/login/saml/saml_password_expiry_notification.h" - -#include "ash/public/cpp/notification_utils.h" -#include "ash/public/cpp/session/session_activation_observer.h" -#include "ash/public/cpp/session/session_controller.h" -#include "base/bind.h" -#include "base/strings/string16.h" -#include "base/strings/string_util.h" -#include "base/task/post_task.h" -#include "base/task/task_traits.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/chromeos/profiles/profile_helper.h" -#include "chrome/browser/notifications/notification_common.h" -#include "chrome/browser/notifications/notification_display_service.h" -#include "chrome/browser/notifications/notification_display_service_factory.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h" -#include "chrome/common/pref_names.h" -#include "chromeos/login/auth/saml_password_attributes.h" -#include "chromeos/strings/grit/chromeos_strings.h" -#include "components/prefs/pref_service.h" -#include "components/vector_icons/vector_icons.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/message_center/public/cpp/notification.h" -#include "ui/message_center/public/cpp/notification_delegate.h" - -using message_center::ButtonInfo; -using message_center::HandleNotificationClickDelegate; -using message_center::Notification; -using message_center::NotificationObserver; -using message_center::NotificationType; -using message_center::NotifierId; -using message_center::NotifierType; -using message_center::RichNotificationData; -using message_center::SystemNotificationWarningLevel; -using message_center::ThunkNotificationDelegate; - -namespace chromeos { - -namespace { - -// Unique ID for this notification. -const char kNotificationId[] = "saml.password-expiry-notification"; - -// NotifierId for histogram reporting. -const base::NoDestructor<NotifierId> kNotifierId( - message_center::NotifierType::SYSTEM_COMPONENT, - kNotificationId); - -// Simplest type of notification UI - no progress bars, images etc. -const NotificationType kNotificationType = - message_center::NOTIFICATION_TYPE_SIMPLE; - -// Generic type for notifications that are not from web pages etc. -const NotificationHandler::Type kNotificationHandlerType = - NotificationHandler::Type::TRANSIENT; - -// The icon to use for this notification - looks like an office building. -const gfx::VectorIcon& kIcon = vector_icons::kBusinessIcon; - -// Leaving this empty means the notification is attributed to the system - -// ie "Chromium OS" or similar. -const base::NoDestructor<base::string16> kEmptyDisplaySource; - -// No origin URL is needed since the notification comes from the system. -const base::NoDestructor<GURL> kEmptyOriginUrl; - -// When the password will expire in |kCriticalWarningDays| or less, the warning -// will have red text, slightly stronger language, and doesn't automatically -// time out - it stays on the screen until the user hides or dismisses it. -const int kCriticalWarningDays = 3; - -base::string16 GetTitleText(int less_than_n_days) { - return l10n_util::GetPluralStringFUTF16(IDS_PASSWORD_EXPIRY_DAYS_TITLE, - less_than_n_days); -} - -base::string16 GetBodyText(bool is_critical) { - return is_critical - ? l10n_util::GetStringUTF16( - IDS_PASSWORD_EXPIRY_CALL_TO_ACTION_CRITICAL) - : l10n_util::GetStringUTF16(IDS_PASSWORD_EXPIRY_CALL_TO_ACTION); -} - -RichNotificationData GetRichNotificationData(bool is_critical) { - RichNotificationData result; - result.never_timeout = is_critical; - result.buttons = std::vector<ButtonInfo>{ButtonInfo( - l10n_util::GetStringUTF16(IDS_PASSWORD_EXPIRY_CHANGE_PASSWORD_BUTTON))}; - return result; -} - -SystemNotificationWarningLevel GetWarningLevel(bool is_critical) { - return is_critical ? SystemNotificationWarningLevel::CRITICAL_WARNING - : SystemNotificationWarningLevel::WARNING; -} - -void ShowNotificationImpl( - Profile* profile, - int less_than_n_days, - scoped_refptr<message_center::NotificationDelegate> delegate) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - const bool is_critical = less_than_n_days <= kCriticalWarningDays; - const base::string16 title = GetTitleText(less_than_n_days); - const base::string16 body = GetBodyText(is_critical); - const RichNotificationData rich_notification_data = - GetRichNotificationData(is_critical); - const SystemNotificationWarningLevel warning_level = - GetWarningLevel(is_critical); - - std::unique_ptr<Notification> notification = ash::CreateSystemNotification( - kNotificationType, kNotificationId, title, body, *kEmptyDisplaySource, - *kEmptyOriginUrl, *kNotifierId, rich_notification_data, delegate, kIcon, - warning_level); - - NotificationDisplayService* nds = - NotificationDisplayServiceFactory::GetForProfile(profile); - // Calling close before display ensures that the notification pops up again - // even if it is already shown. - nds->Close(kNotificationHandlerType, kNotificationId); - nds->Display(kNotificationHandlerType, *notification, /*metadata=*/nullptr); -} - -// A time delta of length one hour. -const base::TimeDelta kOneHour = base::TimeDelta::FromHours(1); -// A time delta of length one day. -const base::TimeDelta kOneDay = base::TimeDelta::FromDays(1); - -// Traits for running RecheckTask. Runs from the UI thread to show notification. -const base::TaskTraits kRecheckTaskTraits = { - content::BrowserThread::UI, base::TaskPriority::BEST_EFFORT, - base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}; - -// Returns true if |profile| is still valid. -bool IsValidProfile(Profile* profile) { - ProfileManager* profile_manager = g_browser_process->profile_manager(); - return profile_manager && profile_manager->IsValidProfile(profile); -} - -// Returns true if showing the notification is enabled for this profile. -bool IsEnabledForProfile(Profile* profile) { - return chromeos::ProfileHelper::IsPrimaryProfile(profile) && - profile->GetPrefs()->GetBoolean( - prefs::kSamlInSessionPasswordChangeEnabled); -} - -// The Rechecker checks periodically if the notification should be shown or -// updated. When it checks depends on when the password will expire. -// There is only at most one Rechecker at a time - for the primary user. -class Rechecker : public ash::SessionActivationObserver, - public NotificationObserver { - public: - // Shows the notification for the primary profile. - void ShowNotification(int less_than_n_days); - - // Checks again if the notification should be shown, and maybe shows it. - void Recheck(); - - // Calls recheck after the given |delay|. - void RecheckAfter(base::TimeDelta delay); - - // Cancels any pending tasks to call Recheck again. - void CancelPendingRecheck(); - - // ash::SessionActivationObserver: - void OnSessionActivated(bool activated) override {} // Not needed. - void OnLockStateChanged(bool locked) override; - - // NotificationObserver: - void Click(const base::Optional<int>& button_index, - const base::Optional<base::string16>& reply) override; - void Close(bool by_user) override; - - // Ensures the singleton is initialized and started for the given profile. - static void StartForProfile(Profile* profile); - // Stops and deletes the Rechecker singleton. - static void Stop(); - - private: - // The constructor and destructor also maintain the singleton instance. - Rechecker(Profile* profile, const AccountId& account_id); - ~Rechecker() override; - - // Singleton, since we only ever need one instance_ for the primary user. - static Rechecker* instance_; - - Profile* profile_; - const AccountId account_id_; - bool reshow_on_unlock_ = false; - - // Weak ptr factory for handling interaction with notifications - these - // pointers shouldn't be invalidated until this class is deleted. - base::WeakPtrFactory<NotificationObserver> observer_weak_ptr_factory_{this}; - // Weak ptr factory for posting tasks. Invalidating these pointers will - // cancel upcoming tasks. - base::WeakPtrFactory<Rechecker> task_weak_ptr_factory_{this}; - - // Give test helper access to internals. - friend SamlPasswordExpiryNotificationTestHelper; - - DISALLOW_COPY_AND_ASSIGN(Rechecker); -}; - -void Rechecker::ShowNotification(int less_than_n_days) { - ShowNotificationImpl(profile_, less_than_n_days, - base::MakeRefCounted<ThunkNotificationDelegate>( - observer_weak_ptr_factory_.GetWeakPtr())); - // When a notification is currently showing, reshow it on every unlock. - reshow_on_unlock_ = true; -} - -void Rechecker::Recheck() { - // This cancels any pending call to Recheck - we don't want some bug to cause - // us to queue up lots of calls to Recheck in the future, we only want one. - CancelPendingRecheck(); - - // In case the profile has been deleted since this task was posted. - if (!IsValidProfile(profile_)) { - delete this; // No need to keep calling recheck. - return; - } - - PrefService* prefs = profile_->GetPrefs(); - SamlPasswordAttributes attrs = SamlPasswordAttributes::LoadFromPrefs(prefs); - if (!IsEnabledForProfile(profile_) || !attrs.has_expiration_time()) { - // Feature is not enabled for this profile, or profile is not primary, or - // there is no expiration time. Dismiss if shown, and stop checking. - DismissSamlPasswordExpiryNotification(profile_); - delete this; - return; - } - - // Calculate how many days until the password will expire. - const base::TimeDelta time_until_expiry = - attrs.expiration_time() - base::Time::Now(); - const int less_than_n_days = - std::max(0, time_until_expiry.InDaysFloored() + 1); - const int advance_warning_days = std::max( - 0, prefs->GetInteger(prefs::kSamlPasswordExpirationAdvanceWarningDays)); - - if (less_than_n_days <= advance_warning_days) { - // The password is expired, or expires in less than |advance_warning_days|. - // So we show a notification immediately. - ShowNotification(less_than_n_days); - // We check again whether to reshow / update the notification after one day: - RecheckAfter(kOneDay); - - } else { - // We have not yet reached the advance warning threshold. Check again - // once we have arrived at expiry_time minus advance_warning_days... - base::TimeDelta recheck_delay = - time_until_expiry - base::TimeDelta::FromDays(advance_warning_days); - // But, wait an extra hour so that when this code is next run, it is clear - // we are now inside advance_warning_days (and not right on the boundary). - recheck_delay += kOneHour; - RecheckAfter(recheck_delay); - } -} - -void Rechecker::RecheckAfter(base::TimeDelta delay) { - base::PostDelayedTaskWithTraits( - FROM_HERE, kRecheckTaskTraits, - base::BindOnce(&Rechecker::Recheck, task_weak_ptr_factory_.GetWeakPtr()), - std::max(delay, kOneHour)); - // This always waits at least one hour before calling Recheck again - we don't - // want some bug to cause this code to run every millisecond. -} - -void Rechecker::CancelPendingRecheck() { - task_weak_ptr_factory_.InvalidateWeakPtrs(); -} - -void Rechecker::OnLockStateChanged(bool locked) { - // If a notification is currently showing, we show a new version of it every - // time the user unlocks the screen. This makes the notification pop up once - // more - just after typing the password is a good time to remind the user. - if (!locked && reshow_on_unlock_) { - Recheck(); - } -} - -void Rechecker::Click(const base::Optional<int>& button_index, - const base::Optional<base::string16>& reply) { - bool clicked_on_button = button_index.has_value(); - if (clicked_on_button) { - PasswordChangeDialog::Show(profile_); - } -} - -void Rechecker::Close(bool by_user) { - // When a notification is dismissed, we then don't pop it up again each time - // the user unlocks the screen. - reshow_on_unlock_ = false; -} - -// static -void Rechecker::StartForProfile(Profile* profile) { - if (!instance_) { - const AccountId account_id = - ProfileHelper::Get()->GetUserByProfile(profile)->GetAccountId(); - new Rechecker(profile, account_id); - } - DCHECK(instance_ && instance_->profile_ == profile); - instance_->Recheck(); -} - -// static -void Rechecker::Stop() { - delete instance_; -} - -// static -Rechecker* Rechecker::instance_ = nullptr; - -Rechecker::Rechecker(Profile* profile, const AccountId& account_id) - : profile_(profile), account_id_(account_id) { - // There must not be an existing singleton instance. - DCHECK(!instance_); - instance_ = this; - - // Add |this| as a SessionActivationObserver to see when the screen is locked. - auto* session_controller = ash::SessionController::Get(); - if (session_controller) { - session_controller->AddSessionActivationObserverForAccountId(account_id_, - this); - } -} - -Rechecker::~Rechecker() { - // Remove this as a SessionActivationObserver. - auto* session_controller = ash::SessionController::Get(); - if (session_controller) { - session_controller->RemoveSessionActivationObserverForAccountId(account_id_, - this); - } - - // This should still be the singleton instance. - DCHECK_EQ(this, instance_); - instance_ = nullptr; -} - -} // namespace - -void MaybeShowSamlPasswordExpiryNotification(Profile* profile) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - if (IsEnabledForProfile(profile)) { - Rechecker::StartForProfile(profile); - } -} - -void ShowSamlPasswordExpiryNotification(Profile* profile, - int less_than_n_days) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - ShowNotificationImpl( - profile, less_than_n_days, - base::MakeRefCounted<HandleNotificationClickDelegate>( - base::BindRepeating(&PasswordChangeDialog::Show, profile))); -} - -void DismissSamlPasswordExpiryNotification(Profile* profile) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - NotificationDisplayServiceFactory::GetForProfile(profile)->Close( - kNotificationHandlerType, kNotificationId); -} - -void SamlPasswordExpiryNotificationTestHelper::ResetForTesting() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - delete Rechecker::instance_; -} - -void SamlPasswordExpiryNotificationTestHelper::SimulateUnlockForTesting() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - Rechecker::instance_->OnLockStateChanged(/*locked=*/false); -} - -} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/saml/saml_password_expiry_notification.h b/chrome/browser/chromeos/login/saml/saml_password_expiry_notification.h deleted file mode 100644 index 7266aa70..0000000 --- a/chrome/browser/chromeos/login/saml/saml_password_expiry_notification.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SAML_SAML_PASSWORD_EXPIRY_NOTIFICATION_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_SAML_SAML_PASSWORD_EXPIRY_NOTIFICATION_H_ - -class Profile; - -namespace chromeos { - -// Utility functions to show or hide a password expiry notification. - -// Show a password expiry notification if the user's password has expired or -// soon expires (that is, within pref kSamlPasswordExpirationAdvanceWarningDays -// time). Otherwise, if the user's password will expire in the more distant -// future, in that case a notification will be shown in the future. Nothing is -// shown if the password is not expected to expire. -void MaybeShowSamlPasswordExpiryNotification(Profile* profile); - -// Shows a password expiry notification. |less_than_n_days| should be 1 if the -// password expires in less than 1 day, 0 if it has already expired, etc. -// Negative numbers are treated the same as zero. -void ShowSamlPasswordExpiryNotification(Profile* profile, int less_than_n_days); - -// Hides the password expiry notification if it is currently shown. -void DismissSamlPasswordExpiryNotification(Profile* profile); - -// Exposes extra functionality that should only be used during testing. -class SamlPasswordExpiryNotificationTestHelper { - public: - // Simulate unlocking the screen, which makes the notification pop up again. - void SimulateUnlockForTesting(); - - // Stop waiting for the password to expire and free up any resources. - void ResetForTesting(); -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SAML_SAML_PASSWORD_EXPIRY_NOTIFICATION_H_
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc index c2e49e2..3244154 100644 --- a/chrome/browser/chromeos/login/session/user_session_manager.cc +++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -62,7 +62,6 @@ #include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h" #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.h" #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter_factory.h" -#include "chrome/browser/chromeos/login/saml/saml_password_expiry_notification.h" #include "chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.h" #include "chrome/browser/chromeos/login/screens/sync_consent_screen.h" #include "chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.h" @@ -1424,15 +1423,11 @@ } } - PrefService* prefs = profile->GetPrefs(); - if (prefs->GetBoolean(prefs::kSamlInSessionPasswordChangeEnabled)) { - // Update password expiry data if new data came in during SAML login: - if (user_context_.GetSamlPasswordAttributes().has_value()) { - user_context_.GetSamlPasswordAttributes()->SaveToPrefs(prefs); - } - // Show password expiry notification if it is expiring - even if it wasn't - // a SAML login (ie, show it even if it was an offline login). - MaybeShowSamlPasswordExpiryNotification(profile); + // Update password expiry data if new data came in during SAML login: + if (base::FeatureList::IsEnabled(::features::kInSessionPasswordChange) && + user_context_.GetSamlPasswordAttributes().has_value()) { + user_context_.GetSamlPasswordAttributes()->SaveToPrefs( + profile->GetPrefs()); } // Transfers authentication-related data from the profile that was used for
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc index 7b30c7ba..8936fbd0 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc +++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
@@ -59,6 +59,12 @@ if (!install_attributes_->IsCloudManaged() || !device_settings_service_->policy_data() || !public_key.get() || !public_key->is_loaded()) { + LOG(ERROR) << "Policy store failed, is_cloud_managed: " + << install_attributes_->IsCloudManaged() << ", policy_data: " + << (device_settings_service_->policy_data() != nullptr) + << ", public_key: " << (public_key.get() != nullptr) + << ", public_key_is_loaded: " + << (public_key.get() ? public_key->is_loaded() : false); status_ = STATUS_BAD_STATE; NotifyStoreError(); return;
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_store.cc b/chrome/browser/chromeos/policy/device_local_account_policy_store.cc index aae7fc9..4562b5c 100644 --- a/chrome/browser/chromeos/policy/device_local_account_policy_store.cc +++ b/chrome/browser/chromeos/policy/device_local_account_policy_store.cc
@@ -201,6 +201,9 @@ scoped_refptr<ownership::PublicKey> key = device_settings_service_->GetPublicKey(); if (!key.get() || !key->is_loaded() || !device_policy_data) { + LOG(ERROR) << "Failed policy validation, key: " << (key.get() != nullptr) + << ", is_loaded: " << (key.get() ? key->is_loaded() : false) + << ", device_policy_data: " << (device_policy_data != nullptr); status_ = CloudPolicyStore::STATUS_BAD_STATE; NotifyStoreLoaded(); return;
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc index fc4a9d6..b688f540 100644 --- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -257,6 +257,10 @@ name: 'frameId', value: details.frameId.toString() }); + details.requestHeaders.push({ + name: 'resourceType', + value: details.type + }); return {requestHeaders: details.requestHeaders}; }, {urls: ['*://*/echoheader*']}, ['blocking', 'requestHeaders']); @@ -2525,7 +2529,7 @@ // response for the navigation preload request, and respond with it to create // the page. GURL url = embedded_test_server()->GetURL( - "/echoheader?foo&frameId&service-worker-navigation-preload"); + "/echoheader?frameId&resourceType&service-worker-navigation-preload"); ui_test_utils::NavigateToURL(browser(), url); content::WebContents* web_contents = @@ -2534,19 +2538,20 @@ // Since the request was to "/echoheader", the response describes the request // headers. // - // The expectation is "bar\n0\ntrue" because... + // The expectation is "0\nmain_frame\ntrue" because... // - // 1) The extension is expected to add a "foo: bar" header to the request - // before it goes to network. - // 2) The extension is similarly expected to add a "frameId: {id}" header, - // where {id} is details.frameId. This id is 0 for the main frame. + // 1) The extension is expected to add a "frameId: {id}" header, where {id} is + // details.frameId. This id is 0 for the main frame. + // 2) The extension is similarly expected to add a "resourceType: {type}" + // header, where {type} is details.type. // 3) The browser adds a "service-worker-navigation-preload: true" header for // navigation preload requests, so also sanity check that header to prove // that this test is really testing the navigation preload request. - EXPECT_EQ("bar\n0\ntrue", EvalJs(web_contents, "document.body.textContent;")); + EXPECT_EQ("0\nmain_frame\ntrue", + EvalJs(web_contents, "document.body.textContent;")); - // Repeat the test from an iframe, to test that details.frameId is populated - // correctly. + // Repeat the test from an iframe, to test that details.frameId and resource + // type is populated correctly. const char kAddIframe[] = R"( (async () => { const iframe = document.createElement('iframe'); @@ -2557,10 +2562,13 @@ }); const result = iframe.contentWindow.document.body.textContent; - // Expect "bar\n{frameId}\ntrue" where {frameId} is a positive integer. + // Expect "{frameId}\nsub_frame\ntrue" where {frameId} is a positive + // integer. const split = result.split('\n'); - if (split[0] == 'bar' && parseInt(split[1]) > 0 && split[2] == 'true') - return 'ok'; + if (parseInt(split[0]) > 0 && split[1] == 'sub_frame' && + split[2] == 'true') { + return 'ok'; + } return 'bad result: ' + result; })(); )";
diff --git a/chrome/browser/extensions/forced_extensions/installation_tracker.cc b/chrome/browser/extensions/forced_extensions/installation_tracker.cc index f50f39d..314fc49 100644 --- a/chrome/browser/extensions/forced_extensions/installation_tracker.cc +++ b/chrome/browser/extensions/forced_extensions/installation_tracker.cc
@@ -89,6 +89,8 @@ DCHECK(!reported_); // Report only if there was non-empty list of force-installed extensions. if (!forced_extensions_.empty()) { + UMA_HISTOGRAM_COUNTS_100("Extensions.ForceInstalledTotalCandidateCount", + forced_extensions_.size()); if (succeeded) { UMA_HISTOGRAM_LONG_TIMES("Extensions.ForceInstalledLoadTime", base::Time::Now() - start_time_);
diff --git a/chrome/browser/extensions/forced_extensions/installation_tracker_unittest.cc b/chrome/browser/extensions/forced_extensions/installation_tracker_unittest.cc index 2fa0326..4cd16dfb 100644 --- a/chrome/browser/extensions/forced_extensions/installation_tracker_unittest.cc +++ b/chrome/browser/extensions/forced_extensions/installation_tracker_unittest.cc
@@ -37,6 +37,9 @@ "Extensions.ForceInstalledDownloadingStage"; constexpr char kFailureCrxInstallErrorStats[] = "Extensions.ForceInstalledFailureCrxInstallError"; +constexpr char kTotalCountStats[] = + "Extensions.ForceInstalledTotalCandidateCount"; + } // namespace namespace extensions { @@ -88,6 +91,9 @@ histogram_tester_.ExpectTotalCount(kFailureReasons, 0); histogram_tester_.ExpectTotalCount(kInstallationStages, 0); histogram_tester_.ExpectTotalCount(kFailureCrxInstallErrorStats, 0); + histogram_tester_.ExpectUniqueSample( + kTotalCountStats, + prefs_->GetManagedPref(pref_names::kInstallForceList)->DictSize(), 1); } TEST_F(ForcedExtensionsInstallationTrackerTest, @@ -105,6 +111,9 @@ kFailureReasons, InstallationReporter::FailureReason::UNKNOWN, 1); histogram_tester_.ExpectTotalCount(kInstallationStages, 0); histogram_tester_.ExpectTotalCount(kFailureCrxInstallErrorStats, 0); + histogram_tester_.ExpectUniqueSample( + kTotalCountStats, + prefs_->GetManagedPref(pref_names::kInstallForceList)->DictSize(), 1); } TEST_F(ForcedExtensionsInstallationTrackerTest, @@ -131,6 +140,9 @@ histogram_tester_.ExpectTotalCount(kInstallationStages, 0); histogram_tester_.ExpectUniqueSample(kFailureCrxInstallErrorStats, CrxInstallErrorDetail::UNEXPECTED_ID, 1); + histogram_tester_.ExpectUniqueSample( + kTotalCountStats, + prefs_->GetManagedPref(pref_names::kInstallForceList)->DictSize(), 1); } TEST_F(ForcedExtensionsInstallationTrackerTest, ExtensionsStuck) { @@ -153,6 +165,9 @@ histogram_tester_.ExpectBucketCount( kInstallationStages, InstallationReporter::Stage::DOWNLOADING, 1); histogram_tester_.ExpectTotalCount(kFailureCrxInstallErrorStats, 0); + histogram_tester_.ExpectUniqueSample( + kTotalCountStats, + prefs_->GetManagedPref(pref_names::kInstallForceList)->DictSize(), 1); } TEST_F(ForcedExtensionsInstallationTrackerTest, ExtensionsAreDownloading) { @@ -182,6 +197,9 @@ histogram_tester_.ExpectBucketCount( kInstallationDownloadingStages, ExtensionDownloaderDelegate::DOWNLOADING_CRX, 1); + histogram_tester_.ExpectUniqueSample( + kTotalCountStats, + prefs_->GetManagedPref(pref_names::kInstallForceList)->DictSize(), 1); } TEST_F(ForcedExtensionsInstallationTrackerTest, NoExtensionsConfigured) { @@ -193,6 +211,7 @@ histogram_tester_.ExpectTotalCount(kFailureReasons, 0); histogram_tester_.ExpectTotalCount(kInstallationStages, 0); histogram_tester_.ExpectTotalCount(kFailureCrxInstallErrorStats, 0); + histogram_tester_.ExpectTotalCount(kTotalCountStats, 0); } } // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 45cba2a7..f5b4b569 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1172,6 +1172,11 @@ "expiry_milestone": -1 }, { + "name": "enable-winrt-sensor-implementation", + "owners": [ "wensh@microsoft.com" ], + "expiry_milestone": 80 + }, + { "name": "enable-generic-sensor", "owners": [ "reillyg@chromium.org", "raphael.kubo.da.costa@intel.com" ], "expiry_milestone": 72 @@ -1302,6 +1307,11 @@ "expiry_milestone": 78 }, { + "name": "enable-defer-all-script", + "owners": [ "//components/data_reduction_proxy/OWNERS" ], + "expiry_milestone": 82 + }, + { "name": "enable-layout-ng", "owners": [ "layout-dev@chromium.org" ], "expiry_milestone": 80 @@ -2525,6 +2535,11 @@ "expiry_milestone": 76 }, { + "name": "omnibox-search-engine-logo", + "owners": [ "wylieb", "chrome-omnibox-team@google.com" ], + "expiry_milestone": 80 + }, + { "name": "omnibox-short-bookmark-suggestions", "owners": [ "krb", "chrome-omnibox-team@google.com" ], "expiry_milestone": 78
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 1a7e2f2..d01461b 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -533,6 +533,10 @@ "If enabled, adds the status of certain experiment variations when making " "calls to Google Payments."; +const char kEnableDeferAllScriptName[] = "DeferAllScript previews"; +const char kEnableDeferAllScriptDescription[] = + "Enable deferring synchronous script on slow pages."; + const char kEnableSaveDataName[] = "Enables save data feature"; const char kEnableSaveDataDescription[] = "Enables save data feature. May cause user's traffic to be proxied via " @@ -603,6 +607,11 @@ "during the handshake when resuming a connection to a compatible TLS 1.3 " "server."; +const char kWinrtSensorsImplementationName[] = "WinRT Sensor Implementation"; +const char kWinrtSensorsImplementationDescription[] = + "Enables usage of the Windows.Devices.Sensors WinRT APIs on Windows for " + "sensors"; + const char kEnableGenericSensorName[] = "Generic Sensor"; const char kEnableGenericSensorDescription[] = "Enables motion sensor classes based on Generic Sensor API, i.e. " @@ -1321,6 +1330,10 @@ "Display entity suggestions using images and an enhanced layout; showing " "more context and descriptive text about the entity."; +const char kOmniboxSearchEngineLogoName[] = "Omnibox search engine logo"; +const char kOmniboxSearchEngineLogoDescription[] = + "Display the current default search engine's logo in the omnibox"; + const char kOmniboxSpareRendererName[] = "Start spare renderer on omnibox focus"; const char kOmniboxSpareRendererDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 466865b..e81aafd 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -328,6 +328,9 @@ extern const char kEnableAutofillSendExperimentIdsInPaymentsRPCsName[]; extern const char kEnableAutofillSendExperimentIdsInPaymentsRPCsDescription[]; +extern const char kEnableDeferAllScriptName[]; +extern const char kEnableDeferAllScriptDescription[]; + extern const char kEnableSaveDataName[]; extern const char kEnableSaveDataDescription[]; @@ -370,6 +373,9 @@ extern const char kEnableTLS13EarlyDataName[]; extern const char kEnableTLS13EarlyDataDescription[]; +extern const char kWinrtSensorsImplementationName[]; +extern const char kWinrtSensorsImplementationDescription[]; + extern const char kEnableGenericSensorName[]; extern const char kEnableGenericSensorDescription[]; @@ -802,6 +808,9 @@ extern const char kOmniboxShortBookmarkSuggestionsName[]; extern const char kOmniboxShortBookmarkSuggestionsDescription[]; +extern const char kOmniboxSearchEngineLogoName[]; +extern const char kOmniboxSearchEngineLogoDescription[]; + extern const char kOmniboxSpareRendererName[]; extern const char kOmniboxSpareRendererDescription[];
diff --git a/chrome/browser/idle/OWNERS b/chrome/browser/idle/OWNERS index 1dcec86..971ef1c 100644 --- a/chrome/browser/idle/OWNERS +++ b/chrome/browser/idle/OWNERS
@@ -1,3 +1,5 @@ file://content/browser/idle/OWNERS per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS + +# TEAM: fugu-dev@chromium.org
diff --git a/chrome/browser/native_file_system/OWNERS b/chrome/browser/native_file_system/OWNERS index 7eb6aed..06981ab 100644 --- a/chrome/browser/native_file_system/OWNERS +++ b/chrome/browser/native_file_system/OWNERS
@@ -1,6 +1,6 @@ file://content/browser/native_file_system/OWNERS -per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS +per-file *permission*=file://chrome/browser/permissions/PERMISSIONS_OWNERS # TEAM: storage-dev@chromium.org # COMPONENT: Blink>Storage>FileSystem
diff --git a/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc b/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc index 070e302..aa530c1 100644 --- a/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc +++ b/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc
@@ -8,6 +8,8 @@ #include "base/bind.h" #include "base/task/post_task.h" +#include "chrome/browser/native_file_system/native_file_system_permission_context_factory.h" +#include "chrome/browser/native_file_system/native_file_system_permission_request_manager.h" #include "chrome/browser/permissions/permission_util.h" #include "chrome/browser/ui/browser_dialogs.h" #include "content/public/browser/browser_task_traits.h" @@ -35,15 +37,42 @@ content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(rfh); - if (!web_contents) { // Requested from a worker, or a no longer existing tab. std::move(callback).Run(PermissionAction::DISMISSED); return; } - ShowNativeFileSystemPermissionDialog(origin, path, is_directory, - std::move(callback), web_contents); + auto* request_manager = + NativeFileSystemPermissionRequestManager::FromWebContents(web_contents); + if (!request_manager) { + std::move(callback).Run(PermissionAction::DISMISSED); + return; + } + + request_manager->AddRequest({origin, path, is_directory}, + std::move(callback)); +} + +void ShowDirectoryAccessConfirmationPromptOnUIThread( + int process_id, + int frame_id, + const url::Origin& origin, + const base::FilePath& path, + base::OnceCallback<void(PermissionAction result)> callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + content::RenderFrameHost* rfh = + content::RenderFrameHost::FromID(process_id, frame_id); + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(rfh); + + if (!web_contents) { + // Requested from a worker, or a no longer existing tab. + std::move(callback).Run(PermissionAction::DISMISSED); + } + + ShowNativeFileSystemDirectoryAccessConfirmationDialog( + origin, path, std::move(callback), web_contents); } // Returns a callback that calls the passed in |callback| by posting a task to @@ -63,6 +92,12 @@ } // namespace +ChromeNativeFileSystemPermissionContext::Grants::Grants() = default; +ChromeNativeFileSystemPermissionContext::Grants::~Grants() = default; +ChromeNativeFileSystemPermissionContext::Grants::Grants(Grants&&) = default; +ChromeNativeFileSystemPermissionContext::Grants& +ChromeNativeFileSystemPermissionContext::Grants::operator=(Grants&&) = default; + class ChromeNativeFileSystemPermissionContext::PermissionGrantImpl : public content::NativeFileSystemPermissionGrant { public: @@ -81,6 +116,11 @@ return origin_; } + bool is_directory() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return is_directory_; + } + const base::FilePath& path() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return path_; @@ -183,6 +223,73 @@ return result; } +void ChromeNativeFileSystemPermissionContext::ConfirmDirectoryReadAccess( + const url::Origin& origin, + const base::FilePath& path, + int process_id, + int frame_id, + base::OnceCallback<void(PermissionStatus)> callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce( + &ShowDirectoryAccessConfirmationPromptOnUIThread, process_id, + frame_id, origin, path, + base::BindOnce( + [](scoped_refptr<base::TaskRunner> task_runner, + base::OnceCallback<void(PermissionStatus result)> callback, + PermissionAction result) { + task_runner->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), + result == PermissionAction::GRANTED + ? PermissionStatus::GRANTED + : PermissionStatus::DENIED)); + }, + base::SequencedTaskRunnerHandle::Get(), std::move(callback)))); +} + +ChromeNativeFileSystemPermissionContext::Grants +ChromeNativeFileSystemPermissionContext::GetPermissionGrants( + const url::Origin& origin) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + Grants grants; + auto it = origins_.find(origin); + if (it == origins_.end()) + return grants; + for (const auto& entry : it->second.grants) { + if (entry.second->GetStatus() == + PermissionGrantImpl::PermissionStatus::GRANTED) { + if (entry.second->is_directory()) { + grants.directory_write_grants.push_back(entry.second->path()); + } else { + grants.file_write_grants.push_back(entry.second->path()); + } + } + } + return grants; +} + +// static +void ChromeNativeFileSystemPermissionContext::GetPermissionGrantsFromUIThread( + content::BrowserContext* browser_context, + const url::Origin& origin, + base::OnceCallback<void(Grants)> callback) { + auto permission_context = + NativeFileSystemPermissionContextFactory::GetForProfileIfExists( + browser_context); + if (!permission_context) { + std::move(callback).Run(Grants()); + return; + } + base::PostTaskAndReplyWithResult( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce( + &ChromeNativeFileSystemPermissionContext::GetPermissionGrants, + permission_context, origin), + std::move(callback)); +} + ChromeNativeFileSystemPermissionContext:: ~ChromeNativeFileSystemPermissionContext() = default;
diff --git a/chrome/browser/native_file_system/chrome_native_file_system_permission_context.h b/chrome/browser/native_file_system/chrome_native_file_system_permission_context.h index e4514ff..179c5035 100644 --- a/chrome/browser/native_file_system/chrome_native_file_system_permission_context.h +++ b/chrome/browser/native_file_system/chrome_native_file_system_permission_context.h
@@ -19,8 +19,8 @@ // Chrome implementation of NativeFileSystemPermissionContext. Currently // implements a single per-origin write permission state. // -// All methods (other than the constructor and destructor) should be called on -// the same sequence. +// All methods should be called on the same sequence, except for the +// constructor, destructor, and GetPermissionGrantsFromUIThread method. // // TODO(mek): Reconsider if this class should just be UI-thread only, avoiding // the need to make this ref-counted. @@ -46,6 +46,31 @@ const base::FilePath& path, bool is_directory) override; + void ConfirmDirectoryReadAccess( + const url::Origin& origin, + const base::FilePath& path, + int process_id, + int frame_id, + base::OnceCallback<void(PermissionStatus)> callback) override; + + struct Grants { + Grants(); + ~Grants(); + Grants(Grants&&); + Grants& operator=(Grants&&); + + std::vector<base::FilePath> file_write_grants; + std::vector<base::FilePath> directory_write_grants; + }; + Grants GetPermissionGrants(const url::Origin& origin); + + // This method must be called on the UI thread, and calls the callback with a + // snapshot of the currently granted permissions after looking them up. + static void GetPermissionGrantsFromUIThread( + content::BrowserContext* browser_context, + const url::Origin& origin, + base::OnceCallback<void(Grants)> callback); + // RefcountedKeyedService: void ShutdownOnUIThread() override;
diff --git a/chrome/browser/native_file_system/native_file_system_permission_context_factory.cc b/chrome/browser/native_file_system/native_file_system_permission_context_factory.cc index 4336f58..e5942f8 100644 --- a/chrome/browser/native_file_system/native_file_system_permission_context_factory.cc +++ b/chrome/browser/native_file_system/native_file_system_permission_context_factory.cc
@@ -18,6 +18,14 @@ } // static +scoped_refptr<ChromeNativeFileSystemPermissionContext> +NativeFileSystemPermissionContextFactory::GetForProfileIfExists( + content::BrowserContext* profile) { + return static_cast<ChromeNativeFileSystemPermissionContext*>( + GetInstance()->GetServiceForBrowserContext(profile, false).get()); +} + +// static NativeFileSystemPermissionContextFactory* NativeFileSystemPermissionContextFactory::GetInstance() { static base::NoDestructor<NativeFileSystemPermissionContextFactory> instance;
diff --git a/chrome/browser/native_file_system/native_file_system_permission_context_factory.h b/chrome/browser/native_file_system/native_file_system_permission_context_factory.h index 432ba1f..4bbc2b3 100644 --- a/chrome/browser/native_file_system/native_file_system_permission_context_factory.h +++ b/chrome/browser/native_file_system/native_file_system_permission_context_factory.h
@@ -18,6 +18,8 @@ public: static scoped_refptr<ChromeNativeFileSystemPermissionContext> GetForProfile( content::BrowserContext* profile); + static scoped_refptr<ChromeNativeFileSystemPermissionContext> + GetForProfileIfExists(content::BrowserContext* profile); static NativeFileSystemPermissionContextFactory* GetInstance(); private:
diff --git a/chrome/browser/native_file_system/native_file_system_permission_request_manager.cc b/chrome/browser/native_file_system/native_file_system_permission_request_manager.cc new file mode 100644 index 0000000..21feff4 --- /dev/null +++ b/chrome/browser/native_file_system/native_file_system_permission_request_manager.cc
@@ -0,0 +1,122 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/native_file_system/native_file_system_permission_request_manager.h" + +#include "base/command_line.h" +#include "base/task/post_task.h" +#include "chrome/browser/permissions/permission_util.h" +#include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/common/chrome_switches.h" +#include "content/public/browser/browser_task_traits.h" + +bool operator==( + const NativeFileSystemPermissionRequestManager::RequestData& a, + const NativeFileSystemPermissionRequestManager::RequestData& b) { + return a.origin == b.origin && a.path == b.path && + a.is_directory == b.is_directory; +} + +struct NativeFileSystemPermissionRequestManager::Request { + Request(RequestData data, + base::OnceCallback<void(PermissionAction result)> callback) + : data(std::move(data)) { + callbacks.push_back(std::move(callback)); + } + + const RequestData data; + std::vector<base::OnceCallback<void(PermissionAction result)>> callbacks; +}; + +NativeFileSystemPermissionRequestManager:: + ~NativeFileSystemPermissionRequestManager() = default; + +void NativeFileSystemPermissionRequestManager::AddRequest( + RequestData data, + base::OnceCallback<void(PermissionAction result)> callback) { + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDenyPermissionPrompts)) { + std::move(callback).Run(PermissionAction::DENIED); + return; + } + + // Check if any pending requests are identical to the new request. + if (current_request_ && current_request_->data == data) { + current_request_->callbacks.push_back(std::move(callback)); + return; + } + for (const auto& request : queued_requests_) { + if (request->data == data) { + request->callbacks.push_back(std::move(callback)); + return; + } + } + + queued_requests_.push_back( + std::make_unique<Request>(std::move(data), std::move(callback))); + if (!IsShowingRequest()) + ScheduleShowRequest(); +} + +NativeFileSystemPermissionRequestManager:: + NativeFileSystemPermissionRequestManager(content::WebContents* web_contents) + : content::WebContentsObserver(web_contents) {} + +bool NativeFileSystemPermissionRequestManager::CanShowRequest() const { + // Deley showing requests until the main frame is fully loaded. + // ScheduleShowRequest() will be called again when that happens. + return main_frame_has_fully_loaded_ && !queued_requests_.empty() && + !current_request_; +} + +void NativeFileSystemPermissionRequestManager::ScheduleShowRequest() { + if (!CanShowRequest()) + return; + + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce( + &NativeFileSystemPermissionRequestManager::DequeueAndShowRequest, + weak_factory_.GetWeakPtr())); +} + +void NativeFileSystemPermissionRequestManager::DequeueAndShowRequest() { + if (!CanShowRequest()) + return; + + current_request_ = std::move(queued_requests_.front()); + queued_requests_.pop_front(); + + ShowNativeFileSystemPermissionDialog( + current_request_->data.origin, current_request_->data.path, + current_request_->data.is_directory, + base::BindOnce( + &NativeFileSystemPermissionRequestManager::OnPermissionDialogResult, + weak_factory_.GetWeakPtr()), + web_contents()); +} + +void NativeFileSystemPermissionRequestManager:: + DocumentOnLoadCompletedInMainFrame() { + main_frame_has_fully_loaded_ = true; + // This is scheduled because while all calls to the browser have been + // issued at DOMContentLoaded, they may be bouncing around in scheduled + // callbacks finding the UI thread still. This makes sure we allow those + // scheduled calls to AddRequest to complete before we show the page-load + // permissions bubble. + if (!queued_requests_.empty()) + ScheduleShowRequest(); +} + +void NativeFileSystemPermissionRequestManager::OnPermissionDialogResult( + PermissionAction result) { + DCHECK(current_request_); + for (auto& callback : current_request_->callbacks) + std::move(callback).Run(result); + current_request_ = nullptr; + if (!queued_requests_.empty()) + ScheduleShowRequest(); +} + +WEB_CONTENTS_USER_DATA_KEY_IMPL(NativeFileSystemPermissionRequestManager)
diff --git a/chrome/browser/native_file_system/native_file_system_permission_request_manager.h b/chrome/browser/native_file_system/native_file_system_permission_request_manager.h new file mode 100644 index 0000000..a4d9d08b --- /dev/null +++ b/chrome/browser/native_file_system/native_file_system_permission_request_manager.h
@@ -0,0 +1,81 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_PERMISSION_REQUEST_MANAGER_H_ +#define CHROME_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_PERMISSION_REQUEST_MANAGER_H_ + +#include "base/containers/circular_deque.h" +#include "base/files/file_path.h" +#include "base/memory/weak_ptr.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" +#include "url/origin.h" + +enum class PermissionAction; + +// This class manages native file system permission requests for a particular +// WebContents. It is very similar to the generic PermissionRequestManager +// class, and as such deals with throttling, coallescing and/or completely +// denying permission requests, depending on the situation and policy. +// +// Native File System code doesn't just use PermissionRequestManager directly +// because the permission requests use different UI, and as such can't easily +// be supported by PermissionRequestManager. +// +// The NativeFileSystemPermissionRequestManager should be used on the UI thread. +class NativeFileSystemPermissionRequestManager + : public content::WebContentsObserver, + public content::WebContentsUserData< + NativeFileSystemPermissionRequestManager> { + public: + ~NativeFileSystemPermissionRequestManager() override; + + struct RequestData { + RequestData(const url::Origin& origin, + const base::FilePath& path, + bool is_directory) + : origin(origin), path(path), is_directory(is_directory) {} + RequestData(RequestData&&) = default; + RequestData& operator=(RequestData&&) = default; + + url::Origin origin; + base::FilePath path; + bool is_directory; + }; + + void AddRequest(RequestData request, + base::OnceCallback<void(PermissionAction result)> callback); + + private: + friend class content::WebContentsUserData< + NativeFileSystemPermissionRequestManager>; + + explicit NativeFileSystemPermissionRequestManager( + content::WebContents* web_contents); + + bool IsShowingRequest() const { return current_request_ != nullptr; } + bool CanShowRequest() const; + void ScheduleShowRequest(); + void DequeueAndShowRequest(); + + // WebContentsObserver + void DocumentOnLoadCompletedInMainFrame() override; + + void OnPermissionDialogResult(PermissionAction result); + + struct Request; + // Request currently being shown in prompt. + std::unique_ptr<Request> current_request_; + // Queued up requests. + base::circular_deque<std::unique_ptr<Request>> queued_requests_; + + // We only show new prompts when this is true. + bool main_frame_has_fully_loaded_ = false; + + base::WeakPtrFactory<NativeFileSystemPermissionRequestManager> weak_factory_{ + this}; + WEB_CONTENTS_USER_DATA_KEY_DECL(); +}; + +#endif // CHROME_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_PERMISSION_REQUEST_MANAGER_H_
diff --git a/chrome/browser/notifications/proto/impression.proto b/chrome/browser/notifications/proto/impression.proto index c16865e..d753c33 100644 --- a/chrome/browser/notifications/proto/impression.proto +++ b/chrome/browser/notifications/proto/impression.proto
@@ -11,7 +11,7 @@ // Contains data to determine when a notification should be shown to the user // and the user impression towards this notification. Should match Impression in // impression_types.h. -// Next tag: 7 +// Next tag: 8 message Impression { // The type of user feedback from a displayed notification. Should match // UserFeedback in notification_scheduler_types.h. @@ -41,6 +41,13 @@ EVENING = 2; } + // Used to override default user action and impression mapping. + // Next tag: 3 + message ImpressionMapping { + optional UserFeedback user_feedback = 1; + optional ImpressionResult impression_result = 2; + } + // Creation time stamp in milliseconds since epoch. optional int64 create_time = 1; @@ -59,4 +66,6 @@ // The unique identifier of the notification. optional string guid = 6; + + repeated ImpressionMapping impression_mapping = 7; }
diff --git a/chrome/browser/notifications/proto/notification_entry.proto b/chrome/browser/notifications/proto/notification_entry.proto index f8dabfed..c9b0ce3 100644 --- a/chrome/browser/notifications/proto/notification_entry.proto +++ b/chrome/browser/notifications/proto/notification_entry.proto
@@ -9,16 +9,20 @@ package notifications.proto; import "client_state.proto"; +import "impression.proto"; import "notification_data.proto"; // Defines scheduling and throttling details. +// Next tag: 3 message ScheduleParams { enum Priority { LOW = 0; HIGH = 1; NO_THROTTLE = 2; } + optional Priority priority = 1; + repeated Impression.ImpressionMapping impression_mapping = 2; } // The notification entry that contains all data for a scheduled notification.
diff --git a/chrome/browser/notifications/scheduler/internal/impression_types.cc b/chrome/browser/notifications/scheduler/internal/impression_types.cc index 148e385a..681c017 100644 --- a/chrome/browser/notifications/scheduler/internal/impression_types.cc +++ b/chrome/browser/notifications/scheduler/internal/impression_types.cc
@@ -13,11 +13,15 @@ const base::Time& create_time) : create_time(create_time), guid(guid), type(type) {} +Impression::Impression(const Impression& other) = default; + +Impression::~Impression() = default; + bool Impression::operator==(const Impression& other) const { return create_time == other.create_time && feedback == other.feedback && impression == other.impression && integrated == other.integrated && task_start_time == other.task_start_time && guid == other.guid && - type == other.type; + type == other.type && impression_mapping == other.impression_mapping; } SuppressionInfo::SuppressionInfo(const base::Time& last_trigger,
diff --git a/chrome/browser/notifications/scheduler/internal/impression_types.h b/chrome/browser/notifications/scheduler/internal/impression_types.h index 876ada57..f01f05083 100644 --- a/chrome/browser/notifications/scheduler/internal/impression_types.h +++ b/chrome/browser/notifications/scheduler/internal/impression_types.h
@@ -29,6 +29,8 @@ Impression(SchedulerClientType type, const std::string& guid, const base::Time& create_time); + Impression(const Impression& other); + ~Impression(); bool operator==(const Impression& other) const; @@ -58,6 +60,9 @@ // initialized. // TODO(xingliu): Consider to persist this as well. SchedulerClientType type = SchedulerClientType::kUnknown; + + // Used to override default impression result. + std::map<UserFeedback, ImpressionResult> impression_mapping; }; // Contains details about supression and recovery after suppression expired.
diff --git a/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc b/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc index 02c5aa2..f64de7f 100644 --- a/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc +++ b/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc
@@ -16,7 +16,6 @@ #include "chrome/browser/notifications/scheduler/internal/background_task_coordinator.h" #include "chrome/browser/notifications/scheduler/internal/display_decider.h" #include "chrome/browser/notifications/scheduler/internal/distribution_policy.h" -#include "chrome/browser/notifications/scheduler/internal/icon_store.h" #include "chrome/browser/notifications/scheduler/internal/impression_history_tracker.h" #include "chrome/browser/notifications/scheduler/internal/notification_entry.h" #include "chrome/browser/notifications/scheduler/internal/notification_scheduler_context.h" @@ -62,23 +61,13 @@ impression_tracker_delegate_ = impression_tracker_delegate; callback_ = std::move(callback); - context->icon_store()->Init(base::BindOnce( - &InitHelper::OnIconStoreInitialized, weak_ptr_factory_.GetWeakPtr())); - } - - private: - void OnIconStoreInitialized(bool success) { - if (!success) { - std::move(callback_).Run(false /*success*/); - return; - } - context_->impression_tracker()->Init( impression_tracker_delegate_, base::BindOnce(&InitHelper::OnImpressionTrackerInitialized, weak_ptr_factory_.GetWeakPtr())); } + private: void OnImpressionTrackerInitialized(bool success) { if (!success) { std::move(callback_).Run(false /*success*/);
diff --git a/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.cc b/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.cc index 2694a781..196d864 100644 --- a/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.cc +++ b/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.cc
@@ -10,7 +10,6 @@ #include "base/time/default_clock.h" #include "chrome/browser/notifications/scheduler/internal/background_task_coordinator.h" #include "chrome/browser/notifications/scheduler/internal/display_decider.h" -#include "chrome/browser/notifications/scheduler/internal/icon_store.h" #include "chrome/browser/notifications/scheduler/internal/impression_history_tracker.h" #include "chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.h" #include "chrome/browser/notifications/scheduler/internal/scheduler_config.h" @@ -24,14 +23,12 @@ NotificationSchedulerContext::NotificationSchedulerContext( std::unique_ptr<NotificationSchedulerClientRegistrar> client_registrar, std::unique_ptr<NotificationBackgroundTaskScheduler> background_task, - std::unique_ptr<IconStore> icon_store, std::unique_ptr<ImpressionHistoryTracker> impression_tracker, std::unique_ptr<ScheduledNotificationManager> notification_manager, std::unique_ptr<DisplayAgent> display_agent, std::unique_ptr<DisplayDecider> display_decider, std::unique_ptr<SchedulerConfig> config) : client_registrar_(std::move(client_registrar)), - icon_store_(std::move(icon_store)), impression_tracker_(std::move(impression_tracker)), notification_manager_(std::move(notification_manager)), display_agent_(std::move(display_agent)),
diff --git a/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.h b/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.h index e01299e6..6de0494 100644 --- a/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.h +++ b/chrome/browser/notifications/scheduler/internal/notification_scheduler_context.h
@@ -16,7 +16,6 @@ class BackgroundTaskCoordinator; class DisplayAgent; class DisplayDecider; -class IconStore; class ImpressionHistoryTracker; class NotificationBackgroundTaskScheduler; class NotificationSchedulerClientRegistrar; @@ -30,7 +29,6 @@ NotificationSchedulerContext( std::unique_ptr<NotificationSchedulerClientRegistrar> client_registrar, std::unique_ptr<NotificationBackgroundTaskScheduler> background_task, - std::unique_ptr<IconStore> icon_store, std::unique_ptr<ImpressionHistoryTracker> impression_tracker, std::unique_ptr<ScheduledNotificationManager> notification_manager, std::unique_ptr<DisplayAgent> display_agent, @@ -46,8 +44,6 @@ return background_task_coordinator_.get(); } - IconStore* icon_store() { return icon_store_.get(); } - ImpressionHistoryTracker* impression_tracker() { return impression_tracker_.get(); } @@ -66,9 +62,6 @@ // Holds a list of clients using the notification scheduler system. std::unique_ptr<NotificationSchedulerClientRegistrar> client_registrar_; - // Stores notification icons. - std::unique_ptr<IconStore> icon_store_; - // Tracks user impressions towards specific notification type. std::unique_ptr<ImpressionHistoryTracker> impression_tracker_;
diff --git a/chrome/browser/notifications/scheduler/internal/proto_conversion.cc b/chrome/browser/notifications/scheduler/internal/proto_conversion.cc index 2167858..e716adc 100644 --- a/chrome/browser/notifications/scheduler/internal/proto_conversion.cc +++ b/chrome/browser/notifications/scheduler/internal/proto_conversion.cc
@@ -267,12 +267,28 @@ void ScheduleParamsToProto(ScheduleParams* params, proto::ScheduleParams* proto) { proto->set_priority(ScheduleParamsPriorityToProto(params->priority)); + + for (const auto& mapping : params->impression_mapping) { + auto* proto_impression_mapping = proto->add_impression_mapping(); + proto_impression_mapping->set_user_feedback(ToUserFeedback(mapping.first)); + proto_impression_mapping->set_impression_result( + ToImpressionResult(mapping.second)); + } } // Converts ScheduleParams from proto buffer type. void ScheduleParamsFromProto(proto::ScheduleParams* proto, ScheduleParams* params) { params->priority = ScheduleParamsPriorityFromProto(proto->priority()); + + for (int i = 0; i < proto->impression_mapping_size(); ++i) { + const auto& proto_impression_mapping = proto->impression_mapping(i); + auto user_feedback = + FromUserFeedback(proto_impression_mapping.user_feedback()); + auto impression_result = + FromImpressionResult(proto_impression_mapping.impression_result()); + params->impression_mapping[user_feedback] = impression_result; + } } } // namespace @@ -303,6 +319,14 @@ impression_ptr->set_task_start_time( ToSchedulerTaskTime(impression.task_start_time)); impression_ptr->set_guid(impression.guid); + + for (const auto& mapping : impression.impression_mapping) { + auto* proto_impression_mapping = impression_ptr->add_impression_mapping(); + proto_impression_mapping->set_user_feedback( + ToUserFeedback(mapping.first)); + proto_impression_mapping->set_impression_result( + ToImpressionResult(mapping.second)); + } } if (client_state->suppression_info.has_value()) { @@ -334,6 +358,17 @@ FromSchedulerTaskTime(proto_impression.task_start_time()); impression.guid = proto_impression.guid(); impression.type = client_state->type; + + for (int i = 0; i < proto_impression.impression_mapping_size(); ++i) { + const auto& proto_impression_mapping = + proto_impression.impression_mapping(i); + auto user_feedback = + FromUserFeedback(proto_impression_mapping.user_feedback()); + auto impression_result = + FromImpressionResult(proto_impression_mapping.impression_result()); + impression.impression_mapping[user_feedback] = impression_result; + } + client_state->impressions.emplace_back(std::move(impression)); }
diff --git a/chrome/browser/notifications/scheduler/internal/proto_conversion_unittest.cc b/chrome/browser/notifications/scheduler/internal/proto_conversion_unittest.cc index 20ccd82..0cccc36 100644 --- a/chrome/browser/notifications/scheduler/internal/proto_conversion_unittest.cc +++ b/chrome/browser/notifications/scheduler/internal/proto_conversion_unittest.cc
@@ -149,6 +149,11 @@ first_impression.task_start_time = task_start_time; TestClientStateConversion(&client_state); } + + // Verify impression mapping. + first_impression.impression_mapping[UserFeedback::kClick] = + ImpressionResult::kNeutral; + TestClientStateConversion(&client_state); } // Verifies multiple impressions are serialized correctly. @@ -195,6 +200,11 @@ entry.schedule_params.priority = priority; TestNotificationEntryConversion(&entry); } + entry.schedule_params.impression_mapping[UserFeedback::kDismiss] = + ImpressionResult::kPositive; + entry.schedule_params.impression_mapping[UserFeedback::kClick] = + ImpressionResult::kNeutral; + TestNotificationEntryConversion(&entry); } // Verifies buttons are converted correctly to proto buffers.
diff --git a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc index 539d6ff6..23acc2f 100644 --- a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc +++ b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.cc
@@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/guid.h" #include "base/memory/weak_ptr.h" +#include "chrome/browser/notifications/scheduler/internal/icon_store.h" #include "chrome/browser/notifications/scheduler/internal/notification_entry.h" #include "chrome/browser/notifications/scheduler/internal/scheduler_config.h" #include "chrome/browser/notifications/scheduler/public/notification_params.h" @@ -27,13 +28,15 @@ class ScheduledNotificationManagerImpl : public ScheduledNotificationManager { public: - using Store = std::unique_ptr<CollectionStore<NotificationEntry>>; + using NotificationStore = std::unique_ptr<CollectionStore<NotificationEntry>>; ScheduledNotificationManagerImpl( - Store store, + NotificationStore notification_store, + std::unique_ptr<IconStore> icon_store, const std::vector<SchedulerClientType>& clients, const SchedulerConfig& config) - : store_(std::move(store)), + : notification_store_(std::move(notification_store)), + icon_store_(std::move(icon_store)), clients_(clients.begin(), clients.end()), delegate_(nullptr), config_(config), @@ -43,9 +46,10 @@ void Init(Delegate* delegate, InitCallback callback) override { DCHECK(!delegate_); delegate_ = delegate; - store_->InitAndLoad( - base::BindOnce(&ScheduledNotificationManagerImpl::OnStoreInitialized, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + + notification_store_->InitAndLoad(base::BindOnce( + &ScheduledNotificationManagerImpl::OnNotificationStoreInitialized, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } // NotificationManager implementation. @@ -69,7 +73,7 @@ entry->schedule_params = std::move(notification_params->schedule_params); auto* entry_ptr = entry.get(); notifications_[type][guid] = std::move(entry); - store_->Add( + notification_store_->Add( guid, *entry_ptr, base::BindOnce(&ScheduledNotificationManagerImpl::OnNotificationAdded, weak_ptr_factory_.GetWeakPtr())); @@ -88,7 +92,7 @@ if (notifications_[entry->type].empty()) notifications_.erase(entry->type); - store_->Delete( + notification_store_->Delete( guid, base::BindOnce(&ScheduledNotificationManagerImpl::OnNotificationDeleted, weak_ptr_factory_.GetWeakPtr())); @@ -133,7 +137,7 @@ while (it != notifications_[type].end()) { const auto& entry = *it->second; ++it; - store_->Delete( + notification_store_->Delete( entry.guid, base::BindOnce( &ScheduledNotificationManagerImpl::OnNotificationDeleted, @@ -155,9 +159,10 @@ } } - void OnStoreInitialized(InitCallback callback, - bool success, - CollectionStore<NotificationEntry>::Entries entries) { + void OnNotificationStoreInitialized( + InitCallback callback, + bool success, + CollectionStore<NotificationEntry>::Entries entries) { if (!success) { std::move(callback).Run(false); return; @@ -169,7 +174,7 @@ bool expired = entry->create_time + config_.notification_expiration <= base::Time::Now(); if (expired) { - store_->Delete( + notification_store_->Delete( entry->guid, base::BindOnce( &ScheduledNotificationManagerImpl::OnNotificationDeleted, @@ -179,14 +184,26 @@ } } SyncRegisteredClients(); - std::move(callback).Run(true); + + icon_store_->Init(base::BindOnce( + &ScheduledNotificationManagerImpl::OnIconStoreInitialized, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); + } + + void OnIconStoreInitialized(InitCallback callback, bool success) { + std::move(callback).Run(success); } void OnNotificationAdded(bool success) { NOTIMPLEMENTED(); } void OnNotificationDeleted(bool success) { NOTIMPLEMENTED(); } - Store store_; + void OnIconAdded(bool success) { NOTIMPLEMENTED(); } + + void OnIconDeleted(bool success) { NOTIMPLEMENTED(); } + + NotificationStore notification_store_; + std::unique_ptr<IconStore> icon_store_; const std::unordered_set<SchedulerClientType> clients_; Delegate* delegate_; std::map<SchedulerClientType, @@ -201,11 +218,12 @@ // static std::unique_ptr<ScheduledNotificationManager> ScheduledNotificationManager::Create( - std::unique_ptr<CollectionStore<NotificationEntry>> store, + std::unique_ptr<CollectionStore<NotificationEntry>> notification_store, + std::unique_ptr<IconStore> icon_store, const std::vector<SchedulerClientType>& clients, const SchedulerConfig& config) { - return std::make_unique<ScheduledNotificationManagerImpl>(std::move(store), - clients, config); + return std::make_unique<ScheduledNotificationManagerImpl>( + std::move(notification_store), std::move(icon_store), clients, config); } ScheduledNotificationManager::ScheduledNotificationManager() = default;
diff --git a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.h b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.h index 1d100882f..f228dad 100644 --- a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.h +++ b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.h
@@ -19,6 +19,7 @@ struct NotificationEntry; struct NotificationParams; struct SchedulerConfig; +class IconStore; // Class to manage in-memory scheduled notifications loaded from the storage. class ScheduledNotificationManager { @@ -43,7 +44,8 @@ // Creates the instance. static std::unique_ptr<ScheduledNotificationManager> Create( - std::unique_ptr<CollectionStore<NotificationEntry>> store, + std::unique_ptr<CollectionStore<NotificationEntry>> notification_store, + std::unique_ptr<IconStore> icon_store, const std::vector<SchedulerClientType>& clients, const SchedulerConfig& config);
diff --git a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc index c4d91e2..21d492c 100644 --- a/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc +++ b/chrome/browser/notifications/scheduler/internal/scheduled_notification_manager_unittest.cc
@@ -10,6 +10,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_task_environment.h" #include "chrome/browser/notifications/scheduler/internal/collection_store.h" +#include "chrome/browser/notifications/scheduler/internal/icon_store.h" #include "chrome/browser/notifications/scheduler/internal/notification_entry.h" #include "chrome/browser/notifications/scheduler/internal/scheduler_config.h" #include "chrome/browser/notifications/scheduler/public/notification_params.h" @@ -60,18 +61,37 @@ DISALLOW_COPY_AND_ASSIGN(MockNotificationStore); }; +class MockIconStore : public IconStore { + public: + MockIconStore() {} + + MOCK_METHOD1(Init, void(IconStore::InitCallback)); + MOCK_METHOD2(Load, void(const std::string&, IconStore::LoadCallback)); + MOCK_METHOD3(Add, + void(const std::string&, + std::unique_ptr<IconEntry>, + IconStore::UpdateCallback)); + MOCK_METHOD2(Delete, void(const std::string&, IconStore::UpdateCallback)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockIconStore); +}; + class ScheduledNotificationManagerTest : public testing::Test { public: - ScheduledNotificationManagerTest() : store_(nullptr) {} + ScheduledNotificationManagerTest() + : notification_store_(nullptr), icon_store_(nullptr) {} ~ScheduledNotificationManagerTest() override = default; void SetUp() override { delegate_ = std::make_unique<MockDelegate>(); - auto store = std::make_unique<MockNotificationStore>(); - store_ = store.get(); + auto notification_store = std::make_unique<MockNotificationStore>(); + auto icon_store = std::make_unique<MockIconStore>(); + notification_store_ = notification_store.get(); + icon_store_ = icon_store.get(); config_.notification_expiration = base::TimeDelta::FromDays(1); manager_ = ScheduledNotificationManager::Create( - std::move(store), + std::move(notification_store), std::move(icon_store), {SchedulerClientType::kTest1, SchedulerClientType::kTest2, SchedulerClientType::kTest3}, config_); @@ -79,7 +99,8 @@ protected: ScheduledNotificationManager* manager() { return manager_.get(); } - MockNotificationStore* store() { return store_; } + MockNotificationStore* notification_store() { return notification_store_; } + MockIconStore* icon_store() { return icon_store_; } MockDelegate* delegate() { return delegate_.get(); } const SchedulerConfig& config() const { return config_; } // Initializes the manager with predefined data in the store. @@ -92,11 +113,16 @@ } // Initialize the store and call the callback. - EXPECT_CALL(*store(), InitAndLoad(_)) + EXPECT_CALL(*notification_store(), InitAndLoad(_)) .WillOnce( Invoke([&entries](base::OnceCallback<void(bool, Entries)> cb) { std::move(cb).Run(true, std::move(entries)); })); + EXPECT_CALL(*icon_store(), Init(_)) + .WillOnce(Invoke([](base::OnceCallback<void(bool)> cb) { + std::move(cb).Run(true); + })); + base::RunLoop loop; manager()->Init(delegate(), base::BindOnce( @@ -111,7 +137,8 @@ private: base::test::ScopedTaskEnvironment scoped_task_environment_; std::unique_ptr<MockDelegate> delegate_; - MockNotificationStore* store_; + MockNotificationStore* notification_store_; + MockIconStore* icon_store_; std::vector<SchedulerClientType> clients_; std::unique_ptr<ScheduledNotificationManager> manager_; SchedulerConfig config_; @@ -121,7 +148,7 @@ // Verify that error is received when initialization failed. TEST_F(ScheduledNotificationManagerTest, InitFailed) { - EXPECT_CALL(*store(), InitAndLoad(_)) + EXPECT_CALL(*notification_store(), InitAndLoad(_)) .WillOnce(Invoke([](base::OnceCallback<void(bool, Entries)> cb) { std::move(cb).Run(false, Entries()); })); @@ -151,7 +178,7 @@ EXPECT_FALSE(guid.empty()); // Verify call contract. - EXPECT_CALL(*store(), Add(guid, _, _)); + EXPECT_CALL(*notification_store(), Add(guid, _, _)); manager()->ScheduleNotification(std::move(params)); // Verify in-memory data. @@ -174,7 +201,7 @@ SchedulerClientType::kTest1, NotificationData(), ScheduleParams()); // Verify call contract. - EXPECT_CALL(*store(), Add(_, _, _)); + EXPECT_CALL(*notification_store(), Add(_, _, _)); manager()->ScheduleNotification(std::move(params)); // Verify in-memory data. @@ -198,7 +225,7 @@ InitWithData(std::vector<NotificationEntry>({entry})); // Verify delegate and dependency call contract. - EXPECT_CALL(*store(), Delete(kGuid, _)); + EXPECT_CALL(*notification_store(), Delete(kGuid, _)); EXPECT_CALL(*delegate(), DisplayNotification(NotificationEntryIs(entry))); manager()->DisplayNotification(kGuid); @@ -266,24 +293,28 @@ manager()->GetAllNotifications(¬ifications); EXPECT_EQ(notifications.size(), 3u); - EXPECT_CALL(*store(), Delete(_, _)).Times(2).RetiresOnSaturation(); + EXPECT_CALL(*notification_store(), Delete(_, _)) + .Times(2) + .RetiresOnSaturation(); manager()->DeleteNotifications(SchedulerClientType::kTest2); manager()->GetAllNotifications(¬ifications); EXPECT_EQ(notifications.size(), 2u); // Ensure deleting non-existing key will not crash, and store will not call // Delete. - EXPECT_CALL(*store(), Delete(_, _)).Times(0).RetiresOnSaturation(); + EXPECT_CALL(*notification_store(), Delete(_, _)) + .Times(0) + .RetiresOnSaturation(); manager()->DeleteNotifications(SchedulerClientType::kTest2); manager()->GetAllNotifications(¬ifications); EXPECT_EQ(notifications.size(), 2u); - EXPECT_CALL(*store(), Delete(_, _)).RetiresOnSaturation(); + EXPECT_CALL(*notification_store(), Delete(_, _)).RetiresOnSaturation(); manager()->DeleteNotifications(SchedulerClientType::kTest1); manager()->GetAllNotifications(¬ifications); EXPECT_EQ(notifications.size(), 1u); - EXPECT_CALL(*store(), Delete(_, _)).RetiresOnSaturation(); + EXPECT_CALL(*notification_store(), Delete(_, _)).RetiresOnSaturation(); manager()->DeleteNotifications(SchedulerClientType::kTest3); manager()->GetAllNotifications(¬ifications); EXPECT_EQ(notifications.size(), 0u); @@ -308,7 +339,9 @@ entry5.create_time = now - base::TimeDelta::FromDays(1) - base::TimeDelta::FromMicroseconds(1); - EXPECT_CALL(*store(), Delete(_, _)).Times(3).RetiresOnSaturation(); + EXPECT_CALL(*notification_store(), Delete(_, _)) + .Times(3) + .RetiresOnSaturation(); InitWithData(std::vector<NotificationEntry>( {entry0, entry1, entry2, entry3, entry4, entry5})); ScheduledNotificationManager::Notifications notifications;
diff --git a/chrome/browser/notifications/scheduler/public/schedule_params.cc b/chrome/browser/notifications/scheduler/public/schedule_params.cc index b926dd1..c01fda3 100644 --- a/chrome/browser/notifications/scheduler/public/schedule_params.cc +++ b/chrome/browser/notifications/scheduler/public/schedule_params.cc
@@ -8,8 +8,11 @@ ScheduleParams::ScheduleParams() : priority(Priority::kLow) {} +ScheduleParams::ScheduleParams(const ScheduleParams& other) = default; + bool ScheduleParams::operator==(const ScheduleParams& other) const { - return priority == other.priority; + return priority == other.priority && + impression_mapping == other.impression_mapping; } ScheduleParams::~ScheduleParams() = default;
diff --git a/chrome/browser/notifications/scheduler/public/schedule_params.h b/chrome/browser/notifications/scheduler/public/schedule_params.h index f4ce176..31b9655 100644 --- a/chrome/browser/notifications/scheduler/public/schedule_params.h +++ b/chrome/browser/notifications/scheduler/public/schedule_params.h
@@ -5,6 +5,10 @@ #ifndef CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_PUBLIC_SCHEDULE_PARAMS_H_ #define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_PUBLIC_SCHEDULE_PARAMS_H_ +#include <map> + +#include "chrome/browser/notifications/scheduler/public/notification_scheduler_types.h" + namespace notifications { // Specifies when to show the scheduled notification, and throttling details. @@ -23,10 +27,19 @@ }; ScheduleParams(); + ScheduleParams(const ScheduleParams& other); bool operator==(const ScheduleParams& other) const; ~ScheduleParams(); Priority priority; + + // Override the default mapping from an user action to impression result. By + // default, click on the notification and helpful button click are positive + // impression and may increase feature exposure. Unhelp button click is + // negative impression and may reduce feature exposure. Dimiss/close + // notification is neutural. Only put value when need to change the default + // mapping. + std::map<UserFeedback, ImpressionResult> impression_mapping; }; } // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc index d9b9b1fd..c46c331 100644 --- a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc +++ b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc
@@ -79,13 +79,13 @@ auto notification_store = std::make_unique<NotificationStore>(std::move(notification_db)); auto notification_manager = ScheduledNotificationManager::Create( - std::move(notification_store), registered_clients, *config.get()); + std::move(notification_store), std::move(icon_store), registered_clients, + *config.get()); auto context = std::make_unique<NotificationSchedulerContext>( std::move(client_registrar), std::move(background_task_scheduler), - std::move(icon_store), std::move(impression_tracker), - std::move(notification_manager), std::move(display_agent), - DisplayDecider::Create(), std::move(config)); + std::move(impression_tracker), std::move(notification_manager), + std::move(display_agent), DisplayDecider::Create(), std::move(config)); auto scheduler = NotificationScheduler::Create(std::move(context)); auto init_aware_scheduler =
diff --git a/chrome/browser/notifications/scheduler/test/test_utils.cc b/chrome/browser/notifications/scheduler/test/test_utils.cc index c64a3b4..721dd1f 100644 --- a/chrome/browser/notifications/scheduler/test/test_utils.cc +++ b/chrome/browser/notifications/scheduler/test/test_utils.cc
@@ -100,6 +100,11 @@ << " \n schedule params: priority:" << static_cast<int>(entry->schedule_params.priority); + for (const auto& mapping : entry->schedule_params.impression_mapping) { + stream << " \n impression mapping: " << static_cast<int>(mapping.first) + << " : " << static_cast<int>(mapping.second); + } + stream << " \n icons_id:"; for (const auto& icon_id : entry->icons_uuid) stream << icon_id << " "; @@ -130,6 +135,12 @@ << static_cast<int>(impression.task_start_time) << "\n" << "guid: " << impression.guid << "\n" << "type: " << static_cast<int>(impression.type); + + for (const auto& mapping : impression.impression_mapping) { + stream << " \n impression mapping: " << static_cast<int>(mapping.first) + << " : " << static_cast<int>(mapping.second); + } + log += stream.str(); }
diff --git a/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.cc index aa3f58ab..793ea4bc 100644 --- a/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.cc
@@ -39,9 +39,9 @@ const char kHistogramAMPSubframeLargestContentPaintFullNavigation[] = "PaintTiming.InputToLargestContentPaint.Subframe.FullNavigation"; const char kHistogramAMPSubframeFirstInputDelay[] = - "InteractiveTiming.FirstInputDelay3.Subframe"; + "InteractiveTiming.FirstInputDelay4.Subframe"; const char kHistogramAMPSubframeFirstInputDelayFullNavigation[] = - "InteractiveTiming.FirstInputDelay3.Subframe.FullNavigation"; + "InteractiveTiming.FirstInputDelay4.Subframe.FullNavigation"; const char kHistogramAMPSubframeLayoutStabilityJankScore[] = "Experimental.LayoutStability.JankScore.Subframe"; const char kHistogramAMPSubframeLayoutStabilityJankScoreFullNavigation[] = @@ -393,7 +393,7 @@ if (subframe_info.timing->interactive_timing->first_input_delay .has_value()) { - builder.SetSubFrame_InteractiveTiming_FirstInputDelay3( + builder.SetSubFrame_InteractiveTiming_FirstInputDelay4( subframe_info.timing->interactive_timing->first_input_delay.value() .InMilliseconds());
diff --git a/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer_unittest.cc index 2826809..9d01f65 100644 --- a/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer_unittest.cc
@@ -337,13 +337,13 @@ "PageLoad.Clients.AMP.PaintTiming.InputToLargestContentPaint.Subframe", 1); histogram_tester().ExpectTotalCount( - "PageLoad.Clients.AMP.InteractiveTiming.FirstInputDelay3.Subframe", 1); + "PageLoad.Clients.AMP.InteractiveTiming.FirstInputDelay4.Subframe", 1); ukm::mojom::UkmEntryPtr entry = GetAmpPageLoadUkmEntry(amp_url); ASSERT_NE(nullptr, entry.get()); test_ukm_recorder().ExpectEntrySourceHasUrl(entry.get(), amp_url); test_ukm_recorder().ExpectEntryMetric( - entry.get(), "SubFrame.InteractiveTiming.FirstInputDelay3", 3); + entry.get(), "SubFrame.InteractiveTiming.FirstInputDelay4", 3); test_ukm_recorder().ExpectEntryMetric( entry.get(), "SubFrame.PaintTiming.NavigationToFirstContentfulPaint", 5); test_ukm_recorder().ExpectEntryMetric( @@ -438,14 +438,14 @@ "FullNavigation", 1); histogram_tester().ExpectTotalCount( - "PageLoad.Clients.AMP.InteractiveTiming.FirstInputDelay3.Subframe." + "PageLoad.Clients.AMP.InteractiveTiming.FirstInputDelay4.Subframe." "FullNavigation", 1); ukm::mojom::UkmEntryPtr entry = GetAmpPageLoadUkmEntry(amp_url); test_ukm_recorder().ExpectEntrySourceHasUrl(entry.get(), amp_url); test_ukm_recorder().ExpectEntryMetric( - entry.get(), "SubFrame.InteractiveTiming.FirstInputDelay3", 3); + entry.get(), "SubFrame.InteractiveTiming.FirstInputDelay4", 3); test_ukm_recorder().ExpectEntryMetric( entry.get(), "SubFrame.PaintTiming.NavigationToFirstContentfulPaint", 5); test_ukm_recorder().ExpectEntryMetric(
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc index c55d71a..7edb0ea 100644 --- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
@@ -1316,11 +1316,11 @@ NavigateAndCommit(GURL(kDefaultTestUrl2)); EXPECT_THAT( - histogram_tester().GetAllSamples(internal::kHistogramFirstInputDelay), + histogram_tester().GetAllSamples(internal::kHistogramFirstInputDelay4), testing::ElementsAre(base::Bucket(5, 1))); - EXPECT_THAT( - histogram_tester().GetAllSamples(internal::kHistogramFirstInputTimestamp), - testing::ElementsAre(base::Bucket(4780, 1))); + EXPECT_THAT(histogram_tester().GetAllSamples( + internal::kHistogramFirstInputTimestamp4), + testing::ElementsAre(base::Bucket(4780, 1))); } TEST_F(CorePageLoadMetricsObserverTest, LongestInputDelayAndTimestamp) {
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc index 01fccd6..f6b5f8b 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -833,9 +833,9 @@ test_ukm_recorder().ExpectEntrySourceHasUrl(kv.second.get(), GURL(kTestUrl1)); test_ukm_recorder().ExpectEntryMetric( - kv.second.get(), PageLoad::kInteractiveTiming_FirstInputDelay3Name, 50); + kv.second.get(), PageLoad::kInteractiveTiming_FirstInputDelay4Name, 50); test_ukm_recorder().ExpectEntryMetric( - kv.second.get(), PageLoad::kInteractiveTiming_FirstInputTimestamp3Name, + kv.second.get(), PageLoad::kInteractiveTiming_FirstInputTimestamp4Name, 712); } }
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index 970f8ea..80185b6 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -489,8 +489,8 @@ GetPasswordProtectionService(); if (pps) { pps->MaybeStartPasswordFieldOnFocusRequest( - web_contents(), GetMainFrameURL(), form_action, frame_url, - pps->GetAccountInfo().hosted_domain); + web_contents(), web_contents()->GetLastCommittedURL(), form_action, + frame_url, pps->GetAccountInfo().hosted_domain); } } @@ -516,9 +516,9 @@ (password_type == PasswordType::PRIMARY_ACCOUNT_PASSWORD) && (sync && sync->IsSyncFeatureActive() && !sync->IsLocalSyncEnabled()); pps->MaybeStartProtectedPasswordEntryRequest( - web_contents(), GetMainFrameURL(), username, password_type, - pps->GetAccountInfo().hosted_domain, is_account_syncing, matching_domains, - password_field_exists); + web_contents(), web_contents()->GetLastCommittedURL(), username, + password_type, pps->GetAccountInfo().hosted_domain, is_account_syncing, + matching_domains, password_field_exists); } void ChromePasswordManagerClient::LogPasswordReuseDetectedEvent() {
diff --git a/chrome/browser/payments/manifest_verifier_browsertest.cc b/chrome/browser/payments/manifest_verifier_browsertest.cc index 4f23aa1..c0a89c69 100644 --- a/chrome/browser/payments/manifest_verifier_browsertest.cc +++ b/chrome/browser/payments/manifest_verifier_browsertest.cc
@@ -22,6 +22,7 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/url_request/url_request_context_getter.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/re2/src/re2/re2.h" namespace payments { namespace { @@ -75,6 +76,8 @@ return verified_apps_; } + const std::string& error_message() const { return error_message_; } + // Expects that the verified payment app with |id| has the |expected_scope| // and the |expected_methods| and the // |expect_has_explicitly_verified_methods|. @@ -90,13 +93,16 @@ EXPECT_EQ(expected_methods, actual_methods); EXPECT_EQ(expect_has_explicitly_verified_methods, it->second->has_explicitly_verified_methods); + EXPECT_TRUE(error_message().empty()) << error_message(); } private: // Called by the verifier upon completed verification. These |apps| have only // valid payment methods. - void OnPaymentAppsVerified(content::PaymentAppProvider::PaymentApps apps) { + void OnPaymentAppsVerified(content::PaymentAppProvider::PaymentApps apps, + const std::string& error_message) { verified_apps_ = std::move(apps); + error_message_ = error_message; } // Serves the payment method manifest files. @@ -105,6 +111,8 @@ // The apps that have been verified by the Verify() method. content::PaymentAppProvider::PaymentApps verified_apps_; + std::string error_message_; + DISALLOW_COPY_AND_ASSIGN(ManifestVerifierBrowserTest); }; @@ -115,6 +123,7 @@ Verify(content::PaymentAppProvider::PaymentApps()); EXPECT_TRUE(verified_apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -122,6 +131,7 @@ Verify(content::PaymentAppProvider::PaymentApps()); EXPECT_TRUE(verified_apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -135,6 +145,7 @@ Verify(std::move(apps)); EXPECT_TRUE(verified_apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -146,6 +157,7 @@ Verify(std::move(apps)); EXPECT_TRUE(verified_apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -161,6 +173,7 @@ Verify(std::move(apps)); EXPECT_TRUE(verified_apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -173,6 +186,7 @@ Verify(std::move(apps)); EXPECT_TRUE(verified_apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -188,6 +202,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://bobpay.com/webpay", {"basic-card"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -201,6 +216,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://bobpay.com/webpay", {"basic-card"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -220,6 +236,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://bobpay.com/webpay", {"basic-card", "interledger"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -235,6 +252,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://bobpay.com/webpay", {"basic-card", "interledger"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -255,6 +273,7 @@ EXPECT_EQ(2U, verified_apps().size()); ExpectApp(0, "https://bobpay.com/webpay", {"basic-card"}, false); ExpectApp(1, "https://alicepay.com/webpay", {"basic-card"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -271,6 +290,7 @@ EXPECT_EQ(2U, verified_apps().size()); ExpectApp(0, "https://bobpay.com/webpay", {"basic-card"}, false); ExpectApp(1, "https://alicepay.com/webpay", {"basic-card"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -290,6 +310,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://bobpay.com/webpay", {"https://frankpay.com/webpay"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -303,6 +324,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://bobpay.com/webpay", {"https://frankpay.com/webpay"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -322,6 +344,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://404.com/webpay", {"https://frankpay.com/webpay"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -335,6 +358,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://404.com/webpay", {"https://frankpay.com/webpay"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -355,6 +379,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://bobpay.com/anything/here", {"https://bobpay.com/does/not/matter/whats/here"}, true); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -369,6 +394,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://bobpay.com/anything/here", {"https://bobpay.com/does/not/matter/whats/here"}, true); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -389,6 +415,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://404.com/anything/here", {"https://404.com/does/not/matter/whats/here"}, true); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -403,6 +430,7 @@ EXPECT_EQ(1U, verified_apps().size()); ExpectApp(0, "https://404.com/anything/here", {"https://404.com/does/not/matter/whats/here"}, true); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -430,6 +458,7 @@ ExpectApp(0, "https://alicepay.com/webpay", {"https://georgepay.com/webpay", "https://ikepay.com/webpay"}, true); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -450,6 +479,7 @@ ExpectApp(0, "https://alicepay.com/webpay", {"https://georgepay.com/webpay", "https://ikepay.com/webpay"}, true); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -472,6 +502,7 @@ {"basic-card", "https://alicepay.com/webpay2", "https://ikepay.com/webpay"}, true); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -490,36 +521,87 @@ {"basic-card", "https://alicepay.com/webpay2", "https://ikepay.com/webpay"}, true); + EXPECT_TRUE(error_message().empty()) << error_message(); } } // Verify that a payment handler from https://bobpay.com/webpay cannot use // payment method names that are unreachable websites, the origin of which does // not match that of the payment handler. -IN_PROC_BROWSER_TEST_F(ManifestVerifierBrowserTest, PaymentMethodName404) { +IN_PROC_BROWSER_TEST_F(ManifestVerifierBrowserTest, + SinglePaymentMethodName404) { + std::string expected_pattern = + "Unable to make a HEAD request to " + "\"https://127.0.0.1:\\d+/404.test/webpay\" for payment method manifest."; { content::PaymentAppProvider::PaymentApps apps; apps[0] = std::make_unique<content::StoredPaymentApp>(); - apps[0]->scope = GURL("https://bobpay.com/webpay"); - apps[0]->enabled_methods.push_back("https://404.com/webpay"); - apps[0]->enabled_methods.push_back("https://404aswell.com/webpay"); + apps[0]->scope = GURL("https://bobpay.test/webpay"); + apps[0]->enabled_methods.push_back("https://404.test/webpay"); Verify(std::move(apps)); EXPECT_TRUE(verified_apps().empty()); + EXPECT_TRUE(RE2::FullMatch(error_message(), expected_pattern)) + << "Actual error message \"" << error_message() + << "\" did not match expected pattern \"" << expected_pattern << "\"."; } // Repeat verifications should have identical results. { content::PaymentAppProvider::PaymentApps apps; apps[0] = std::make_unique<content::StoredPaymentApp>(); - apps[0]->scope = GURL("https://bobpay.com/webpay"); - apps[0]->enabled_methods.push_back("https://404.com/webpay"); - apps[0]->enabled_methods.push_back("https://404aswell.com/webpay"); + apps[0]->scope = GURL("https://bobpay.test/webpay"); + apps[0]->enabled_methods.push_back("https://404.test/webpay"); Verify(std::move(apps)); EXPECT_TRUE(verified_apps().empty()); + EXPECT_TRUE(RE2::FullMatch(error_message(), expected_pattern)) + << "Actual error message \"" << error_message() + << "\" did not match expected pattern \"" << expected_pattern << "\"."; + } +} + +// Verify that a payment handler from https://bobpay.com/webpay cannot use +// payment method names that are unreachable websites, the origin of which does +// not match that of the payment handler. Since multiple downloads fail, the +// error message will describe the first failure. +IN_PROC_BROWSER_TEST_F(ManifestVerifierBrowserTest, + MultiplePaymentMethodName404) { + std::string expected_pattern = + "Unable to make a HEAD request to " + "\"https://127.0.0.1:\\d+/404(aswell)?.test/webpay\" for payment method " + "manifest."; + { + content::PaymentAppProvider::PaymentApps apps; + apps[0] = std::make_unique<content::StoredPaymentApp>(); + apps[0]->scope = GURL("https://bobpay.test/webpay"); + apps[0]->enabled_methods.push_back("https://404.test/webpay"); + apps[0]->enabled_methods.push_back("https://404aswell.test/webpay"); + + Verify(std::move(apps)); + + EXPECT_TRUE(verified_apps().empty()); + EXPECT_TRUE(RE2::FullMatch(error_message(), expected_pattern)) + << "Actual error message \"" << error_message() + << "\" did not match expected pattern \"" << expected_pattern << "\"."; + } + + // Repeat verifications should have identical results. + { + content::PaymentAppProvider::PaymentApps apps; + apps[0] = std::make_unique<content::StoredPaymentApp>(); + apps[0]->scope = GURL("https://bobpay.test/webpay"); + apps[0]->enabled_methods.push_back("https://404.test/webpay"); + apps[0]->enabled_methods.push_back("https://404aswell.test/webpay"); + + Verify(std::move(apps)); + + EXPECT_TRUE(verified_apps().empty()); + EXPECT_TRUE(RE2::FullMatch(error_message(), expected_pattern)) + << "Actual error message \"" << error_message() + << "\" did not match expected pattern \"" << expected_pattern << "\"."; } } @@ -544,6 +626,7 @@ {"basic-card", "interledger", "payee-credit-transfer", "payer-credit-transfer", "tokenized-card"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat verifications should have identical results. @@ -565,6 +648,7 @@ {"basic-card", "interledger", "payee-credit-transfer", "payer-credit-transfer", "tokenized-card"}, false); + EXPECT_TRUE(error_message().empty()) << error_message(); } }
diff --git a/chrome/browser/payments/service_worker_payment_app_factory_browsertest.cc b/chrome/browser/payments/service_worker_payment_app_factory_browsertest.cc index cd6be44..8cf2cc7d 100644 --- a/chrome/browser/payments/service_worker_payment_app_factory_browsertest.cc +++ b/chrome/browser/payments/service_worker_payment_app_factory_browsertest.cc
@@ -30,6 +30,7 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/url_request/url_request_context_getter.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/re2/src/re2/re2.h" namespace payments { namespace { @@ -209,6 +210,9 @@ return installable_apps_; } + // Returns the error message from the service worker payment app factory. + const std::string& error_message() const { return error_message_; } + // Expects that the first app has the |expected_method|. void ExpectPaymentAppWithMethod(const std::string& expected_method) { ExpectPaymentAppFromScopeWithMethod(kDefaultScope, expected_method); @@ -258,9 +262,11 @@ // valid payment methods. void OnGotAllPaymentApps( content::PaymentAppProvider::PaymentApps apps, - ServiceWorkerPaymentAppFactory::InstallablePaymentApps installable_apps) { + ServiceWorkerPaymentAppFactory::InstallablePaymentApps installable_apps, + const std::string& error_message) { apps_ = std::move(apps); installable_apps_ = std::move(installable_apps); + error_message_ = error_message; } // Starts the |test_server| for |hostname|. Returns true on success. @@ -341,6 +347,9 @@ // GetAllPaymentAppsForMethods() method. ServiceWorkerPaymentAppFactory::InstallablePaymentApps installable_apps_; + // The error message returned by the service worker factory. + std::string error_message_; + base::test::ScopedFeatureList scoped_feature_list_; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerPaymentAppFactoryBrowserTest); @@ -354,6 +363,7 @@ EXPECT_TRUE(installable_apps().empty()); EXPECT_TRUE(apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -363,6 +373,7 @@ EXPECT_TRUE(installable_apps().empty()); EXPECT_TRUE(apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -378,6 +389,7 @@ EXPECT_TRUE(installable_apps().empty()); EXPECT_TRUE(apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -388,6 +400,7 @@ EXPECT_TRUE(installable_apps().empty()); EXPECT_TRUE(apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -402,6 +415,7 @@ EXPECT_TRUE(installable_apps().empty()); ASSERT_EQ(1U, apps().size()); ExpectPaymentAppWithMethod("basic-card"); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -412,6 +426,7 @@ EXPECT_TRUE(installable_apps().empty()); ASSERT_EQ(1U, apps().size()); ExpectPaymentAppWithMethod("basic-card"); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -426,6 +441,7 @@ EXPECT_TRUE(installable_apps().empty()); ASSERT_EQ(1U, apps().size()); ExpectPaymentAppWithMethod("https://alicepay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -436,6 +452,7 @@ EXPECT_TRUE(installable_apps().empty()); ASSERT_EQ(1U, apps().size()); ExpectPaymentAppWithMethod("https://alicepay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -452,6 +469,7 @@ EXPECT_TRUE(installable_apps().empty()); EXPECT_TRUE(apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -461,6 +479,7 @@ EXPECT_TRUE(installable_apps().empty()); EXPECT_TRUE(apps().empty()); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -477,6 +496,7 @@ EXPECT_TRUE(installable_apps().empty()); ASSERT_EQ(1U, apps().size()); ExpectPaymentAppWithMethod("https://frankpay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -486,6 +506,7 @@ EXPECT_TRUE(installable_apps().empty()); ASSERT_EQ(1U, apps().size()); ExpectPaymentAppWithMethod("https://frankpay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -503,6 +524,7 @@ EXPECT_TRUE(installable_apps().empty()); ASSERT_EQ(1U, apps().size()); ExpectPaymentAppWithMethod("https://georgepay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -512,6 +534,7 @@ EXPECT_TRUE(installable_apps().empty()); ASSERT_EQ(1U, apps().size()); ExpectPaymentAppWithMethod("https://georgepay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -533,6 +556,7 @@ "https://georgepay.com/webpay"); ExpectPaymentAppFromScopeWithMethod("/app2/", "https://georgepay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -545,6 +569,7 @@ "https://georgepay.com/webpay"); ExpectPaymentAppFromScopeWithMethod("/app2/", "https://georgepay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -569,6 +594,7 @@ "https://georgepay.com/webpay"); ExpectPaymentAppFromScopeWithMethod("/app2/", "https://frankpay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -582,6 +608,7 @@ "https://georgepay.com/webpay"); ExpectPaymentAppFromScopeWithMethod("/app2/", "https://frankpay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -597,6 +624,7 @@ EXPECT_TRUE(apps().empty()); ASSERT_EQ(1U, installable_apps().size()); ExpectInstallablePaymentAppInScope("https://kylepay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -606,6 +634,7 @@ EXPECT_TRUE(apps().empty()); ASSERT_EQ(1U, installable_apps().size()); ExpectInstallablePaymentAppInScope("https://kylepay.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -613,11 +642,18 @@ // redirects to a different site (https://kylepay.com/webpay). IN_PROC_BROWSER_TEST_F(ServiceWorkerPaymentAppFactoryBrowserTest, InvalidDifferentSiteRedirect) { + std::string expected_pattern = + "Cross-site redirect from \"https://larrypay.com:\\d+/webpay\" to " + "\"https://kylepay.com/webpay\" not allowed for payment manifests."; + { GetAllPaymentAppsForMethods({"https://larrypay.com/webpay"}); EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_TRUE(RE2::FullMatch(error_message(), expected_pattern)) + << "Actual error message \"" << error_message() + << "\" did not match expected pattern \"" << expected_pattern << "\"."; } // Repeat lookups should have identical results. @@ -626,6 +662,9 @@ EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_TRUE(RE2::FullMatch(error_message(), expected_pattern)) + << "Actual error message \"" << error_message() + << "\" did not match expected pattern \"" << expected_pattern << "\"."; } } @@ -633,11 +672,15 @@ // it redirects 4 times (charlie -> david -> frank -> george -> harry). IN_PROC_BROWSER_TEST_F(ServiceWorkerPaymentAppFactoryBrowserTest, FourRedirectsIsNotValid) { + std::string expected_error_message = + "Unable to download the payment manifest because reached the maximum " + "number of redirects."; { GetAllPaymentAppsForMethods({"https://charlie.example.com/webpay"}); EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_EQ(expected_error_message, error_message()); } // Repeat lookups should have identical results. @@ -646,6 +689,7 @@ EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_EQ(expected_error_message, error_message()); } } @@ -659,6 +703,7 @@ EXPECT_TRUE(apps().empty()); ASSERT_EQ(1U, installable_apps().size()); ExpectInstallablePaymentAppInScope("https://harry.example.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -668,6 +713,7 @@ EXPECT_TRUE(apps().empty()); ASSERT_EQ(1U, installable_apps().size()); ExpectInstallablePaymentAppInScope("https://harry.example.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -681,6 +727,7 @@ EXPECT_TRUE(apps().empty()); ASSERT_EQ(1U, installable_apps().size()); ExpectInstallablePaymentAppInScope("https://harry.example.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } // Repeat lookups should have identical results. @@ -690,6 +737,7 @@ EXPECT_TRUE(apps().empty()); ASSERT_EQ(1U, installable_apps().size()); ExpectInstallablePaymentAppInScope("https://harry.example.com/webpay"); + EXPECT_TRUE(error_message().empty()) << error_message(); } } @@ -698,11 +746,18 @@ // https://harry.example.com/payment-manifest.json. IN_PROC_BROWSER_TEST_F(ServiceWorkerPaymentAppFactoryBrowserTest, CrossOriginHttpLinkHeaderIsInvalid) { + std::string expected_pattern = + "Cross-origin payment method manifest " + "\"https://harry.example.com/payment-manifest.json\" not allowed for the " + "payment method \"https://ike.example.com:\\d+/webpay\"."; { GetAllPaymentAppsForMethods({"https://ike.example.com/webpay"}); EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_TRUE(RE2::FullMatch(error_message(), expected_pattern)) + << "Actual error message \"" << error_message() + << "\" did not match expected pattern \"" << expected_pattern << "\"."; } // Repeat lookups should have identical results. @@ -711,6 +766,9 @@ EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_TRUE(RE2::FullMatch(error_message(), expected_pattern)) + << "Actual error message \"" << error_message() + << "\" did not match expected pattern \"" << expected_pattern << "\"."; } } @@ -718,11 +776,18 @@ // its cross-origin default application https://harry.example.com/app.json. IN_PROC_BROWSER_TEST_F(ServiceWorkerPaymentAppFactoryBrowserTest, CrossOriginDefaultApplicationIsInvalid) { + std::string expected_pattern = + "Cross-origin default application https://harry.example.com/app.json not " + "allowed in payment method manifest " + "https://john.example.com:\\d+/payment-manifest.json."; { GetAllPaymentAppsForMethods({"https://john.example.com/webpay"}); EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_TRUE(RE2::FullMatch(error_message(), expected_pattern)) + << "Actual error message \"" << error_message() + << "\" did not match expected pattern \"" << expected_pattern << "\"."; } // Repeat lookups should have identical results. @@ -731,6 +796,9 @@ EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_TRUE(RE2::FullMatch(error_message(), expected_pattern)) + << "Actual error message \"" << error_message() + << "\" did not match expected pattern \"" << expected_pattern << "\"."; } } @@ -738,11 +806,15 @@ // its cross-origin service worker location https://harry.example.com/app.js. IN_PROC_BROWSER_TEST_F(ServiceWorkerPaymentAppFactoryBrowserTest, CrossOriginServiceWorkerIsInvalid) { + std::string expected_error_message = + "Cross-origin \"serviceworker\".\"src\" https://harry.example.com/app.js " + "not allowed in web app manifest https://kyle.example.com/app.json."; { GetAllPaymentAppsForMethods({"https://kyle.example.com/webpay"}); EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_EQ(expected_error_message, error_message()); } // Repeat lookups should have identical results. @@ -751,6 +823,7 @@ EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_EQ(expected_error_message, error_message()); } } @@ -758,11 +831,16 @@ // its cross-origin service worker scope https://harry.example.com/webpay/". IN_PROC_BROWSER_TEST_F(ServiceWorkerPaymentAppFactoryBrowserTest, CrossOriginServiceWorkerScopeIsInvalid) { + std::string expected_error_message = + "Cross-origin \"serviceworker\".\"scope\" " + "https://harry.example.com/webpay not allowed in web app manifest " + "https://larry.example.com/app.json."; { GetAllPaymentAppsForMethods({"https://larry.example.com/webpay"}); EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_EQ(expected_error_message, error_message()); } // Repeat lookups should have identical results. @@ -771,6 +849,7 @@ EXPECT_TRUE(apps().empty()); EXPECT_TRUE(installable_apps().empty()); + EXPECT_EQ(expected_error_message, error_message()); } }
diff --git a/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.cc b/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.cc index 34f76a5d..5132720 100644 --- a/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.cc +++ b/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.cc
@@ -7,7 +7,9 @@ #include <limits> #include <string> +#include "base/auto_reset.h" #include "base/bind.h" +#include "base/callback.h" #include "base/files/file_util.h" #include "base/hash/md5.h" #include "base/logging.h" @@ -20,12 +22,15 @@ #include "build/build_config.h" #include "third_party/leveldatabase/env_chromium.h" #include "third_party/leveldatabase/leveldb_chrome.h" +#include "third_party/leveldatabase/src/include/leveldb/env.h" #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" namespace performance_manager { namespace { +bool g_use_in_memory_db_for_testing = false; + // The name of the following histograms is the same as the one used in the // //c/b/resource_coordinator version of this file. It's fine to keep the same // name as these 2 codepath will never be enabled at the same time. These @@ -159,6 +164,12 @@ return db_.get(); } + void SetInitializationCallbackForTesting(base::OnceClosure callback) { + init_callback_for_testing_ = std::move(callback); + if (DBIsInitialized()) + std::move(init_callback_for_testing_).Run(); + } + private: enum class OpeningType { // A new database has been created. @@ -170,6 +181,10 @@ // Implementation for the OpenOrCreateDatabase function. OpeningType OpenOrCreateDatabaseImpl(); + // A levelDB environment that gets used for testing. This allows using an + // in-memory database when needed. + std::unique_ptr<leveldb::Env> env_for_testing_; + // The on disk location of the database. const base::FilePath db_path_; // The connection to the LevelDB database. @@ -179,12 +194,18 @@ // The options to be used for all database write operations. leveldb::WriteOptions write_options_; + base::OnceClosure init_callback_for_testing_; + SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(AsyncHelper); }; void LevelDBSiteDataStore::AsyncHelper::OpenOrCreateDatabase() { OpeningType opening_type = OpenOrCreateDatabaseImpl(); + + if (init_callback_for_testing_) + std::move(init_callback_for_testing_).Run(); + if (!db_) return; std::string db_metadata; @@ -362,6 +383,12 @@ leveldb_env::Options options; options.create_if_missing = true; + + if (g_use_in_memory_db_for_testing) { + env_for_testing_ = leveldb_chrome::NewMemEnv("LevelDBSiteDataStore"); + options.env = env_for_testing_.get(); + } + leveldb::Status status = leveldb_env::OpenDB(options, db_path_.AsUTF8Unsafe(), &db_); @@ -468,6 +495,16 @@ std::move(reply_callback)); } +void LevelDBSiteDataStore::SetInitializationCallbackForTesting( + base::OnceClosure callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + blocking_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&LevelDBSiteDataStore::AsyncHelper:: + SetInitializationCallbackForTesting, + base::Unretained(async_helper_.get()), + std::move(callback))); +} + bool LevelDBSiteDataStore::DatabaseIsInitializedForTesting() { return async_helper_->DBIsInitialized(); } @@ -476,4 +513,11 @@ return async_helper_->GetDBForTesting(); } +// static +std::unique_ptr<base::AutoReset<bool>> +LevelDBSiteDataStore::UseInMemoryDBForTesting() { + return std::make_unique<base::AutoReset<bool>>( + &g_use_in_memory_db_for_testing, true); +} + } // namespace performance_manager
diff --git a/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.h b/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.h index f3c54c0da..0e00bfa 100644 --- a/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.h +++ b/chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_PERSISTENCE_SITE_DATA_LEVELDB_SITE_DATA_STORE_H_ #define CHROME_BROWSER_PERFORMANCE_MANAGER_PERSISTENCE_SITE_DATA_LEVELDB_SITE_DATA_STORE_H_ +#include "base/auto_reset.h" #include "base/files/file_path.h" #include "base/macros.h" #include "base/sequence_checker.h" @@ -41,6 +42,7 @@ const std::vector<url::Origin>& site_origins) override; void ClearStore() override; void GetStoreSize(GetStoreSizeCallback callback) override; + void SetInitializationCallbackForTesting(base::OnceClosure callback) override; bool DatabaseIsInitializedForTesting(); @@ -51,6 +53,10 @@ // thread safe. leveldb::DB* GetDBForTesting(); + // Make the new instances of this class use an in memory database rather than + // creating it on disk. + static std::unique_ptr<base::AutoReset<bool>> UseInMemoryDBForTesting(); + static const size_t kDbVersion; static const char kDbMetadataKey[];
diff --git a/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.cc b/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.cc new file mode 100644 index 0000000..e9e0ec5 --- /dev/null +++ b/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.cc
@@ -0,0 +1,85 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h" + +#include "base/memory/ptr_util.h" +#include "chrome/browser/performance_manager/persistence/site_data/noop_site_data_writer.h" +#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h" +#include "chrome/browser/performance_manager/persistence/site_data/site_data_reader.h" +#include "chrome/browser/performance_manager/persistence/site_data/site_data_writer.h" + +namespace performance_manager { + +NonRecordingSiteDataCache::NonRecordingSiteDataCache( + const std::string& browser_context_id, + SiteDataCacheInspector* data_cache_inspector, + SiteDataCache* data_cache_for_readers) + : data_cache_for_readers_(data_cache_for_readers), + data_cache_inspector_(data_cache_inspector), + browser_context_id_(browser_context_id) { + DCHECK(data_cache_for_readers_); + // Register the debug interface against the browser context. + SiteDataCacheFactory::GetInstance()->SetDataCacheInspectorForBrowserContext( + this, browser_context_id_); +} + +NonRecordingSiteDataCache::~NonRecordingSiteDataCache() { + SiteDataCacheFactory::GetInstance()->SetDataCacheInspectorForBrowserContext( + nullptr, browser_context_id_); +} + +std::unique_ptr<SiteDataReader> NonRecordingSiteDataCache::GetReaderForOrigin( + const url::Origin& origin) { + return data_cache_for_readers_->GetReaderForOrigin(origin); +} + +std::unique_ptr<SiteDataWriter> NonRecordingSiteDataCache::GetWriterForOrigin( + const url::Origin& origin, + performance_manager::TabVisibility tab_visibility) { + // Return a fake data writer. + SiteDataWriter* writer = new NoopSiteDataWriter(); + return base::WrapUnique(writer); +} + +bool NonRecordingSiteDataCache::IsRecordingForTesting() { + return false; +} + +const char* NonRecordingSiteDataCache::GetDataCacheName() { + return "NonRecordingSiteDataCache"; +} + +std::vector<url::Origin> NonRecordingSiteDataCache::GetAllInMemoryOrigins() { + if (!data_cache_inspector_) + return std::vector<url::Origin>(); + + return data_cache_inspector_->GetAllInMemoryOrigins(); +} + +void NonRecordingSiteDataCache::GetDataStoreSize( + DataStoreSizeCallback on_have_data) { + if (!data_cache_inspector_) { + std::move(on_have_data).Run(base::nullopt, base::nullopt); + return; + } + + data_cache_inspector_->GetDataStoreSize(std::move(on_have_data)); +} + +bool NonRecordingSiteDataCache::GetDataForOrigin( + const url::Origin& origin, + bool* is_dirty, + std::unique_ptr<SiteDataProto>* data) { + if (!data_cache_inspector_) + return false; + + return data_cache_inspector_->GetDataForOrigin(origin, is_dirty, data); +} + +NonRecordingSiteDataCache* NonRecordingSiteDataCache::GetDataCache() { + return this; +} + +} // namespace performance_manager
diff --git a/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h b/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h new file mode 100644 index 0000000..b7d7ddd --- /dev/null +++ b/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h
@@ -0,0 +1,63 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_PERSISTENCE_SITE_DATA_NON_RECORDING_SITE_DATA_CACHE_H_ +#define CHROME_BROWSER_PERFORMANCE_MANAGER_PERSISTENCE_SITE_DATA_NON_RECORDING_SITE_DATA_CACHE_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/macros.h" +#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache.h" +#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_inspector.h" + +namespace performance_manager { + +// Implementation of a SiteDataCache that ensures that no data gets persisted. +// +// This class should be used for off the record profiles. +class NonRecordingSiteDataCache : public SiteDataCache, + public SiteDataCacheInspector { + public: + NonRecordingSiteDataCache(const std::string& browser_context_id, + SiteDataCacheInspector* data_cache_inspector, + SiteDataCache* data_cache_for_readers); + ~NonRecordingSiteDataCache() override; + + // SiteDataCache: + std::unique_ptr<SiteDataReader> GetReaderForOrigin( + const url::Origin& origin) override; + std::unique_ptr<SiteDataWriter> GetWriterForOrigin( + const url::Origin& origin, + performance_manager::TabVisibility tab_visibility) override; + bool IsRecordingForTesting() override; + + // SiteDataCacheInspector: + const char* GetDataCacheName() override; + std::vector<url::Origin> GetAllInMemoryOrigins() override; + void GetDataStoreSize(DataStoreSizeCallback on_have_data) override; + bool GetDataForOrigin(const url::Origin& origin, + bool* is_dirty, + std::unique_ptr<SiteDataProto>* data) override; + NonRecordingSiteDataCache* GetDataCache() override; + + private: + // The data cache to use to create the readers served by this data store. E.g. + // during an incognito session it should point to the data cache used by the + // parent session. + SiteDataCache* data_cache_for_readers_; + + // The inspector implementation this instance delegates to. + SiteDataCacheInspector* data_cache_inspector_; + + // The ID of the browser context this data store is associated with. + const std::string browser_context_id_; + + DISALLOW_COPY_AND_ASSIGN(NonRecordingSiteDataCache); +}; + +} // namespace performance_manager + +#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_PERSISTENCE_SITE_DATA_NON_RECORDING_SITE_DATA_CACHE_H_
diff --git a/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache_unittest.cc b/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache_unittest.cc new file mode 100644 index 0000000..bc694a3 --- /dev/null +++ b/chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache_unittest.cc
@@ -0,0 +1,144 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h" + +#include "chrome/browser/performance_manager/persistence/site_data/leveldb_site_data_store.h" +#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache.h" +#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h" +#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.h" +#include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_inspector.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace performance_manager { + +namespace { + +class NonRecordingSiteDataCacheTest : public testing::Test { + public: + NonRecordingSiteDataCacheTest() + : use_in_memory_db_for_testing_( + LevelDBSiteDataStore::UseInMemoryDBForTesting()), + factory_(SiteDataCacheFactory::CreateForTesting( + test_browser_thread_bundle_.GetMainThreadTaskRunner())), + off_the_record_profile_(parent_profile_.GetOffTheRecordProfile()) {} + + ~NonRecordingSiteDataCacheTest() override { factory_.reset(); } + + void SetUp() override { + recording_data_cache_ = base::WrapUnique(new SiteDataCacheImpl( + parent_profile_.UniqueId(), parent_profile_.GetPath())); + + // Wait for the database to be initialized. + base::RunLoop run_loop; + recording_data_cache_->SetInitializationCallbackForTesting( + run_loop.QuitClosure()); + run_loop.Run(); + + non_recording_data_cache_ = std::make_unique<NonRecordingSiteDataCache>( + off_the_record_profile_->UniqueId(), recording_data_cache_.get(), + recording_data_cache_.get()); + } + + protected: + const url::Origin kTestOrigin = + url::Origin::Create(GURL("http://www.foo.com")); + + content::TestBrowserThreadBundle test_browser_thread_bundle_; + + // Ensure that the database used by the data store owned by + // |recording_data_cache_| gets created in memory. This avoid having to wait + // for it to be fully closed before destroying |parent_profile_|. + std::unique_ptr<base::AutoReset<bool>> use_in_memory_db_for_testing_; + + // The data cache factory that will be used by the caches tested here. + std::unique_ptr<SiteDataCacheFactory, base::OnTaskRunnerDeleter> factory_; + + // The on the record profile. + TestingProfile parent_profile_; + // An off the record profile owned by |parent_profile|. + Profile* off_the_record_profile_; + + std::unique_ptr<SiteDataCacheImpl> recording_data_cache_; + std::unique_ptr<NonRecordingSiteDataCache> non_recording_data_cache_; +}; + +} // namespace + +TEST_F(NonRecordingSiteDataCacheTest, EndToEnd) { + // Ensures that the observation made via a writer created by the non + // recording data cache aren't recorded. + auto reader = non_recording_data_cache_->GetReaderForOrigin(kTestOrigin); + EXPECT_TRUE(reader); + auto fake_writer = non_recording_data_cache_->GetWriterForOrigin( + kTestOrigin, performance_manager::TabVisibility::kBackground); + EXPECT_TRUE(fake_writer); + auto real_writer = recording_data_cache_->GetWriterForOrigin( + kTestOrigin, performance_manager::TabVisibility::kBackground); + EXPECT_TRUE(real_writer); + + EXPECT_EQ(performance_manager::SiteFeatureUsage::kSiteFeatureUsageUnknown, + reader->UpdatesTitleInBackground()); + fake_writer->NotifySiteLoaded(); + fake_writer->NotifyUpdatesTitleInBackground(); + EXPECT_EQ(performance_manager::SiteFeatureUsage::kSiteFeatureUsageUnknown, + reader->UpdatesTitleInBackground()); + + real_writer->NotifySiteLoaded(); + real_writer->NotifyUpdatesTitleInBackground(); + EXPECT_EQ(performance_manager::SiteFeatureUsage::kSiteFeatureInUse, + reader->UpdatesTitleInBackground()); + + // These unload events shouldn't be registered, make sure that they aren't by + // unloading the site more time than it has been loaded. + fake_writer->NotifySiteUnloaded(); + fake_writer->NotifySiteUnloaded(); + + real_writer->NotifySiteUnloaded(); +} + +TEST_F(NonRecordingSiteDataCacheTest, InspectorWorks) { + // Make sure the inspector interface was registered at construction. + SiteDataCacheInspector* inspector = factory_->GetInspectorForBrowserContext( + off_the_record_profile_->UniqueId()); + EXPECT_NE(nullptr, inspector); + EXPECT_EQ(non_recording_data_cache_.get(), inspector); + + EXPECT_STREQ("NonRecordingSiteDataCache", inspector->GetDataCacheName()); + + // We expect an empty data cache at the outset. + EXPECT_EQ(0U, inspector->GetAllInMemoryOrigins().size()); + std::unique_ptr<SiteDataProto> data; + bool is_dirty = false; + EXPECT_FALSE(inspector->GetDataForOrigin(kTestOrigin, &is_dirty, &data)); + EXPECT_FALSE(is_dirty); + EXPECT_EQ(nullptr, data.get()); + + { + // Add an entry through the writing data cache, see that it's reflected in + // the inspector interface. + auto writer = recording_data_cache_->GetWriterForOrigin( + kTestOrigin, performance_manager::TabVisibility::kBackground); + + EXPECT_EQ(1U, inspector->GetAllInMemoryOrigins().size()); + EXPECT_TRUE(inspector->GetDataForOrigin(kTestOrigin, &is_dirty, &data)); + EXPECT_FALSE(is_dirty); + ASSERT_NE(nullptr, data.get()); + + // Touch the underlying data, see that the dirty bit updates. + writer->NotifySiteLoaded(); + EXPECT_TRUE(inspector->GetDataForOrigin(kTestOrigin, &is_dirty, &data)); + } + + // Make sure the interface is unregistered from the browser context on + // destruction. + non_recording_data_cache_.reset(); + EXPECT_EQ(nullptr, factory_->GetInspectorForBrowserContext( + off_the_record_profile_->UniqueId())); +} + +} // namespace performance_manager
diff --git a/chrome/browser/performance_manager/persistence/site_data/noop_site_data_writer.h b/chrome/browser/performance_manager/persistence/site_data/noop_site_data_writer.h index 0542377..3284ef7d 100644 --- a/chrome/browser/performance_manager/persistence/site_data/noop_site_data_writer.h +++ b/chrome/browser/performance_manager/persistence/site_data/noop_site_data_writer.h
@@ -30,8 +30,9 @@ uint64_t private_footprint_kb_estimate) override; private: - // Private constructor, these objects are meant to be created by a noop site - // data store. + friend class NonRecordingSiteDataCache; + // Private constructor, these objects are meant to be created by a + // NonRecordingSiteDataCache. NoopSiteDataWriter(); DISALLOW_COPY_AND_ASSIGN(NoopSiteDataWriter);
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.cc b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.cc index 3ca86dc..2ae7465 100644 --- a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.cc +++ b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.cc
@@ -9,8 +9,8 @@ #include "base/sequenced_task_runner.h" #include "base/stl_util.h" #include "base/task_runner_util.h" -#include "base/threading/sequenced_task_runner_handle.h" #include "chrome/browser/performance_manager/performance_manager.h" +#include "chrome/browser/performance_manager/persistence/site_data/non_recording_site_data_cache.h" #include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.h" #include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_inspector.h" #include "content/public/browser/browser_context.h" @@ -30,7 +30,6 @@ const scoped_refptr<base::SequencedTaskRunner> task_runner) : task_runner_(task_runner) { DETACH_FROM_SEQUENCE(sequence_checker_); - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } SiteDataCacheFactory::~SiteDataCacheFactory() { @@ -68,19 +67,24 @@ // static void SiteDataCacheFactory::OnBrowserContextCreatedOnUIThread( SiteDataCacheFactory* factory, - content::BrowserContext* browser_context) { + content::BrowserContext* browser_context, + content::BrowserContext* parent_context) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(factory); // As |factory| will be deleted on its task runner it's safe to pass the raw // pointer to BindOnce, it's guaranteed that this task will run before the // factory. + base::Optional<std::string> parent_context_id; + if (parent_context) { + DCHECK(browser_context->IsOffTheRecord()); + parent_context_id = parent_context->UniqueId(); + } factory->task_runner_->PostTask( FROM_HERE, base::BindOnce(&SiteDataCacheFactory::OnBrowserContextCreated, base::Unretained(factory), browser_context->UniqueId(), - browser_context->GetPath(), - browser_context->IsOffTheRecord())); + browser_context->GetPath(), parent_context_id)); } // static @@ -97,28 +101,28 @@ base::Unretained(factory), browser_context->UniqueId())); } -// static SiteDataCache* SiteDataCacheFactory::GetDataCacheForBrowserContext( const std::string& browser_context_id) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto it = data_cache_map_.find(browser_context_id); if (it != data_cache_map_.end()) return it->second.get(); return nullptr; } -// static SiteDataCacheInspector* SiteDataCacheFactory::GetInspectorForBrowserContext( const std::string& browser_context_id) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); auto it = data_cache_inspector_map_.find(browser_context_id); if (it != data_cache_inspector_map_.end()) return it->second; return nullptr; } -// static void SiteDataCacheFactory::SetDataCacheInspectorForBrowserContext( SiteDataCacheInspector* inspector, const std::string& browser_context_id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (inspector) { DCHECK_EQ(nullptr, GetInspectorForBrowserContext(browser_context_id)); data_cache_inspector_map_.emplace( @@ -132,14 +136,23 @@ void SiteDataCacheFactory::OnBrowserContextCreated( const std::string& browser_context_id, const base::FilePath& context_path, - bool context_is_off_the_record) { + base::Optional<std::string> parent_context_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!base::Contains(data_cache_map_, browser_context_id)); - if (context_is_off_the_record) { - // TODO(sebmarchand): Add support for off-the-record contexts. - NOTREACHED(); + if (parent_context_id) { + SiteDataCacheInspector* parent_debug = + GetInspectorForBrowserContext(parent_context_id.value()); + DCHECK(parent_debug); + DCHECK(base::Contains(data_cache_map_, parent_context_id.value())); + SiteDataCache* data_cache_for_readers = + data_cache_map_[parent_context_id.value()].get(); + DCHECK(data_cache_for_readers); + data_cache_map_.emplace(std::make_pair( + std::move(browser_context_id), + std::make_unique<NonRecordingSiteDataCache>( + browser_context_id, parent_debug, data_cache_for_readers))); } else { data_cache_map_.emplace(std::make_pair( std::move(browser_context_id),
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h index 88bdf8cc..f27b4006 100644 --- a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h +++ b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory.h
@@ -12,6 +12,7 @@ #include "base/files/file_path.h" #include "base/location.h" #include "base/macros.h" +#include "base/optional.h" #include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" #include "chrome/browser/performance_manager/persistence/site_data/site_data_cache.h" @@ -57,9 +58,14 @@ // destroyed. They should be called from the UI thread, a task will then be // posted to the task_runner owned by |factory| to create the data store // associated with this browser context. + // + // If this browser context is inheriting from a parent context (e.g. if it's + // off the record) then this parent context should be specified via + // |parent_context|. static void OnBrowserContextCreatedOnUIThread( SiteDataCacheFactory* factory, - content::BrowserContext* browser_context); + content::BrowserContext* browser_context, + content::BrowserContext* parent_context); static void OnBrowserContextDestroyedOnUIThread( SiteDataCacheFactory* factory, content::BrowserContext* browser_context); @@ -98,7 +104,7 @@ // that runs on this object's task runner. void OnBrowserContextCreated(const std::string& browser_context_id, const base::FilePath& context_path, - bool context_is_off_the_record); + base::Optional<std::string> parent_context_id); void OnBrowserContextDestroyed(const std::string& browser_context_id); // The task runner on which this object lives, this is expected to be the
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc index 3a4c6a22..3c49d47 100644 --- a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc +++ b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc
@@ -41,7 +41,7 @@ TEST_F(SiteDataCacheFactoryTest, EndToEnd) { SiteDataCacheFactory::OnBrowserContextCreatedOnUIThread(factory_.get(), - &profile_); + &profile_, nullptr); base::RunLoop run_loop; task_runner_->PostTask(
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.cc b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.cc index 06bb6895..4afd3c10 100644 --- a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.cc +++ b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.cc
@@ -6,6 +6,7 @@ #include <set> +#include "base/callback.h" #include "base/feature_list.h" #include "base/memory/ptr_util.h" #include "base/stl_util.h" @@ -158,4 +159,9 @@ data_store_->ClearStore(); } +void SiteDataCacheImpl::SetInitializationCallbackForTesting( + base::OnceClosure callback) { + data_store_->SetInitializationCallbackForTesting(std::move(callback)); +} + } // namespace performance_manager
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.h b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.h index 1469bf5..b7d84145 100644 --- a/chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.h +++ b/chrome/browser/performance_manager/persistence/site_data/site_data_cache_impl.h
@@ -10,6 +10,7 @@ #include <utility> #include <vector> +#include "base/callback_forward.h" #include "base/containers/flat_map.h" #include "base/files/file_path.h" #include "base/gtest_prod_util.h" @@ -36,7 +37,7 @@ const base::FilePath& browser_context_path); ~SiteDataCacheImpl() override; - // SiteCharacteristicDataCache: + // SiteDataCache: std::unique_ptr<SiteDataReader> GetReaderForOrigin( const url::Origin& origin) override; std::unique_ptr<SiteDataWriter> GetWriterForOrigin( @@ -70,6 +71,10 @@ // Clear the data cache and the on-disk store. void ClearAllSiteData(); + // Set a callback that will be called once the data store backing this cache + // has been fully initialized. + void SetInitializationCallbackForTesting(base::OnceClosure callback); + private: // Returns a pointer to the SiteDataImpl object associated with |origin|, // create one and add it to |origin_data_map_| if it doesn't exist.
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_impl_unittest.cc b/chrome/browser/performance_manager/persistence/site_data/site_data_impl_unittest.cc index b98f94c..72a4f69b 100644 --- a/chrome/browser/performance_manager/persistence/site_data/site_data_impl_unittest.cc +++ b/chrome/browser/performance_manager/persistence/site_data/site_data_impl_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/performance_manager/persistence/site_data/site_data_impl.h" +#include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/test/bind_test_util.h"
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_reader.cc b/chrome/browser/performance_manager/persistence/site_data/site_data_reader.cc index 9ed6c74..801988d 100644 --- a/chrome/browser/performance_manager/persistence/site_data/site_data_reader.cc +++ b/chrome/browser/performance_manager/persistence/site_data/site_data_reader.cc
@@ -7,6 +7,7 @@ #include <utility> #include "base/bind.h" +#include "base/callback.h" #include "chrome/browser/performance_manager/persistence/site_data/site_data_impl.h" namespace performance_manager {
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_reader_unittest.cc b/chrome/browser/performance_manager/persistence/site_data/site_data_reader_unittest.cc index 81354759..1cee22d 100644 --- a/chrome/browser/performance_manager/persistence/site_data/site_data_reader_unittest.cc +++ b/chrome/browser/performance_manager/persistence/site_data/site_data_reader_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include <utility> +#include "base/callback.h" #include "base/location.h" #include "base/macros.h" #include "base/memory/ptr_util.h"
diff --git a/chrome/browser/performance_manager/persistence/site_data/site_data_store.h b/chrome/browser/performance_manager/persistence/site_data/site_data_store.h index b91a0909..54d64d7 100644 --- a/chrome/browser/performance_manager/persistence/site_data/site_data_store.h +++ b/chrome/browser/performance_manager/persistence/site_data/site_data_store.h
@@ -7,7 +7,7 @@ #include <vector> -#include "base/callback.h" +#include "base/callback_forward.h" #include "base/macros.h" #include "base/optional.h" #include "chrome/browser/performance_manager/persistence/site_data/site_data.pb.h" @@ -52,6 +52,11 @@ // Retrieve the size of the store. virtual void GetStoreSize(GetStoreSizeCallback callback) = 0; + + // Set a callback that will be called once the data store has been fully + // initialized. + virtual void SetInitializationCallbackForTesting( + base::OnceClosure callback) = 0; }; } // namespace performance_manager
diff --git a/chrome/browser/performance_manager/persistence/site_data/unittest_utils.cc b/chrome/browser/performance_manager/persistence/site_data/unittest_utils.cc index 5b782dd..d39094f6 100644 --- a/chrome/browser/performance_manager/persistence/site_data/unittest_utils.cc +++ b/chrome/browser/performance_manager/persistence/site_data/unittest_utils.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "chrome/browser/performance_manager/persistence/site_data/unittest_utils.h" +#include "base/callback.h" #include <utility> @@ -36,5 +37,10 @@ std::move(callback).Run(base::nullopt, base::nullopt); } +void NoopSiteDataStore::SetInitializationCallbackForTesting( + base::OnceClosure callback) { + std::move(callback).Run(); +} + } // namespace testing } // namespace performance_manager
diff --git a/chrome/browser/performance_manager/persistence/site_data/unittest_utils.h b/chrome/browser/performance_manager/persistence/site_data/unittest_utils.h index f7ea028..12a20dc 100644 --- a/chrome/browser/performance_manager/persistence/site_data/unittest_utils.h +++ b/chrome/browser/performance_manager/persistence/site_data/unittest_utils.h
@@ -44,6 +44,7 @@ const std::vector<url::Origin>& site_origins) override; void ClearStore() override; void GetStoreSize(GetStoreSizeCallback callback) override; + void SetInitializationCallbackForTesting(base::OnceClosure callback) override; private: DISALLOW_COPY_AND_ASSIGN(NoopSiteDataStore);
diff --git a/chrome/browser/policy/e2e_test/.vpython b/chrome/browser/policy/e2e_test/.vpython index 262de132..7d94b3b 100644 --- a/chrome/browser/policy/e2e_test/.vpython +++ b/chrome/browser/policy/e2e_test/.vpython
@@ -11,7 +11,7 @@ wheel: < name: "infra/celab/celab/windows-amd64" - version: "ewVkoqiGDczXj334qRCQ8uSvGl6dd6XQGAcdbmgwpbsC" + version: "t5ee9dgnv7arG5o74SeesxNLMN-f5Z-RLd0IX9YQvrcC" > # googleapiclient
diff --git a/chrome/browser/policy/e2e_test/tests/__init__.py b/chrome/browser/policy/e2e_test/tests/__init__.py index 26eadb6..90bedaae 100644 --- a/chrome/browser/policy/e2e_test/tests/__init__.py +++ b/chrome/browser/policy/e2e_test/tests/__init__.py
@@ -4,8 +4,7 @@ from force_google_safe_search.force_google_safe_search import * from homepage.homepage import * -# TODO(feiling): Fix RestoreOnStartupTest on LUCI bots. -# from restore_on_startup.restore_on_startup import * +from restore_on_startup.restore_on_startup import * from popups_allowed.popups_allowed import * from url_blacklist.url_blacklist import * from url_whitelist.url_whitelist import *
diff --git a/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py b/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py index a696649..36c36def 100644 --- a/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py +++ b/chrome/browser/policy/e2e_test/tests/restore_on_startup/restore_on_startup.py
@@ -92,7 +92,13 @@ ]) output_urls = json.loads(output) self.assertEqual(len(output_urls), 1) - self.assertTrue('/_/chrome/newtab' in output_urls[0]) + + # The URL of the new tab can be one of the following: + # - https://www.google.com/_/chrome/newtab?ie=UTF-8 + # - chrome://newtab + # - chrome-search://local-ntp/local-ntp.html + self.assertTrue('/newtab' in output_urls[0] or + 'local-ntp.html' in output_urls[0]) @test def test_OpenListOfUrls(self):
diff --git a/chrome/browser/predictors/loading_predictor_tab_helper.cc b/chrome/browser/predictors/loading_predictor_tab_helper.cc index 9a01fbc..a2ff39f 100644 --- a/chrome/browser/predictors/loading_predictor_tab_helper.cc +++ b/chrome/browser/predictors/loading_predictor_tab_helper.cc
@@ -42,7 +42,8 @@ case content::ResourceType::kServiceWorker: case content::ResourceType::kCspReport: case content::ResourceType::kPluginResource: - case content::ResourceType::kNavigationPreload: + case content::ResourceType::kNavigationPreloadMainFrame: + case content::ResourceType::kNavigationPreloadSubFrame: return net::LOWEST; } }
diff --git a/chrome/browser/resources/chromeos/login/saml_password_attributes.js b/chrome/browser/resources/chromeos/login/saml_password_attributes.js index 0067ea2..880ceec 100644 --- a/chrome/browser/resources/chromeos/login/saml_password_attributes.js +++ b/chrome/browser/resources/chromeos/login/saml_password_attributes.js
@@ -64,19 +64,36 @@ * be empty if some or all of the attributes could not be extracted. */ function readPasswordAttributes(xmlStr) { - if (xmlStr.length < MIN_SANE_XML_LENGTH || - xmlStr.length > MAX_SANE_XML_LENGTH) { - return PasswordAttributes.EMPTY; - } - const xmlDom = new DOMParser().parseFromString(xmlStr, 'text/xml'); - if (!xmlDom) { - return PasswordAttributes.EMPTY; - } + // Don't throw any exception that could cause login to fail - extracting + // these attributes can fail, but login should not be interrupted. + try { + if (!xmlStr || typeof xmlStr != 'string') { + return PasswordAttributes.EMPTY; + } + if (xmlStr.length < MIN_SANE_XML_LENGTH || + xmlStr.length > MAX_SANE_XML_LENGTH) { + return PasswordAttributes.EMPTY; + } + if (!xmlStr.includes(SCHEMA_NAME_PREFIX)) { + // No need to bother parsing the XML if it doesn't contain this string. + return PasswordAttributes.EMPTY; + } - return new PasswordAttributes( - extractTimestampFromXml(xmlDom, PASSWORD_MODIFIED_TIMESTAMP_SELECTOR), - extractTimestampFromXml(xmlDom, PASSWORD_EXPIRATION_TIMESTAMP_SELECTOR), - extractStringFromXml(xmlDom, PASSWORD_CHANGE_URL_SELECTOR)); + const xmlDom = new DOMParser().parseFromString(xmlStr, 'text/xml'); + if (!xmlDom) { + return PasswordAttributes.EMPTY; + } + + return new PasswordAttributes( + extractTimestampFromXml(xmlDom, PASSWORD_MODIFIED_TIMESTAMP_SELECTOR), + extractTimestampFromXml( + xmlDom, PASSWORD_EXPIRATION_TIMESTAMP_SELECTOR), + extractStringFromXml(xmlDom, PASSWORD_CHANGE_URL_SELECTOR)); + + } catch (error) { + console.error('Error reading password attributes: ' + error); + return PasswordAttributes.EMPTY; + } } /**
diff --git a/chrome/browser/resources/omnibox/omnibox_output.js b/chrome/browser/resources/omnibox/omnibox_output.js index 4fa0ac2..d128558 100644 --- a/chrome/browser/resources/omnibox/omnibox_output.js +++ b/chrome/browser/resources/omnibox/omnibox_output.js
@@ -824,25 +824,47 @@ * @return {string|undefined} */ static classifyJsonWord(word) { - if (/^\d+$/.test(word)) { + // Statically creating the regexes only once. + OutputJsonProperty.classifications = + OutputJsonProperty.classifications || [ + {re: /^"[^]*":$/, clazz: 'key'}, + {re: /^"[^]*"$/, clazz: 'string'}, + {re: /true|false/, clazz: 'boolean'}, + {re: /null/, clazz: 'null'}, + ]; + OutputJsonProperty.spaceRegex = OutputJsonProperty.spaceRegex || /^\s*$/; + + // Using isNaN, because Number.isNaN checks explicitly for NaN whereas + // isNaN coerces the param to a Number. I.e. isNaN('3') === false, while + // Number.isNaN('3') === true. + if (isNaN(word)) { + const classification = + OutputJsonProperty.classifications.find(({re}) => re.test(word)); + return classification && classification.clazz; + } else if (!OutputJsonProperty.spaceRegex.test(word)) { return 'number'; } - if (/^"[^]*":$/.test(word)) { - return 'key'; - } - if (/^"[^]*"$/.test(word)) { - return 'string'; - } - if (/true|false/.test(word)) { - return 'boolean'; - } - if (/null/.test(word)) { - return 'null'; - } } } - class OutputAdditionalInfoProperty extends OutputJsonProperty { + class OutputAdditionalInfoProperty extends OutputProperty { + constructor() { + super(); + const container = document.createElement('div'); + + /** @private {!Element} */ + this.pre_ = document.createElement('pre'); + this.pre_.classList.add('json'); + container.appendChild(this.pre_); + + /** @private {!Element} */ + this.link_ = document.createElement('a'); + this.link_.download = 'AdditionalInfo.json'; + + container.appendChild(this.link_); + this.appendChild(container); + } + /** @private @override */ render_() { clearChildren(this.pre_); @@ -852,6 +874,7 @@ this.pre_.appendChild( OutputJsonProperty.renderJsonWord(value + '\n', ['number'])); }); + this.link_.href = this.createDownloadLink_(); } /** @override @return {string} */ @@ -867,6 +890,16 @@ {key: 'document_type', value: this.values_[1]} ]; } + + /** @private @return {string} */ + createDownloadLink_() { + const obj = this.tuples_.reduce((obj, {key, value}) => { + obj[key] = value; + return obj; + }, {}); + const obj64 = btoa(unescape(encodeURIComponent(JSON.stringify(obj)))); + return `data:application/json;base64,${obj64}`; + } } class OutputUrlProperty extends FlexWrappingOutputProperty {
diff --git a/chrome/browser/resources/omnibox/output_results_group.css b/chrome/browser/resources/omnibox/output_results_group.css index 06b14f98..56f5d51 100644 --- a/chrome/browser/resources/omnibox/output_results_group.css +++ b/chrome/browser/resources/omnibox/output_results_group.css
@@ -232,6 +232,20 @@ color: red; } +.cell-additional-info a { + background-image: url(../../../../third_party/blink/renderer/modules/media_controls/resources/ic_download.svg); + background-position: center; + background-repeat: no-repeat; + background-size: contain; + display: block; + height: 16px; + width: 16px; +} + +.cell-additional-info:not(:hover) a { + visibility: hidden; +} + /* boolean cells */ .check-mark,
diff --git a/chrome/browser/resources/print_preview/ui/destination_list.js b/chrome/browser/resources/print_preview/ui/destination_list.js index 3b4d1cc..c513269 100644 --- a/chrome/browser/resources/print_preview/ui/destination_list.js +++ b/chrome/browser/resources/print_preview/ui/destination_list.js
@@ -68,8 +68,7 @@ } this.updateList( - 'matchingDestinations_', - destination => destination.key + '/' + destination.connectionStatusText, + 'matchingDestinations_', destination => destination.key, this.searchQuery ? this.destinations.filter( d => d.matches(/** @type {!RegExp} */ (this.searchQuery))) :
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html index 0b546ed..a4acf13 100644 --- a/chrome/browser/resources/settings/a11y_page/a11y_page.html +++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -43,14 +43,14 @@ </div> </if> <if expr="chromeos"> - <div route-path="default"> - <template is="dom-if" if="[[showCaptionSettings_]]"> - <cr-link-row class="hr" id="captions" - label="$i18n{captionsTitle}" - on-click="onTapCaptions_"> - </cr-link-row> - </template> - <template is="dom-if" if="[[pageVisibility.webstoreLink]]"> + <template is="dom-if" if="[[pageVisibility.webstoreLink]]"> + <div route-path="default"> + <template is="dom-if" if="[[showCaptionSettings_]]"> + <cr-link-row class="hr" id="captions" + label="$i18n{captionsTitle}" + on-click="onTapCaptions_"> + </cr-link-row> + </template> <settings-toggle-button id="a11yImageLabels" hidden$="[[!showAccessibilityLabelsSetting_]]" pref="{{prefs.settings.a11y.enable_accessibility_image_labels}}" @@ -67,42 +67,38 @@ on-click="onManageAccessibilityFeaturesTap_" sub-label="$i18n{moreFeaturesLinkDescription}"> </cr-link-row> - <template is="dom-if" route-path="/manageAccessibility"> - <settings-subpage - associated-control="[[$$('#subpage-trigger')]]" - page-title="$i18n{manageAccessibilityFeatures}"> - <settings-manage-a11y-page prefs="{{prefs}}"> - </settings-manage-a11y-page> + </div> + <template is="dom-if" route-path="/manageAccessibility"> + <settings-subpage associated-control="[[$$('#subpage-trigger')]]" + page-title="$i18n{manageAccessibilityFeatures}"> + <settings-manage-a11y-page prefs="{{prefs}}"> + </settings-manage-a11y-page> + </settings-subpage> + </template> + <template is="dom-if" route-path="/manageAccessibility/tts"> + <settings-subpage + associated-control="[[$$('#subpage-trigger')]]" + page-title="$i18n{manageTtsSettings}"> + <settings-tts-subpage prefs="{{prefs}}"> + </settings-tts-subpage> + </settings-subpage> + </template> + <template is="dom-if" if="[[showExperimentalSwitchAccess_]]"> + <template is="dom-if" + route-path="/manageAccessibility/switchAccess"> + <settings-subpage associated-control="[[$$('#subpage-trigger')]]" + page-title="$i18n{manageSwitchAccessSettings}"> + <settings-switch-access-subpage prefs="{{prefs.settings.a11y}}"> + </settings-switch-access-subpage> </settings-subpage> </template> - <template is="dom-if" route-path="/manageAccessibility/tts"> - <settings-subpage - associated-control="[[$$('#subpage-trigger')]]" - page-title="$i18n{manageTtsSettings}"> - <settings-tts-subpage prefs="{{prefs}}"> - </settings-tts-subpage> - </settings-subpage> - </template> - <template is="dom-if" if="[[showExperimentalSwitchAccess_]]"> - <template is="dom-if" - route-path="/manageAccessibility/switchAccess"> - <settings-subpage - associated-control="[[$$('#subpage-trigger')]]" - page-title="$i18n{manageSwitchAccessSettings}"> - <settings-switch-access-subpage - prefs="{{prefs.settings.a11y}}"> - </settings-switch-access-subpage> - </settings-subpage> - </template> - </template> </template> - <cr-link-row class="hr" - label="$i18n{moreFeaturesLink}" - on-click="onMoreFeaturesLinkClick_" - sub-label="$i18n{a11yWebStore}" - hidden="[[pageVisibility.webstoreLink]]" external> - </cr-link-row> - </div> + </template> + <cr-link-row class="hr" + label="$i18n{moreFeaturesLink}" + on-click="onMoreFeaturesLinkClick_" + sub-label="$i18n{a11yWebStore}" + hidden="[[pageVisibility.webstoreLink]]" external></cr-link-row> </if> <if expr="chromeos or is_linux or is_win">
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html index 4dbac5e..57ea8e7 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.html +++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -26,7 +26,6 @@ <link rel="import" href="../device_page/device_page.html"> <link rel="import" href="../internet_page/internet_page.html"> <link rel="import" href="../multidevice_page/multidevice_page.html"> -<link rel="import" href="../parental_controls_page/parental_controls_page.html"> </if> <if expr="not chromeos"> @@ -154,15 +153,6 @@ </settings-people-page> </settings-section> </template> -<if expr="chromeos"> - <template is="dom-if" if="[[showParentalControls]]" restamp> - <settings-section page-title="$i18n{parentalControlsPageTitle}" - section="parentalControls"> - <settings-parental-controls-page> - </settings-parental-controls-page> - </settings-section> - </template> -</if> <template is="dom-if" if="[[showPage_(pageVisibility.autofill)]]" restamp> <settings-section page-title="$i18n{autofillPageTitle}"
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn index cfd6b3f..e2642b2 100644 --- a/chrome/browser/resources/settings/chromeos/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -63,7 +63,7 @@ group("closure_compile") { deps = [ "os_a11y_page:closure_compile", - "os_downloads_page:closure_compile", + "os_files_page:closure_compile", "os_languages_page:closure_compile", "os_people_page:closure_compile", "os_printing_page:closure_compile",
diff --git a/chrome/browser/resources/settings/chromeos/lazy_load.html b/chrome/browser/resources/settings/chromeos/lazy_load.html index 5ef6846..91f958bc 100644 --- a/chrome/browser/resources/settings/chromeos/lazy_load.html +++ b/chrome/browser/resources/settings/chromeos/lazy_load.html
@@ -3,7 +3,7 @@ <body> <link rel="import" href="../date_time_page/date_time_page.html"> <link rel="import" href="os_a11y_page/os_a11y_page.html"> - <link rel="import" href="os_downloads_page/os_downloads_page.html"> + <link rel="import" href="os_files_page/os_files_page.html"> <link rel="import" href="os_languages_page/os_languages_page.html"> <link rel="import" href="os_printing_page/os_printing_page.html"> <link rel="import" href="os_privacy_page/os_privacy_page.html">
diff --git a/chrome/browser/resources/settings/chromeos/os_downloads_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_files_page/BUILD.gn similarity index 89% rename from chrome/browser/resources/settings/chromeos/os_downloads_page/BUILD.gn rename to chrome/browser/resources/settings/chromeos/os_files_page/BUILD.gn index 38799493..a1b5d3d6 100644 --- a/chrome/browser/resources/settings/chromeos/os_downloads_page/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/os_files_page/BUILD.gn
@@ -6,7 +6,7 @@ js_type_check("closure_compile") { deps = [ - ":os_downloads_page", + ":os_files_page", ":smb_shares_page", ] } @@ -18,7 +18,7 @@ ] } -js_library("os_downloads_page") { +js_library("os_files_page") { deps = [ "../..:page_visibility", "../..:route",
diff --git a/chrome/browser/resources/settings/chromeos/os_downloads_page/os_downloads_page.html b/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.html similarity index 90% rename from chrome/browser/resources/settings/chromeos/os_downloads_page/os_downloads_page.html rename to chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.html index 5168a9d..77ead4e 100644 --- a/chrome/browser/resources/settings/chromeos/os_downloads_page/os_downloads_page.html +++ b/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.html
@@ -8,10 +8,10 @@ <link rel="import" href="../../settings_shared_css.html"> <link rel="import" href="smb_shares_page.html"> -<dom-module id="os-settings-downloads-page"> +<dom-module id="os-settings-files-page"> <template> <style include="settings-shared"></style> - <settings-animated-pages id="pages" section="downloads" + <settings-animated-pages id="pages" section="files" focus-config="[[focusConfig_]]"> <div route-path="default"> <settings-toggle-button @@ -34,5 +34,5 @@ </template> </settings-animated-pages> </template> - <script src="os_downloads_page.js"></script> + <script src="os_files_page.js"></script> </dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/os_downloads_page/os_downloads_page.js b/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.js similarity index 87% rename from chrome/browser/resources/settings/chromeos/os_downloads_page/os_downloads_page.js rename to chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.js index f8f7f48..ff8f34e 100644 --- a/chrome/browser/resources/settings/chromeos/os_downloads_page/os_downloads_page.js +++ b/chrome/browser/resources/settings/chromeos/os_files_page/os_files_page.js
@@ -4,12 +4,11 @@ /** * @fileoverview - * 'os-settings-downloads-page' is the settings page containing downloads - * settings. + * 'os-settings-files-page' is the settings page containing files settings. * */ Polymer({ - is: 'os-settings-downloads-page', + is: 'os-settings-files-page', properties: { /**
diff --git a/chrome/browser/resources/settings/chromeos/os_downloads_page/smb_shares_page.html b/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.html similarity index 100% rename from chrome/browser/resources/settings/chromeos/os_downloads_page/smb_shares_page.html rename to chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.html
diff --git a/chrome/browser/resources/settings/chromeos/os_downloads_page/smb_shares_page.js b/chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.js similarity index 100% rename from chrome/browser/resources/settings/chromeos/os_downloads_page/smb_shares_page.js rename to chrome/browser/resources/settings/chromeos/os_files_page/smb_shares_page.js
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html index 14d235a..72f767c 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
@@ -122,12 +122,6 @@ <iron-icon icon="cr:person"></iron-icon> $i18n{peoplePageTitle} </a> - <a id="parentalControls" href="/parentalControls" - hidden="[[!showParentalControls]]"> - <iron-icon icon="cr20:kite"> - </iron-icon> - $i18n{parentalControlsPageTitle} - </a> <a id="personalization" href="/personalization"> <iron-icon icon="settings:palette"></iron-icon> $i18n{personalizationPageTitle}
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html index 8aa1493..86d4122b 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html +++ b/chrome/browser/resources/settings/chromeos/os_settings_page/os_settings_page.html
@@ -247,13 +247,15 @@ </os-settings-languages-page> </settings-section> </template> + <!-- TODO(jordynass): Change from downloads to files once + pageVisibility is forked for OS Settings.--> <template is="dom-if" if="[[showPage_(pageVisibility.downloads)]]" restamp> - <settings-section page-title="$i18n{downloadsPageTitle}" - section="downloads"> - <os-settings-downloads-page prefs="{{prefs}}" + <settings-section page-title="$i18n{filesPageTitle}" + section="files"> + <os-settings-files-page prefs="{{prefs}}" page-visibility="[[pageVisibility.downloads]]"> - </os-settings-downloads-page> + </os-settings-files-page> </settings-section> </template> <template is="dom-if" if="[[showPage_(pageVisibility.printing)]]"
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd index 216ef26e..b50af0d 100644 --- a/chrome/browser/resources/settings/os_settings_resources.grd +++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -447,20 +447,20 @@ <structure name="IDR_OS_SETTINGS_DEVICE_NIGHT_LIGHT_SLIDER_JS" file="device_page/night_light_slider.js" type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_DOWNLOADS_PAGE_HTML" - file="chromeos/os_downloads_page/os_downloads_page.html" + <structure name="IDR_OS_SETTINGS_FILES_PAGE_HTML" + file="chromeos/os_files_page/os_files_page.html" type="chrome_html" preprocess="true" allowexternalscript="true" /> - <structure name="IDR_OS_SETTINGS_DOWNLOADS_PAGE_JS" - file="chromeos/os_downloads_page/os_downloads_page.js" + <structure name="IDR_OS_SETTINGS_FILES_PAGE_JS" + file="chromeos/os_files_page/os_files_page.js" type="chrome_html" preprocess="true" /> <structure name="IDR_OS_SETTINGS_SMB_SHARES_PAGE_HTML" - file="chromeos/os_downloads_page/smb_shares_page.html" + file="chromeos/os_files_page/smb_shares_page.html" type="chrome_html" /> <structure name="IDR_OS_SETTINGS_SMB_SHARES_PAGE_JS" - file="chromeos/os_downloads_page/smb_shares_page.js" + file="chromeos/os_files_page/smb_shares_page.js" type="chrome_html" /> <structure name="IDR_OS_SETTINGS_I18n_SETUP_HTML" file="i18n_setup.html"
diff --git a/chrome/browser/resources/settings/people_page/users_page.html b/chrome/browser/resources/settings/people_page/users_page.html index 7bfa99c..3f17fcf 100644 --- a/chrome/browser/resources/settings/people_page/users_page.html +++ b/chrome/browser/resources/settings/people_page/users_page.html
@@ -10,6 +10,10 @@ <link rel="import" href="user_list.html"> <link rel="import" href="users_add_user_dialog.html"> +<if expr="chromeos"> +<link rel="import" href="../parental_controls_page/parental_controls_page.html"> +</if> + <dom-module id="settings-users-page"> <template> <style include="settings-shared action-link"> @@ -25,6 +29,10 @@ .block { display: block; } + + #header { + padding-inline-start: 20px; + } </style> <div class="settings-box" hidden$="[[!isWhitelistManaged_]]"> $i18n{settingsManagedLabel} @@ -64,6 +72,13 @@ </a> </div> </div> +<if expr="chromeos"> + <template is="dom-if" if="[[showParentalControls_]]"> + <h2 id="header" class="title">$i18n{parentalControlsPageTitle}</h2> + <settings-parental-controls-page> + </settings-parental-controls-page> + </template> +</if> <settings-users-add-user-dialog id="addUserDialog" on-close="onAddUserDialogClose_"> </settings-users-add-user-dialog>
diff --git a/chrome/browser/resources/settings/people_page/users_page.js b/chrome/browser/resources/settings/people_page/users_page.js index f8f19f3..11bfa00 100644 --- a/chrome/browser/resources/settings/people_page/users_page.js +++ b/chrome/browser/resources/settings/people_page/users_page.js
@@ -30,6 +30,19 @@ type: Boolean, value: false, }, + + /** @private */ + showParentalControls_: { + type: Boolean, + value: false, + }, + }, + + /** @override */ + ready: function() { + this.showParentalControls_ = + loadTimeData.valueExists('showParentalControls') && + loadTimeData.getBoolean('showParentalControls'); }, /** @override */
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js index 8511441..afa7a072 100644 --- a/chrome/browser/resources/settings/route.js +++ b/chrome/browser/resources/settings/route.js
@@ -64,7 +64,6 @@ * NETWORK_DETAIL: (undefined|!settings.Route), * ON_STARTUP: (undefined|!settings.Route), * PASSWORDS: (undefined|!settings.Route), - * PARENTAL_CONTROLS: (undefined|!settings.Route), * PAYMENTS: (undefined|!settings.Route), * PEOPLE: (undefined|!settings.Route), * PERSONALIZATION: (undefined|!settings.Route), @@ -257,12 +256,6 @@ r.SMART_LOCK = r.MULTIDEVICE_FEATURES.createChild('/multidevice/features/smartLock'); - if (loadTimeData.valueExists('showParentalControls') && - loadTimeData.getBoolean('showParentalControls')) { - r.PARENTAL_CONTROLS = - r.BASIC.createSection('/parentalControls', 'parentalControls'); - } - // TODO(hsuregan): Remove once this file is forked. if (loadTimeData.getBoolean('showOSSettings')) { r.PERSONALIZATION =
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html index 305aa50..9369f5f5 100644 --- a/chrome/browser/resources/settings/settings_menu/settings_menu.html +++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -125,13 +125,6 @@ <iron-icon icon="cr:person"></iron-icon> $i18n{peoplePageTitle} </a> -<if expr="chromeos"> - <a id="parentalControls" href="/parentalControls" - hidden="[[!showParentalControls]]"> - <iron-icon icon="cr20:kite"></iron-icon> - $i18n{parentalControlsPageTitle} - </a> -</if> <a id="autofill" href="/autofill" hidden="[[!pageVisibility.autofill]]"> <iron-icon icon="settings:assignment"></iron-icon>
diff --git a/chrome/browser/resources/settings/site_settings/chooser_exception_list.js b/chrome/browser/resources/settings/site_settings/chooser_exception_list.js index 7e37cde..79c7539 100644 --- a/chrome/browser/resources/settings/site_settings/chooser_exception_list.js +++ b/chrome/browser/resources/settings/site_settings/chooser_exception_list.js
@@ -176,7 +176,9 @@ return Object.assign(exception, {sites}); }); - if (!this.updateList('chooserExceptions', x => x.displayName, exceptions)) { + if (!this.updateList( + 'chooserExceptions', x => x.displayName, exceptions, + true /* uidBasedUpdate */)) { // The chooser objects have not been changed, so check if their site // permissions have changed. The |exceptions| and |this.chooserExceptions| // arrays should be the same length.
diff --git a/chrome/browser/resources/settings/site_settings/site_data.js b/chrome/browser/resources/settings/site_settings/site_data.js index f15cb13..06c8e74 100644 --- a/chrome/browser/resources/settings/site_settings/site_data.js +++ b/chrome/browser/resources/settings/site_settings/site_data.js
@@ -176,8 +176,7 @@ updateSiteList_: function() { this.isLoading_ = true; this.browserProxy_.getDisplayList(this.filter).then(listInfo => { - this.updateList( - 'sites', item => `${item.site}_${item.localData}`, listInfo.items); + this.updateList('sites', item => item.site, listInfo.items); this.isLoading_ = false; this.fire('site-data-list-complete'); });
diff --git a/chrome/browser/resources/settings/site_settings/site_list.js b/chrome/browser/resources/settings/site_settings/site_list.js index c1bcb458..5e9cbba 100644 --- a/chrome/browser/resources/settings/site_settings/site_list.js +++ b/chrome/browser/resources/settings/site_settings/site_list.js
@@ -339,14 +339,10 @@ site.setting == this.categorySubtype) .map(site => this.expandSiteException(site)); - // <if expr="not chromeos"> - this.updateList('sites', (x) => x.origin, sites); - // </if> - // <if expr="chromeos"> sites = this.processExceptionsForAndroidSmsInfo_(sites); - this.updateList('sites', (x) => x.origin + x.showAndroidSmsNote, sites); // </if> + this.updateList('sites', x => x.origin, sites); }, /**
diff --git a/chrome/browser/resources/settings/site_settings/zoom_levels.js b/chrome/browser/resources/settings/site_settings/zoom_levels.js index 1614243c..e600e08f 100644 --- a/chrome/browser/resources/settings/site_settings/zoom_levels.js +++ b/chrome/browser/resources/settings/site_settings/zoom_levels.js
@@ -47,7 +47,7 @@ * their zoom levels. */ onZoomLevelsChanged_: function(sites) { - this.updateList('sites_', item => `${item.origin}_${item.zoom}`, sites); + this.updateList('sites_', item => item.origin, sites); this.showNoSites_ = this.sites_.length == 0; },
diff --git a/chrome/browser/resources/webapks/about_webapks.js b/chrome/browser/resources/webapks/about_webapks.js index 2be6576..4c65246 100644 --- a/chrome/browser/resources/webapks/about_webapks.js +++ b/chrome/browser/resources/webapks/about_webapks.js
@@ -7,6 +7,7 @@ * name: string, * shortName: string, * packageName: string, + * id: string, * shellApkVersion: number, * versionCode: number, * uri: string, @@ -19,11 +20,20 @@ * backgroundColor: string, * lastUpdateCheckTimeMs: number, * relaxUpdates: boolean, + * updateStatus: string, * }} */ let WebApkInfo; /** + * @typedef {{ + * id: string, + * status: string, + * }} + */ +let UpdateStatus; + +/** * Creates and returns an element (with |text| as content) assigning it the * |className| class. * @@ -40,8 +50,8 @@ /** * Callback from the backend with the information of a WebAPK to display. - * This will be called once for each WebAPK available on the device and each - * one will be appended at the end of the other. + * This will be called once. All WebAPKs available on the device will be + * returned. * * @param {!Array<WebApkInfo>} webApkList List of objects with information about * WebAPKs installed. @@ -67,6 +77,19 @@ } /** + * @param {HTMLElement} webApkList List of elements which contain WebAPK + * attributes. + * @param {string} text For the button. + * @param {function()} callback Invoked on click. + */ +function addWebApkButton(webApkList, text, callback) { + const divElement = + createElementWithTextAndClass(text, 'button', 'update-button'); + divElement.onclick = callback; + webApkList.appendChild(divElement); +} + +/** * Adds a new entry to the page with the information of a WebAPK. * * @param {WebApkInfo} webApkInfo Information about an installed WebAPK. @@ -100,6 +123,16 @@ addWebApkField( webApkList, 'Check for Updates Less Frequently: ', webApkInfo.relaxUpdates.toString()); + addWebApkField(webApkList, 'Update Status: ', webApkInfo.updateStatus); + + addWebApkButton(webApkList, 'Update ' + webApkInfo.name, () => { + alert( + 'The WebAPK will check for an update the next time it launches. ' + + 'If an update is available, the "Update Status" on this page ' + + 'will switch to "Scheduled". The update will be installed once ' + + 'the WebAPK is closed (this may take a few minutes).'); + chrome.send('requestWebApkUpdate', [webApkInfo.id]); + }); } document.addEventListener('DOMContentLoaded', function() {
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc index 97d6998a..0457b1ff 100644 --- a/chrome/browser/search/instant_service.cc +++ b/chrome/browser/search/instant_service.cc
@@ -190,7 +190,6 @@ pref_service_(profile_->GetPrefs()), theme_observer_(this), native_theme_(ui::NativeTheme::GetInstanceForNativeUi()), - background_updated_timestamp_(base::TimeTicks::Now()), weak_ptr_factory_(this) { // The initialization below depends on a typical set of browser threads. Skip // it if we are running in a unit test without the full suite. @@ -442,14 +441,12 @@ pref_service_->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, false); RemoveLocalBackgroundImageCopy(); - background_updated_timestamp_ = base::TimeTicks::Now(); - if (background_url.is_valid() && is_backdrop_url) { const GURL& thumbnail_url = background_service_->GetThumbnailUrl(background_url); - FetchCustomBackground( - background_updated_timestamp_, - thumbnail_url.is_valid() ? thumbnail_url : background_url); + FetchCustomBackground(background_url, thumbnail_url.is_valid() + ? thumbnail_url + : background_url); base::DictionaryValue background_info = GetBackgroundInfoAsDict( background_url, attribution_line_1, attribution_line_2, action_url); @@ -467,7 +464,6 @@ } void InstantService::SetBackgroundToLocalResource() { - background_updated_timestamp_ = base::TimeTicks::Now(); pref_service_->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, true); UpdateThemeInfo(); } @@ -800,7 +796,7 @@ } void InstantService::UpdateCustomBackgroundColorAsync( - base::TimeTicks timestamp, + const GURL& image_url, const gfx::Image& fetched_image, const image_fetcher::RequestMetadata& metadata) { // Calculate the bitmap color asynchronously as it is slow (1-2 seconds for @@ -810,11 +806,11 @@ FROM_HERE, {base::TaskPriority::BEST_EFFORT}, base::BindOnce(&GetBitmapMainColor, *fetched_image.ToSkBitmap()), base::BindOnce(&InstantService::UpdateCustomBackgroundPrefsWithColor, - weak_ptr_factory_.GetWeakPtr(), timestamp)); + weak_ptr_factory_.GetWeakPtr(), image_url)); } } -void InstantService::FetchCustomBackground(base::TimeTicks timestamp, +void InstantService::FetchCustomBackground(const GURL& image_url, const GURL& fetch_url) { DCHECK(!fetch_url.is_empty()); @@ -841,9 +837,9 @@ image_fetcher::ImageFetcherParams params(traffic_annotation, kCustomBackgroundsUmaClientName); image_fetcher_->FetchImage( - fetch_url, + image_url, base::BindOnce(&InstantService::UpdateCustomBackgroundColorAsync, - weak_ptr_factory_.GetWeakPtr(), timestamp), + weak_ptr_factory_.GetWeakPtr(), image_url), std::move(params)); } @@ -885,9 +881,8 @@ registry->RegisterBooleanPref(prefs::kNtpShortcutsVisible, true); } -void InstantService::UpdateCustomBackgroundPrefsWithColor( - base::TimeTicks timestamp, - SkColor color) { +void InstantService::UpdateCustomBackgroundPrefsWithColor(const GURL& image_url, + SkColor color) { // Update background color only if the selected background is still the same. const base::DictionaryValue* background_info = pref_service_->GetDictionary(prefs::kNtpCustomBackgroundDict); @@ -896,7 +891,7 @@ GURL current_bg_url( background_info->FindKey(kNtpCustomBackgroundURL)->GetString()); - if (timestamp == background_updated_timestamp_) { + if (current_bg_url == image_url) { pref_service_->Set(prefs::kNtpCustomBackgroundDict, GetBackgroundInfoWithColor(background_info, color)); }
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h index 35e6132..2a73342 100644 --- a/chrome/browser/search/instant_service.h +++ b/chrome/browser/search/instant_service.h
@@ -162,12 +162,12 @@ // Calculates the most frequent color of the image and stores it in prefs. void UpdateCustomBackgroundColorAsync( - base::TimeTicks timestamp, + const GURL& image_url, const gfx::Image& fetched_image, const image_fetcher::RequestMetadata& metadata); // Fetches the image for the given |fetch_url|. - void FetchCustomBackground(base::TimeTicks timestamp, const GURL& fetch_url); + void FetchCustomBackground(const GURL& image_url, const GURL& fetch_url); private: class SearchProviderObserver; @@ -184,9 +184,6 @@ FRIEND_TEST_ALL_PREFIXES(InstantServiceTest, DoesToggleShortcutsVisibility); FRIEND_TEST_ALL_PREFIXES(InstantServiceTest, IsCustomLinksEnabled); FRIEND_TEST_ALL_PREFIXES(InstantServiceTest, TestNoThemeInfo); - FRIEND_TEST_ALL_PREFIXES(InstantServiceTest, TestUpdateCustomBackgroundColor); - FRIEND_TEST_ALL_PREFIXES(InstantServiceTest, - LocalImageDoesNotUpdateCustomBackgroundColor); // KeyedService: void Shutdown() override; @@ -240,17 +237,12 @@ // chrome-search://local-ntp/background.jpg void SetBackgroundToLocalResource(); - // Updates custom background prefs with color if the background hasn't changed - // since the calculation started. - void UpdateCustomBackgroundPrefsWithColor(base::TimeTicks timestamp, + // Updates custom background prefs with color for the given |image_url|. + void UpdateCustomBackgroundPrefsWithColor(const GURL& image_url, SkColor color); void SetImageFetcherForTesting(image_fetcher::ImageFetcher* image_fetcher); - base::TimeTicks GetBackgroundUpdatedTimestampForTesting() { - return background_updated_timestamp_; - } - Profile* const profile_; // The process ids associated with Instant processes. @@ -287,8 +279,6 @@ std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_; - base::TimeTicks background_updated_timestamp_; - base::WeakPtrFactory<InstantService> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(InstantService);
diff --git a/chrome/browser/search/instant_service_unittest.cc b/chrome/browser/search/instant_service_unittest.cc index fc86ac3..610fad2 100644 --- a/chrome/browser/search/instant_service_unittest.cc +++ b/chrome/browser/search/instant_service_unittest.cc
@@ -581,7 +581,7 @@ // Background color will not update if no background is set. instant_service_->UpdateCustomBackgroundColorAsync( - base::TimeTicks::Now(), image, image_fetcher::RequestMetadata()); + GURL(), image, image_fetcher::RequestMetadata()); thread_bundle()->RunUntilIdle(); EXPECT_FALSE(CheckBackgroundColor( SK_ColorRED, @@ -597,9 +597,9 @@ instant_service_->SetCustomBackgroundURLWithAttributions( kUrl, kAttributionLine1, kAttributionLine2, kActionUrl); - // Background color will not update if background timestamp has changed. + // Background color will not update if current background url changed. instant_service_->UpdateCustomBackgroundColorAsync( - base::TimeTicks::Now(), image, image_fetcher::RequestMetadata()); + GURL("different_url"), image, image_fetcher::RequestMetadata()); thread_bundle()->RunUntilIdle(); EXPECT_FALSE(CheckBackgroundColor( SK_ColorRED, @@ -607,52 +607,9 @@ // Background color should update. instant_service_->UpdateCustomBackgroundColorAsync( - instant_service_->GetBackgroundUpdatedTimestampForTesting(), image, - image_fetcher::RequestMetadata()); + kUrl, image, image_fetcher::RequestMetadata()); thread_bundle()->RunUntilIdle(); EXPECT_TRUE(CheckBackgroundColor( SK_ColorRED, pref_service->GetDictionary(prefs::kNtpCustomBackgroundDict))); } - -TEST_F(InstantServiceTest, LocalImageDoesNotUpdateCustomBackgroundColor) { - SkBitmap bitmap; - bitmap.allocN32Pixels(32, 32); - bitmap.eraseColor(SK_ColorRED); - gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmap); - sync_preferences::TestingPrefServiceSyncable* pref_service = - profile()->GetTestingPrefService(); - - base::FilePath profile_path = profile()->GetPath(); - base::FilePath path(profile_path.AppendASCII("test_file")); - base::FilePath copy_path(profile_path.AppendASCII( - chrome::kChromeSearchLocalNtpBackgroundFilename)); - base::WriteFile(path, "background_image", 16); - - instant_service_->SelectLocalBackgroundImage(path); - - ASSERT_FALSE(instant_service_->IsCustomBackgroundSet()); - - const GURL kUrl("https://www.foo.com"); - const std::string kAttributionLine1 = "foo"; - const std::string kAttributionLine2 = "bar"; - const GURL kActionUrl("https://www.bar.com"); - - SetUserSelectedDefaultSearchProvider("{google:baseURL}"); - instant_service_->AddValidBackdropUrlForTesting(kUrl); - instant_service_->SetCustomBackgroundURLWithAttributions( - kUrl, kAttributionLine1, kAttributionLine2, kActionUrl); - base::TimeTicks time_set = - instant_service_->GetBackgroundUpdatedTimestampForTesting(); - - instant_service_->SelectLocalBackgroundImage(path); - - // Background color will not update if a local image was uploaded in the - // meantime. - instant_service_->UpdateCustomBackgroundColorAsync( - time_set, image, image_fetcher::RequestMetadata()); - thread_bundle()->RunUntilIdle(); - EXPECT_FALSE(CheckBackgroundColor( - SK_ColorRED, - pref_service->GetDictionary(prefs::kNtpCustomBackgroundDict))); -}
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc index b858066..04dbee0 100644 --- a/chrome/browser/sessions/session_restore.cc +++ b/chrome/browser/sessions/session_restore.cc
@@ -27,7 +27,6 @@ #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/search.h" @@ -38,6 +37,8 @@ #include "chrome/browser/sessions/tab_loader.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_list_observer.h" #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/browser_tabrestore.h" @@ -53,8 +54,6 @@ #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/dom_storage_context.h" #include "content/public/browser/navigation_controller.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/notification_service.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" @@ -95,7 +94,7 @@ // SessionRestoreImpl is responsible for fetching the set of tabs to create // from SessionService. SessionRestoreImpl deletes itself when done. -class SessionRestoreImpl : public content::NotificationObserver { +class SessionRestoreImpl : public BrowserListObserver { public: SessionRestoreImpl(Profile* profile, Browser* browser, @@ -155,10 +154,8 @@ return browser; } - if (browser_) { - registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, - content::Source<Browser>(browser_)); - } + if (browser_) + BrowserList::AddObserver(this); return browser_; } @@ -252,6 +249,7 @@ } ~SessionRestoreImpl() override { + BrowserList::RemoveObserver(this); active_session_restorers->erase(this); if (active_session_restorers->empty()) { delete active_session_restorers; @@ -259,18 +257,10 @@ } } - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override { - switch (type) { - case chrome::NOTIFICATION_BROWSER_CLOSED: - delete this; - return; - - default: - NOTREACHED(); - break; - } + // BrowserListObserver: + void OnBrowserRemoved(Browser* browser) override { + if (browser == browser_) + delete this; } Profile* profile() { return profile_; } @@ -318,7 +308,7 @@ // if the browser is deleted. Don't listen to anything. This avoid a // possible double delete too (if browser is closed before DeleteSoon() is // processed). - registrar_.RemoveAll(); + BrowserList::RemoveObserver(this); } #if defined(OS_CHROMEOS) @@ -706,8 +696,6 @@ std::vector<std::unique_ptr<sessions::SessionWindow>> windows_; SessionID active_window_id_; - content::NotificationRegistrar registrar_; - // When asynchronous it's possible for there to be no windows. To make sure // Chrome doesn't prematurely exit we register a KeepAlive for the lifetime // of this object.
diff --git a/chrome/browser/signin/signin_manager_android_wrapper.cc b/chrome/browser/signin/signin_manager_android_wrapper.cc index fc64845a..6d200f94 100644 --- a/chrome/browser/signin/signin_manager_android_wrapper.cc +++ b/chrome/browser/signin/signin_manager_android_wrapper.cc
@@ -5,10 +5,12 @@ #include "chrome/browser/signin/signin_manager_android_wrapper.h" SigninManagerAndroidWrapper::SigninManagerAndroidWrapper( - Profile* profile, + SigninClient* signin_client, + PrefService* local_state_prefs_service, identity::IdentityManager* identity_manager, std::unique_ptr<SigninManagerDelegate> signin_manager_delegate) - : signin_manager_android_(profile, + : signin_manager_android_(signin_client, + local_state_prefs_service, identity_manager, std::move(signin_manager_delegate)) {}
diff --git a/chrome/browser/signin/signin_manager_android_wrapper.h b/chrome/browser/signin/signin_manager_android_wrapper.h index 8589a759..c482505 100644 --- a/chrome/browser/signin/signin_manager_android_wrapper.h +++ b/chrome/browser/signin/signin_manager_android_wrapper.h
@@ -10,13 +10,12 @@ #include "components/keyed_service/core/keyed_service.h" #include "components/signin/public/identity_manager/identity_manager.h" -class Profile; - class SigninManagerAndroidWrapper : public KeyedService { public: // initializes the member signin_manager_android_ and keeps ownership. SigninManagerAndroidWrapper( - Profile* profile, + SigninClient* signin_client, + PrefService* local_state_prefs_service, identity::IdentityManager* identity_manager, std::unique_ptr<SigninManagerDelegate> signin_manager_delegate);
diff --git a/chrome/browser/signin/signin_manager_android_wrapper_factory.cc b/chrome/browser/signin/signin_manager_android_wrapper_factory.cc index 895bee2..a7a90339 100644 --- a/chrome/browser/signin/signin_manager_android_wrapper_factory.cc +++ b/chrome/browser/signin/signin_manager_android_wrapper_factory.cc
@@ -6,14 +6,18 @@ #include "chrome/browser/android/signin/chrome_signin_manager_delegate.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "chrome/browser/browser_process.h" + SigninManagerAndroidWrapperFactory::SigninManagerAndroidWrapperFactory() : BrowserContextKeyedServiceFactory( "SigninManagerAndroidWrapper", BrowserContextDependencyManager::GetInstance()) { DependsOn(IdentityManagerFactory::GetInstance()); + DependsOn(ChromeSigninClientFactory::GetInstance()); } SigninManagerAndroidWrapperFactory::~SigninManagerAndroidWrapperFactory() {} @@ -36,10 +40,12 @@ KeyedService* SigninManagerAndroidWrapperFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { Profile* profile = Profile::FromBrowserContext(context); + auto* signin_client = ChromeSigninClientFactory::GetForProfile(profile); auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); auto signin_manager_delegate = std::make_unique<ChromeSigninManagerDelegate>(); - return new SigninManagerAndroidWrapper(profile, identity_manager, - std::move(signin_manager_delegate)); + return new SigninManagerAndroidWrapper( + signin_client, g_browser_process->local_state(), identity_manager, + std::move(signin_manager_delegate)); }
diff --git a/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc b/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc index 28f3fa3b..bba50ba 100644 --- a/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc +++ b/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc
@@ -51,23 +51,18 @@ // This parameter controls whether the count of recurrent errors is // per-browsing-session or persisted to a pref, accumulating across browsing // sessions. Default is "in-memory". -constexpr char kRecurrentInterstitialModeParam[] = "mode"; -constexpr char kRecurrentInterstitialModeInMemory[] = "in-memory"; -constexpr char kRecurrentInterstitialModePref[] = "pref"; - #if defined(OS_ANDROID) -const base::FeatureParam<std::string> kRecurrentInterstitialMode{ - &kRecurrentInterstitialFeature, kRecurrentInterstitialModeParam, - kRecurrentInterstitialModePref}; +ChromeSSLHostStateDelegate::RecurrentInterstitialMode + kRecurrentInterstitialDefaultMode = + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::PREF; #else -const base::FeatureParam<std::string> kRecurrentInterstitialMode{ - &kRecurrentInterstitialFeature, kRecurrentInterstitialModeParam, - kRecurrentInterstitialModeInMemory}; +ChromeSSLHostStateDelegate::RecurrentInterstitialMode + kRecurrentInterstitialDefaultMode = + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::IN_MEMORY; #endif // The number of times an error must recur before the recurrent error message is // shown. -constexpr char kRecurrentInterstitialThresholdParam[] = "threshold"; constexpr int kRecurrentInterstitialDefaultThreshold = 3; // If "mode" is "pref", a pref stores the time at which each error most recently @@ -75,7 +70,6 @@ // more than the threshold number of times with the most recent instance being // less than |kRecurrentInterstitialResetTimeParam| seconds in the past. The // default is 3 days. -constexpr char kRecurrentInterstitialResetTimeParam[] = "reset-time"; constexpr int kRecurrentInterstitialDefaultResetTime = 259200; // 3 days in seconds @@ -147,18 +141,17 @@ bool DoesRecurrentInterstitialPrefMeetThreshold(Profile* profile, base::Clock* clock, int error, - int threshold) { + int threshold, + int error_reset_time) { const base::DictionaryValue* pref = profile->GetPrefs()->GetDictionary(prefs::kRecurrentSSLInterstitial); const base::Value* list_value = pref->FindKey(net::ErrorToShortString(error)); if (!list_value) return false; - base::Time cutoff_time = - clock->Now() - - base::TimeDelta::FromSeconds(base::GetFieldTrialParamByFeatureAsInt( - kRecurrentInterstitialFeature, kRecurrentInterstitialResetTimeParam, - kRecurrentInterstitialDefaultResetTime)); + base::Time cutoff_time; + cutoff_time = clock->Now() - base::TimeDelta::FromSeconds(error_reset_time); + // Assume that the values in the list are in increasing order; // UpdateRecurrentInterstitialPref() maintains this ordering. Check if there // are more than |threshold| values after the cutoff time. @@ -248,18 +241,16 @@ } // namespace -// TODO(https://crbug.com/953972): Remove this and all dependent code paths. -const base::Feature kRecurrentInterstitialFeature{ - "RecurrentInterstitialFeature", base::FEATURE_ENABLED_BY_DEFAULT}; - ChromeSSLHostStateDelegate::ChromeSSLHostStateDelegate(Profile* profile) : clock_(new base::DefaultClock()), - profile_(profile) { + profile_(profile), + recurrent_interstitial_threshold_for_testing(-1), + recurrent_interstitial_mode_for_testing(NOT_SET), + recurrent_interstitial_reset_time_for_testing(-1) { MigrateOldSettings(HostContentSettingsMapFactory::GetForProfile(profile)); } -ChromeSSLHostStateDelegate::~ChromeSSLHostStateDelegate() { -} +ChromeSSLHostStateDelegate::~ChromeSSLHostStateDelegate() {} void ChromeSSLHostStateDelegate::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { @@ -469,17 +460,10 @@ error != net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED) { return; } - - if (!base::FeatureList::IsEnabled(kRecurrentInterstitialFeature)) { - return; - } - - const std::string mode_param = kRecurrentInterstitialMode.Get(); - const int threshold = base::GetFieldTrialParamByFeatureAsInt( - kRecurrentInterstitialFeature, kRecurrentInterstitialThresholdParam, - kRecurrentInterstitialDefaultThreshold); - - if (mode_param.empty() || mode_param == kRecurrentInterstitialModeInMemory) { + RecurrentInterstitialMode mode_param = GetRecurrentInterstitialMode(); + const int threshold = GetRecurrentInterstitialThreshold(); + if (mode_param == + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::IN_MEMORY) { const auto count_it = recurrent_errors_.find(error); if (count_it == recurrent_errors_.end()) { recurrent_errors_[error] = 1; @@ -489,29 +473,26 @@ return; } recurrent_errors_[error] = count_it->second + 1; - } else if (mode_param == kRecurrentInterstitialModePref) { + } else if (mode_param == + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::PREF) { UpdateRecurrentInterstitialPref(profile_, clock_.get(), error, threshold); } } bool ChromeSSLHostStateDelegate::HasSeenRecurrentErrors(int error) const { - if (!base::FeatureList::IsEnabled(kRecurrentInterstitialFeature)) { - return false; - } - - const std::string mode_param = kRecurrentInterstitialMode.Get(); - const int threshold = base::GetFieldTrialParamByFeatureAsInt( - kRecurrentInterstitialFeature, kRecurrentInterstitialThresholdParam, - kRecurrentInterstitialDefaultThreshold); - - if (mode_param.empty() || mode_param == kRecurrentInterstitialModeInMemory) { + RecurrentInterstitialMode mode_param = GetRecurrentInterstitialMode(); + const int threshold = GetRecurrentInterstitialThreshold(); + if (mode_param == + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::IN_MEMORY) { const auto count_it = recurrent_errors_.find(error); if (count_it == recurrent_errors_.end()) return false; return count_it->second >= threshold; - } else if (mode_param == kRecurrentInterstitialModePref) { - return DoesRecurrentInterstitialPrefMeetThreshold(profile_, clock_.get(), - error, threshold); + } else if (mode_param == + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::PREF) { + return DoesRecurrentInterstitialPrefMeetThreshold( + profile_, clock_.get(), error, threshold, + GetRecurrentInterstitialResetTime()); } return false; @@ -529,6 +510,46 @@ clock_ = std::move(clock); } +void ChromeSSLHostStateDelegate::SetRecurrentInterstitialThresholdForTesting( + int threshold) { + recurrent_interstitial_threshold_for_testing = threshold; +} + +void ChromeSSLHostStateDelegate::SetRecurrentInterstitialModeForTesting( + ChromeSSLHostStateDelegate::RecurrentInterstitialMode mode) { + recurrent_interstitial_mode_for_testing = mode; +} + +void ChromeSSLHostStateDelegate::SetRecurrentInterstitialResetTimeForTesting( + int reset) { + recurrent_interstitial_reset_time_for_testing = reset; +} + +int ChromeSSLHostStateDelegate::GetRecurrentInterstitialThreshold() const { + if (recurrent_interstitial_threshold_for_testing == -1) { + return kRecurrentInterstitialDefaultThreshold; + } else { + return recurrent_interstitial_threshold_for_testing; + } +} + +int ChromeSSLHostStateDelegate::GetRecurrentInterstitialResetTime() const { + if (recurrent_interstitial_reset_time_for_testing == -1) { + return kRecurrentInterstitialDefaultResetTime; + } else { + return recurrent_interstitial_reset_time_for_testing; + } +} + +ChromeSSLHostStateDelegate::RecurrentInterstitialMode +ChromeSSLHostStateDelegate::GetRecurrentInterstitialMode() const { + if (recurrent_interstitial_mode_for_testing == NOT_SET) { + return kRecurrentInterstitialDefaultMode; + } else { + return recurrent_interstitial_mode_for_testing; + } +} + // This helper function gets the dictionary of certificate fingerprints to // errors of certificates that have been accepted by the user from the content // dictionary that has been passed in. The returned pointer is owned by the the
diff --git a/chrome/browser/ssl/chrome_ssl_host_state_delegate.h b/chrome/browser/ssl/chrome_ssl_host_state_delegate.h index 870949b8..176ebf8 100644 --- a/chrome/browser/ssl/chrome_ssl_host_state_delegate.h +++ b/chrome/browser/ssl/chrome_ssl_host_state_delegate.h
@@ -35,6 +35,8 @@ // - when errors have recurred multiple times class ChromeSSLHostStateDelegate : public content::SSLHostStateDelegate { public: + enum RecurrentInterstitialMode { PREF, IN_MEMORY, NOT_SET }; + explicit ChromeSSLHostStateDelegate(Profile* profile); ~ChromeSSLHostStateDelegate() override; @@ -83,6 +85,15 @@ // SetClockForTesting takes ownership of the passed in clock. void SetClockForTesting(std::unique_ptr<base::Clock> clock); + void SetRecurrentInterstitialThresholdForTesting(int threshold); + void SetRecurrentInterstitialModeForTesting( + ChromeSSLHostStateDelegate::RecurrentInterstitialMode mode); + void SetRecurrentInterstitialResetTimeForTesting(int reset); + + RecurrentInterstitialMode GetRecurrentInterstitialMode() const; + int GetRecurrentInterstitialThreshold() const; + int GetRecurrentInterstitialResetTime() const; + private: // Used to specify whether new content setting entries should be created if // they don't already exist when querying the user's settings. @@ -131,6 +142,10 @@ std::map<int /* error code */, int /* count */> recurrent_errors_; DISALLOW_COPY_AND_ASSIGN(ChromeSSLHostStateDelegate); + + int recurrent_interstitial_threshold_for_testing; + enum RecurrentInterstitialMode recurrent_interstitial_mode_for_testing; + int recurrent_interstitial_reset_time_for_testing; }; #endif // CHROME_BROWSER_SSL_CHROME_SSL_HOST_STATE_DELEGATE_H_
diff --git a/chrome/browser/ssl/chrome_ssl_host_state_delegate_test.cc b/chrome/browser/ssl/chrome_ssl_host_state_delegate_test.cc index 0f8c052e..01211eb0 100644 --- a/chrome/browser/ssl/chrome_ssl_host_state_delegate_test.cc +++ b/chrome/browser/ssl/chrome_ssl_host_state_delegate_test.cc
@@ -344,15 +344,15 @@ // after seeing an error of interest multiple times, in the default mode in // which error occurrences are stored in-memory. IN_PROC_BROWSER_TEST_F(ChromeSSLHostStateDelegateTest, HasSeenRecurrentErrors) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeatureWithParameters(kRecurrentInterstitialFeature, - {{"threshold", "2"}}); content::WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext()); content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate(); ChromeSSLHostStateDelegate* chrome_state = static_cast<ChromeSSLHostStateDelegate*>(state); + chrome_state->SetRecurrentInterstitialThresholdForTesting(2); + chrome_state->SetRecurrentInterstitialModeForTesting( + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::PREF); chrome_state->DidDisplayErrorPage(net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED); EXPECT_FALSE(chrome_state->HasSeenRecurrentErrors( @@ -370,15 +370,15 @@ // count of each error is persisted across browsing sessions). IN_PROC_BROWSER_TEST_F(ChromeSSLHostStateDelegateTest, HasSeenRecurrentErrorsPref) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeatureWithParameters( - kRecurrentInterstitialFeature, {{"threshold", "2"}, {"mode", "pref"}}); content::WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext()); content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate(); ChromeSSLHostStateDelegate* chrome_state = static_cast<ChromeSSLHostStateDelegate*>(state); + chrome_state->SetRecurrentInterstitialThresholdForTesting(2); + chrome_state->SetRecurrentInterstitialModeForTesting( + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::PREF); chrome_state->DidDisplayErrorPage(net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED); EXPECT_FALSE(chrome_state->HasSeenRecurrentErrors( @@ -396,6 +396,10 @@ // Create a new ChromeSSLHostStateDelegate to check that the state has been // saved to the pref and that the new ChromeSSLHostStateDelegate reads it. ChromeSSLHostStateDelegate new_state(profile); + new_state.SetRecurrentInterstitialThresholdForTesting(2); + new_state.SetRecurrentInterstitialModeForTesting( + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::PREF); + EXPECT_TRUE(new_state.HasSeenRecurrentErrors( net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED)); EXPECT_TRUE(new_state.HasSeenRecurrentErrors(net::ERR_CERT_SYMANTEC_LEGACY)); @@ -410,15 +414,15 @@ // going backwards in pref mode. IN_PROC_BROWSER_TEST_F(ChromeSSLHostStateDelegateTest, HasSeenRecurrentErrorsPrefClockGoesBackwards) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeatureWithParameters( - kRecurrentInterstitialFeature, {{"threshold", "2"}, {"mode", "pref"}}); content::WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext()); content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate(); ChromeSSLHostStateDelegate* chrome_state = static_cast<ChromeSSLHostStateDelegate*>(state); + chrome_state->SetRecurrentInterstitialThresholdForTesting(2); + chrome_state->SetRecurrentInterstitialModeForTesting( + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::PREF); base::SimpleTestClock* clock = new base::SimpleTestClock(); clock->SetNow(base::Time::Now()); @@ -448,16 +452,15 @@ // threshold of 3 errors, unlike previous tests which use a threshold of 2. IN_PROC_BROWSER_TEST_F(ChromeSSLHostStateDelegateTest, HasSeenRecurrentErrorsPrefErrorsInPast) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeatureWithParameters( - kRecurrentInterstitialFeature, - {{"threshold", "3"}, {"mode", "pref"}, {"reset-time", "10"}}); content::WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext()); content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate(); ChromeSSLHostStateDelegate* chrome_state = static_cast<ChromeSSLHostStateDelegate*>(state); + chrome_state->SetRecurrentInterstitialResetTimeForTesting(10); + chrome_state->SetRecurrentInterstitialModeForTesting( + ChromeSSLHostStateDelegate::RecurrentInterstitialMode::PREF); base::SimpleTestClock* clock = new base::SimpleTestClock(); clock->SetNow(base::Time::Now()); @@ -774,4 +777,4 @@ content::SSLHostStateDelegate::ALLOWED, state->QueryPolicy("127.0.0.1", *cert, net::ERR_CERT_COMMON_NAME_INVALID, &unused_value)); -} +} \ No newline at end of file
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc index ab29d39e..67eaedf 100644 --- a/chrome/browser/ssl/ssl_browsertest.cc +++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -7760,56 +7760,42 @@ mock_cert_verifier()->set_default_result( net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED); - // When |show_error_message| is false, the test checks the field trial - // configuration in which recurrent errors are tracked and histograms are - // recorded but the interstitial UI isn't actually modified. This - // configuration allows comparison of clickthrough rates for the exact same - // error conditions with and without the modified error UI. - for (const auto& show_error_message : {false, true}) { - ChromeSSLHostStateDelegate* state = - reinterpret_cast<ChromeSSLHostStateDelegate*>( - browser()->profile()->GetSSLHostStateDelegate()); - state->ResetRecurrentErrorCountForTesting(); + ChromeSSLHostStateDelegate* state = + reinterpret_cast<ChromeSSLHostStateDelegate*>( + browser()->profile()->GetSSLHostStateDelegate()); + state->ResetRecurrentErrorCountForTesting(); - base::HistogramTester histograms; - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeatureWithParameters( - kRecurrentInterstitialFeature, - {{"threshold", "2"}, - {"show_error_ui", show_error_message ? "true" : "false"}}); + base::HistogramTester histograms; + state->SetRecurrentInterstitialThresholdForTesting(2); - // Use different hostnames for the two test cases to avoid the clickthrough - // from one interfering with the other. - GURL url = - https_server.GetURL(show_error_message ? "show_error_message.test" - : "no_error_message.test", - "/"); - ui_test_utils::NavigateToURL(browser(), url); - WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); - WaitForInterstitial(tab); - ExpectInterstitialElementHidden(tab, "recurrent-error-message", - true /* expect_hidden */); - histograms.ExpectUniqueSample(kRecurrentInterstitialHistogram, false, 1); + // Use different hostnames for the two test cases to avoid the clickthrough + // from one interfering with the other. + GURL url = https_server.GetURL("show_error_message.test", "/"); + ui_test_utils::NavigateToURL(browser(), url); + WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); + WaitForInterstitial(tab); + ExpectInterstitialElementHidden(tab, "recurrent-error-message", + true /* expect_hidden */); + histograms.ExpectUniqueSample(kRecurrentInterstitialHistogram, false, 1); - ui_test_utils::NavigateToURL(browser(), url); - WaitForInterstitial(tab); - ExpectInterstitialElementHidden(tab, "recurrent-error-message", - !show_error_message /* expect_hidden */); - histograms.ExpectBucketCount(kRecurrentInterstitialHistogram, true, 1); - histograms.ExpectUniqueSample( - kRecurrentInterstitialActionHistogram, - SSLErrorControllerClient::RecurrentErrorAction::kShow, 1); + ui_test_utils::NavigateToURL(browser(), url); + WaitForInterstitial(tab); + ExpectInterstitialElementHidden(tab, "recurrent-error-message", + false /* expect_hidden */); + histograms.ExpectBucketCount(kRecurrentInterstitialHistogram, true, 1); + histograms.ExpectUniqueSample( + kRecurrentInterstitialActionHistogram, + SSLErrorControllerClient::RecurrentErrorAction::kShow, 1); - // Proceed through the interstitial and observe that the histogram is - // recorded correctly. - content::TestNavigationObserver nav_observer(tab, 1); - ASSERT_TRUE(content::ExecuteScript( - tab, "window.certificateErrorPageController.proceed();")); - nav_observer.Wait(); - histograms.ExpectBucketCount( - kRecurrentInterstitialActionHistogram, - SSLErrorControllerClient::RecurrentErrorAction::kProceed, 1); - } + // Proceed through the interstitial and observe that the histogram is + // recorded correctly. + content::TestNavigationObserver nav_observer(tab, 1); + ASSERT_TRUE(content::ExecuteScript( + tab, "window.certificateErrorPageController.proceed();")); + nav_observer.Wait(); + histograms.ExpectBucketCount( + kRecurrentInterstitialActionHistogram, + SSLErrorControllerClient::RecurrentErrorAction::kProceed, 1); } // TODO(jcampan): more tests to do below.
diff --git a/chrome/browser/ssl/ssl_error_controller_client.cc b/chrome/browser/ssl/ssl_error_controller_client.cc index 60966d13..abfeb18a 100644 --- a/chrome/browser/ssl/ssl_error_controller_client.cc +++ b/chrome/browser/ssl/ssl_error_controller_client.cc
@@ -226,7 +226,5 @@ } bool SSLErrorControllerClient::HasSeenRecurrentError() { - return HasSeenRecurrentErrorInternal(web_contents_, cert_error_) && - base::GetFieldTrialParamByFeatureAsBool(kRecurrentInterstitialFeature, - "show_error_ui", true); + return HasSeenRecurrentErrorInternal(web_contents_, cert_error_); }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index c7d46ac..f25c3847 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -112,8 +112,10 @@ "find_bar/find_bar_state_factory.cc", "find_bar/find_bar_state_factory.h", "find_bar/find_notification_details.h", + "find_bar/find_result_observer.h", "find_bar/find_tab_helper.cc", "find_bar/find_tab_helper.h", + "find_bar/find_types.h", "interventions/framebust_block_message_delegate.cc", "interventions/framebust_block_message_delegate.h", "interventions/intervention_delegate.h", @@ -635,10 +637,6 @@ "android/autofill/card_unmask_prompt_view_android.h", "android/autofill/credit_card_scanner_view_android.cc", "android/autofill/credit_card_scanner_view_android.h", - "android/bluetooth_chooser_android.cc", - "android/bluetooth_chooser_android.h", - "android/bluetooth_scanning_prompt_android.cc", - "android/bluetooth_scanning_prompt_android.h", "android/chrome_http_auth_handler.cc", "android/chrome_http_auth_handler.h", "android/color_chooser_dialog_android.cc", @@ -648,6 +646,12 @@ "android/content_settings/popup_blocked_infobar_delegate.h", "android/context_menu_helper.cc", "android/context_menu_helper.h", + "android/device_dialog/bluetooth_chooser_android.cc", + "android/device_dialog/bluetooth_chooser_android.h", + "android/device_dialog/bluetooth_scanning_prompt_android.cc", + "android/device_dialog/bluetooth_scanning_prompt_android.h", + "android/device_dialog/usb_chooser_dialog_android.cc", + "android/device_dialog/usb_chooser_dialog_android.h", "android/external_protocol_dialog_android.cc", "android/infobars/ads_blocked_infobar.cc", "android/infobars/ads_blocked_infobar.h", @@ -743,8 +747,6 @@ "android/tab_model/tab_model_observer_jni_bridge.h", "android/toolbar/location_bar_model_android.cc", "android/toolbar/location_bar_model_android.h", - "android/usb_chooser_dialog_android.cc", - "android/usb_chooser_dialog_android.h", "android/view_android_helper.cc", "android/view_android_helper.h", "browser_otr_state_android.cc",
diff --git a/chrome/browser/ui/android/device_dialog/OWNERS b/chrome/browser/ui/android/device_dialog/OWNERS new file mode 100644 index 0000000..298cd1c --- /dev/null +++ b/chrome/browser/ui/android/device_dialog/OWNERS
@@ -0,0 +1,2 @@ +juncai@chromium.org +reillyg@chromium.org
diff --git a/chrome/browser/ui/android/bluetooth_chooser_android.cc b/chrome/browser/ui/android/device_dialog/bluetooth_chooser_android.cc similarity index 98% rename from chrome/browser/ui/android/bluetooth_chooser_android.cc rename to chrome/browser/ui/android/device_dialog/bluetooth_chooser_android.cc index ed15f40..9d77bea 100644 --- a/chrome/browser/ui/android/bluetooth_chooser_android.cc +++ b/chrome/browser/ui/android/device_dialog/bluetooth_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 "chrome/browser/ui/android/bluetooth_chooser_android.h" +#include "chrome/browser/ui/android/device_dialog/bluetooth_chooser_android.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h"
diff --git a/chrome/browser/ui/android/bluetooth_chooser_android.h b/chrome/browser/ui/android/device_dialog/bluetooth_chooser_android.h similarity index 90% rename from chrome/browser/ui/android/bluetooth_chooser_android.h rename to chrome/browser/ui/android/device_dialog/bluetooth_chooser_android.h index af41b0e..05a7452 100644 --- a/chrome/browser/ui/android/bluetooth_chooser_android.h +++ b/chrome/browser/ui/android/device_dialog/bluetooth_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 CHROME_BROWSER_UI_ANDROID_BLUETOOTH_CHOOSER_ANDROID_H_ -#define CHROME_BROWSER_UI_ANDROID_BLUETOOTH_CHOOSER_ANDROID_H_ +#ifndef CHROME_BROWSER_UI_ANDROID_DEVICE_DIALOG_BLUETOOTH_CHOOSER_ANDROID_H_ +#define CHROME_BROWSER_UI_ANDROID_DEVICE_DIALOG_BLUETOOTH_CHOOSER_ANDROID_H_ #include "base/android/scoped_java_ref.h" #include "content/public/browser/bluetooth_chooser.h" @@ -58,4 +58,4 @@ BluetoothChooser::EventHandler event_handler_; }; -#endif // CHROME_BROWSER_UI_ANDROID_BLUETOOTH_CHOOSER_ANDROID_H_ +#endif // CHROME_BROWSER_UI_ANDROID_DEVICE_DIALOG_BLUETOOTH_CHOOSER_ANDROID_H_
diff --git a/chrome/browser/ui/android/bluetooth_scanning_prompt_android.cc b/chrome/browser/ui/android/device_dialog/bluetooth_scanning_prompt_android.cc similarity index 97% rename from chrome/browser/ui/android/bluetooth_scanning_prompt_android.cc rename to chrome/browser/ui/android/device_dialog/bluetooth_scanning_prompt_android.cc index e941cac..fe2a1bc 100644 --- a/chrome/browser/ui/android/bluetooth_scanning_prompt_android.cc +++ b/chrome/browser/ui/android/device_dialog/bluetooth_scanning_prompt_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 "chrome/browser/ui/android/bluetooth_scanning_prompt_android.h" +#include "chrome/browser/ui/android/device_dialog/bluetooth_scanning_prompt_android.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h"
diff --git a/chrome/browser/ui/android/bluetooth_scanning_prompt_android.h b/chrome/browser/ui/android/device_dialog/bluetooth_scanning_prompt_android.h similarity index 82% rename from chrome/browser/ui/android/bluetooth_scanning_prompt_android.h rename to chrome/browser/ui/android/device_dialog/bluetooth_scanning_prompt_android.h index 9ec2a32..89fe02f 100644 --- a/chrome/browser/ui/android/bluetooth_scanning_prompt_android.h +++ b/chrome/browser/ui/android/device_dialog/bluetooth_scanning_prompt_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 CHROME_BROWSER_UI_ANDROID_BLUETOOTH_SCANNING_PROMPT_ANDROID_H_ -#define CHROME_BROWSER_UI_ANDROID_BLUETOOTH_SCANNING_PROMPT_ANDROID_H_ +#ifndef CHROME_BROWSER_UI_ANDROID_DEVICE_DIALOG_BLUETOOTH_SCANNING_PROMPT_ANDROID_H_ +#define CHROME_BROWSER_UI_ANDROID_DEVICE_DIALOG_BLUETOOTH_SCANNING_PROMPT_ANDROID_H_ #include "base/android/scoped_java_ref.h" #include "base/macros.h" @@ -16,7 +16,7 @@ class BluetoothScanningPromptAndroid : public content::BluetoothScanningPrompt { public: // A Java counterpart will be generated for this enum. - // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser + // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.device_dialog enum BluetoothScanningPermissionEvent { ALLOW = 0, BLOCK = 1, @@ -47,4 +47,4 @@ DISALLOW_COPY_AND_ASSIGN(BluetoothScanningPromptAndroid); }; -#endif // CHROME_BROWSER_UI_ANDROID_BLUETOOTH_SCANNING_PROMPT_ANDROID_H_ +#endif // CHROME_BROWSER_UI_ANDROID_DEVICE_DIALOG_BLUETOOTH_SCANNING_PROMPT_ANDROID_H_
diff --git a/chrome/browser/ui/android/usb_chooser_dialog_android.cc b/chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.cc similarity index 98% rename from chrome/browser/ui/android/usb_chooser_dialog_android.cc rename to chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.cc index 78423c1..2160e48 100644 --- a/chrome/browser/ui/android/usb_chooser_dialog_android.cc +++ b/chrome/browser/ui/android/device_dialog/usb_chooser_dialog_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 "chrome/browser/ui/android/usb_chooser_dialog_android.h" +#include "chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.h" #include <stddef.h>
diff --git a/chrome/browser/ui/android/usb_chooser_dialog_android.h b/chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.h similarity index 90% rename from chrome/browser/ui/android/usb_chooser_dialog_android.h rename to chrome/browser/ui/android/device_dialog/usb_chooser_dialog_android.h index 97f5498..00ce6b7 100644 --- a/chrome/browser/ui/android/usb_chooser_dialog_android.h +++ b/chrome/browser/ui/android/device_dialog/usb_chooser_dialog_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 CHROME_BROWSER_UI_ANDROID_USB_CHOOSER_DIALOG_ANDROID_H_ -#define CHROME_BROWSER_UI_ANDROID_USB_CHOOSER_DIALOG_ANDROID_H_ +#ifndef CHROME_BROWSER_UI_ANDROID_DEVICE_DIALOG_USB_CHOOSER_DIALOG_ANDROID_H_ +#define CHROME_BROWSER_UI_ANDROID_DEVICE_DIALOG_USB_CHOOSER_DIALOG_ANDROID_H_ #include <memory> #include <string> @@ -69,4 +69,4 @@ DISALLOW_COPY_AND_ASSIGN(UsbChooserDialogAndroid); }; -#endif // CHROME_BROWSER_UI_ANDROID_USB_CHOOSER_DIALOG_ANDROID_H_ +#endif // CHROME_BROWSER_UI_ANDROID_DEVICE_DIALOG_USB_CHOOSER_DIALOG_ANDROID_H_
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc index 018dcaa5..801e9c1 100644 --- a/chrome/browser/ui/app_list/search/omnibox_result.cc +++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -31,8 +31,7 @@ namespace { -// #000 at 87% opacity. -constexpr SkColor kListIconColor = SkColorSetARGB(0xDE, 0x00, 0x00, 0x00); +constexpr SkColor kListIconColor = gfx::kGoogleGrey700; int ACMatchStyleToTagStyle(int styles) { int tag_styles = 0;
diff --git a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc index 6f39ae3b..92aec05 100644 --- a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc +++ b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
@@ -10,6 +10,7 @@ #include "ash/public/cpp/app_menu_constants.h" #include "ash/public/cpp/shelf_item.h" #include "base/bind_helpers.h" +#include "chrome/browser/chromeos/crostini/crostini_manager.h" #include "chrome/browser/chromeos/crostini/crostini_registry_service.h" #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h" #include "chrome/browser/chromeos/crostini/crostini_util.h"
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc index 9c1b3b1..28335b4 100644 --- a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc +++ b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
@@ -17,6 +17,7 @@ #include "base/test/bind_test_util.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/chromeos/arc/icon_decode_request.h" +#include "chrome/browser/chromeos/crostini/crostini_manager.h" #include "chrome/browser/chromeos/crostini/crostini_registry_service.h" #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h" #include "chrome/browser/chromeos/crostini/crostini_test_helper.h"
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index a9da630..53fe269 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -182,6 +182,7 @@ #include "components/sessions/core/tab_restore_service.h" #include "components/startup_metric_utils/browser/startup_metric_utils.h" #include "components/translate/core/browser/language_state.h" +#include "components/user_manager/user_manager.h" #include "components/viz/common/surfaces/surface_id.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/zoom/zoom_controller.h" @@ -237,6 +238,8 @@ #if defined(OS_CHROMEOS) #include "chrome/browser/ui/settings_window_manager_chromeos.h" +#include "components/session_manager/core/session_manager.h" +#include "components/user_manager/user_manager.h" #endif #if BUILDFLAG(ENABLE_EXTENSIONS) @@ -314,6 +317,26 @@ (!profile->IsGuestSession() || profile->IsOffTheRecord()) && profile->AllowsBrowserWindows(); } +bool IsOnKioskSplashScreen() { +#if defined(OS_CHROMEOS) + session_manager::SessionManager* session_manager = + session_manager::SessionManager::Get(); + if (!session_manager) + return false; + // We have to check this way because of CHECK() in UserManager::Get(). + if (!user_manager::UserManager::IsInitialized()) + return false; + user_manager::UserManager* user_manager = user_manager::UserManager::Get(); + if (!user_manager->IsLoggedInAsKioskApp() && + !user_manager->IsLoggedInAsArcKioskApp()) + return false; + if (session_manager->session_state() != session_manager::SessionState::LOGIN_PRIMARY) + return false; + return true; +#else + return false; +#endif +} } // namespace @@ -394,6 +417,10 @@ Browser* Browser::Create(const CreateParams& params) { if (!CanCreateBrowserForProfile(params.profile)) return nullptr; + // Disable browser creation on kiosk mode while loading. + if (IsOnKioskSplashScreen()) + return nullptr; + return new Browser(params); }
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc index dee922d..e96de7b 100644 --- a/chrome/browser/ui/browser_commands.cc +++ b/chrome/browser/ui/browser_commands.cc
@@ -47,6 +47,7 @@ #include "chrome/browser/ui/find_bar/find_bar.h" #include "chrome/browser/ui/find_bar/find_bar_controller.h" #include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "chrome/browser/ui/in_product_help/reopen_tab_in_product_help.h" #include "chrome/browser/ui/in_product_help/reopen_tab_in_product_help_factory.h" #include "chrome/browser/ui/location_bar/location_bar.h" @@ -1122,8 +1123,7 @@ void CloseFind(Browser* browser) { browser->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); } void Zoom(Browser* browser, content::PageZoom zoom) {
diff --git a/chrome/browser/ui/browser_unittest.cc b/chrome/browser/ui/browser_unittest.cc index 7e60b65..1df794b 100644 --- a/chrome/browser/ui/browser_unittest.cc +++ b/chrome/browser/ui/browser_unittest.cc
@@ -12,6 +12,11 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/testing_profile.h" +#include "components/session_manager/core/session_manager.h" +#include "components/user_manager/user_names.h" +#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" +#include "components/user_manager/fake_user_manager.h" +#include "components/user_manager/scoped_user_manager.h" #include "components/zoom/zoom_controller.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/site_instance.h" @@ -22,6 +27,7 @@ using content::SiteInstance; using content::WebContents; using content::WebContentsTester; +using session_manager::SessionState; class BrowserUnitTest : public BrowserWithTestWindowTest { public: @@ -268,6 +274,39 @@ EXPECT_TRUE(otr_browser); } +#if defined(OS_CHROMEOS) +TEST_F(BrowserUnitTest, CreateBrowserDuringKioskSplashScreen) { + session_manager::SessionManager session_manager; + + // Setting up user manager state to be in kiosk mode: + // Creating a new user manager. + chromeos::FakeChromeUserManager* user_manager = + new chromeos::FakeChromeUserManager(); + user_manager::ScopedUserManager manager{ + std::unique_ptr<user_manager::UserManager>(user_manager)}; + const user_manager::User* user = + user_manager->AddKioskAppUser(AccountId::FromUserEmail("fake_user@test")); + user_manager->LoginUser(user->GetAccountId()); + + TestingProfile profile; + Browser::CreateParams create_params(&profile, false); + + std::unique_ptr<BrowserWindow> window1(CreateBrowserWindow()); + create_params.window = window1.get(); + session_manager.SetSessionState(SessionState::LOGIN_PRIMARY); + std::unique_ptr<Browser> test_browser(Browser::Create(create_params)); + // Browser should not be created during login session state. + EXPECT_FALSE(test_browser); + + std::unique_ptr<BrowserWindow> window2(CreateBrowserWindow()); + create_params.window = window2.get(); + session_manager.SetSessionState(SessionState::ACTIVE); + std::unique_ptr<Browser> test_browser2(Browser::Create(create_params)); + // Normal flow, creation succeeds. + EXPECT_TRUE(test_browser2); +} +#endif + class BrowserBookmarkBarTest : public BrowserWithTestWindowTest { public: BrowserBookmarkBarTest() {}
diff --git a/chrome/browser/ui/find_bar/find_bar_controller.cc b/chrome/browser/ui/find_bar/find_bar_controller.cc index 8d453fd..1ec625d 100644 --- a/chrome/browser/ui/find_bar/find_bar_controller.cc +++ b/chrome/browser/ui/find_bar/find_bar_controller.cc
@@ -11,7 +11,6 @@ #include "base/no_destructor.h" #include "base/strings/string_util.h" #include "build/build_config.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" @@ -22,10 +21,12 @@ #include "chrome/browser/ui/find_bar/find_bar_state.h" #include "chrome/browser/ui/find_bar/find_bar_state_factory.h" #include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_source.h" +#include "content/public/browser/notification_types.h" #include "content/public/browser/web_contents.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/range/range.h" @@ -118,8 +119,9 @@ find_bar_->SetFocusAndSelection(); } -void FindBarController::EndFindSession(SelectionAction selection_action, - ResultAction result_action) { +void FindBarController::EndFindSession( + FindOnPageSelectionAction selection_action, + FindBoxResultAction result_action) { find_bar_->Hide(true); // |web_contents_| can be NULL for a number of reasons, for example when the @@ -133,7 +135,7 @@ // tickmarks and highlighting. find_tab_helper->StopFinding(selection_action); - if (result_action == kClearResultsInFindBox) + if (result_action == FindBoxResultAction::kClear) find_bar_->ClearResults(find_tab_helper->find_result()); // When we get dismissed we restore the focus to where it belongs. @@ -152,13 +154,17 @@ FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(web_contents_); - if (find_tab_helper) + if (find_tab_helper) { find_tab_helper->set_selected_range(find_bar_->GetSelectedRange()); + find_tab_observer_.Remove(find_tab_helper); + } } web_contents_ = contents; FindTabHelper* find_tab_helper = web_contents_ ? FindTabHelper::FromWebContents(web_contents_) : nullptr; + if (find_tab_helper) + find_tab_observer_.Add(find_tab_helper); // Hide any visible find window from the previous tab if a NULL tab contents // is passed in or if the find UI is not active in the new tab. @@ -170,9 +176,6 @@ if (!web_contents_) return; - registrar_.Add(this, - chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, - content::Source<WebContents>(web_contents_)); registrar_.Add( this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, @@ -208,24 +211,21 @@ void FindBarController::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { - if (type == chrome::NOTIFICATION_FIND_RESULT_AVAILABLE) { - DCHECK(content::Source<WebContents>(source).ptr() == web_contents_); - OnFindResultAvailable(); - } else if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { - NavigationController* source_controller = - content::Source<NavigationController>(source).ptr(); - if (source_controller == &web_contents_->GetController()) { - content::LoadCommittedDetails* commit_details = - content::Details<content::LoadCommittedDetails>(details).ptr(); - ui::PageTransition transition_type = - commit_details->entry->GetTransitionType(); - // Hide the find bar on reload or navigation. - if (find_bar_->IsFindBarVisible() && commit_details->is_main_frame && - (ui::PageTransitionCoreTypeIs(transition_type, - ui::PAGE_TRANSITION_RELOAD) || - commit_details->is_navigation_to_different_page())) - EndFindSession(kKeepSelectionOnPage, kClearResultsInFindBox); - } + DCHECK_EQ(content::NOTIFICATION_NAV_ENTRY_COMMITTED, type); + NavigationController* source_controller = + content::Source<NavigationController>(source).ptr(); + if (source_controller == &web_contents_->GetController()) { + content::LoadCommittedDetails* commit_details = + content::Details<content::LoadCommittedDetails>(details).ptr(); + ui::PageTransition transition_type = + commit_details->entry->GetTransitionType(); + // Hide the find bar on reload or navigation. + if (find_bar_->IsFindBarVisible() && commit_details->is_main_frame && + (ui::PageTransitionCoreTypeIs(transition_type, + ui::PAGE_TRANSITION_RELOAD) || + commit_details->is_navigation_to_different_page())) + EndFindSession(FindOnPageSelectionAction::kKeep, + FindBoxResultAction::kClear); } } @@ -269,7 +269,9 @@ return new_pos; } -void FindBarController::OnFindResultAvailable() { +void FindBarController::OnFindResultAvailable( + content::WebContents* web_contents) { + DCHECK_EQ(web_contents, web_contents_); UpdateFindBarForCurrentResult(); FindTabHelper* find_tab_helper =
diff --git a/chrome/browser/ui/find_bar/find_bar_controller.h b/chrome/browser/ui/find_bar/find_bar_controller.h index f6c5692c..7d5809d 100644 --- a/chrome/browser/ui/find_bar/find_bar_controller.h +++ b/chrome/browser/ui/find_bar/find_bar_controller.h
@@ -8,8 +8,11 @@ #include <memory> #include "base/macros.h" +#include "base/scoped_observer.h" #include "base/strings/string16.h" #include "chrome/browser/ui/find_bar/find_bar_platform_helper.h" +#include "chrome/browser/ui/find_bar/find_result_observer.h" +#include "chrome/browser/ui/find_bar/find_tab_helper.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -24,24 +27,12 @@ class Rect; } -class FindBarController : public content::NotificationObserver { +enum class FindOnPageSelectionAction; +enum class FindBoxResultAction; + +class FindBarController : public content::NotificationObserver, + public FindResultObserver { public: - // An enum listing the possible actions to take on a find-in-page selection - // in the page when ending the find session. - enum SelectionAction { - kKeepSelectionOnPage, // Translate the find selection into a normal - // selection. - kClearSelectionOnPage, // Clear the find selection. - kActivateSelectionOnPage // Focus and click the selected node (for links). - }; - - // An enum listing the possible actions to take on a find-in-page results in - // the Find box when ending the find session. - enum ResultAction { - kClearResultsInFindBox, // Clear search string, ordinal and match count. - kKeepResultsInFindBox, // Leave the results untouched. - }; - // FindBar takes ownership of |find_bar_view|. FindBarController(FindBar* find_bar, Browser* browser); @@ -51,10 +42,10 @@ void Show(); // Ends the current session. |selection_action| specifies what to do with the - // selection on the page created by the find operation. |results_action| + // selection on the page created by the find operation. |result_action| // specifies what to do with the contents of the Find box (after ending). - void EndFindSession(SelectionAction selection_action, - ResultAction results_action); + void EndFindSession(FindOnPageSelectionAction selection_action, + FindBoxResultAction result_action); // The visibility of the find bar view changed. void FindBarVisibilityChanged(); @@ -72,6 +63,9 @@ const content::NotificationSource& source, const content::NotificationDetails& details) override; + // FindResultObserver: + void OnFindResultAvailable(content::WebContents* web_contents) override; + void SetText(base::string16 text); // Called when the find text is updated in response to a user action. @@ -88,10 +82,6 @@ const gfx::Rect& avoid_overlapping_rect); private: - // Called when we've received notice of a find result for the associated - // WebContents. - void OnFindResultAvailable(); - // Sends an update to the find bar with the tab contents' current result. The // web_contents_ must be non-NULL before this call. This handles // de-flickering in addition to just calling the update function. @@ -121,6 +111,8 @@ int last_reported_matchcount_ = 0; int last_reported_ordinal_ = 0; + ScopedObserver<FindTabHelper, FindResultObserver> find_tab_observer_{this}; + DISALLOW_COPY_AND_ASSIGN(FindBarController); };
diff --git a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc index b6f8904..0e3e0d6 100644 --- a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc +++ b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
@@ -25,10 +25,11 @@ #include "chrome/browser/ui/find_bar/find_bar_host_unittest_util.h" #include "chrome/browser/ui/find_bar/find_notification_details.h" #include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/views_mode_controller.h" #include "chrome/common/url_constants.h" -#include "chrome/test/base/find_in_page_observer.h" +#include "chrome/test/base/find_result_waiter.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/prefs/pref_service.h" @@ -563,7 +564,7 @@ EXPECT_EQ(3, ordinal); // End the find session. - find_tab_helper->StopFinding(FindBarController::kKeepSelectionOnPage); + find_tab_helper->StopFinding(FindOnPageSelectionAction::kKeep); } // This tests that we start searching after selected text. @@ -1044,7 +1045,7 @@ browser()->tab_strip_model()->GetActiveWebContents()); // Stop the (non-existing) find operation, and clear the selection (which // signals the UI is still active). - find_tab_helper->StopFinding(FindBarController::kClearSelectionOnPage); + find_tab_helper->StopFinding(FindOnPageSelectionAction::kClear); // Make sure the Find UI flag hasn't been cleared, it must be so that the UI // still responds to browser window resizing. ASSERT_TRUE(find_tab_helper->find_ui_active()); @@ -1073,8 +1074,7 @@ // End the Find session, thereby making the next F3 start afresh. browser()->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); // Simulate F3 while Find box is closed. Should have 1 match. EXPECT_EQ(1, FindInPageASCII(web_contents, "", kFwd, kIgnoreCase, &ordinal)); @@ -1122,8 +1122,7 @@ // Switch back to first tab. browser()->tab_strip_model()->ActivateTabAt(0); browser()->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); // Simulate F3. ui_test_utils::FindInPage(web_contents_1, base::string16(), kFwd, kIgnoreCase, &ordinal, NULL); @@ -1159,8 +1158,7 @@ // Close the Find box. browser()->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); // Open the Find box again. EnsureFindBoxOpen(); @@ -1229,8 +1227,7 @@ // Close the Find box. browser()->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); // Now create a second tab and load the same page. chrome::AddTabAt(browser(), GURL(), -1, true); @@ -1255,8 +1252,7 @@ // Close the Find box. browser()->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); // Re-open the Find box. // This is a special case: previous search in WebContents used to get cleared @@ -1293,8 +1289,7 @@ // Close the Find box. browser()->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); // Open a new incognito window and navigate to the same page. Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile(); @@ -1321,8 +1316,7 @@ // Close the Find box. incognito_browser->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); // Now open a new tab in the original (non-incognito) browser. chrome::AddSelectedTabWithURL(browser(), url, ui::PAGE_TRANSITION_TYPED); @@ -1355,7 +1349,7 @@ content::WindowedNotificationObserver observer( content::NOTIFICATION_LOAD_STOP, content::Source<NavigationController>(&web_contents->GetController())); - find_tab_helper->StopFinding(FindBarController::kActivateSelectionOnPage); + find_tab_helper->StopFinding(FindOnPageSelectionAction::kActivate); observer.Wait(); } @@ -1509,14 +1503,12 @@ // Close the find bar. FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(web_contents_incognito); - find_tab_helper->StopFinding(FindBarController::kActivateSelectionOnPage); + find_tab_helper->StopFinding(FindOnPageSelectionAction::kActivate); // Cmd + G triggers IDC_FIND_NEXT command. Thus we test FindInPage() // method from browser_commands.cc. FindInPage16() bypasses it. EXPECT_TRUE(chrome::ExecuteCommand(browser_incognito, IDC_FIND_NEXT)); - ui_test_utils::FindInPageNotificationObserver observer( - web_contents_incognito); - observer.Wait(); + ui_test_utils::FindResultWaiter(web_contents_incognito).Wait(); EXPECT_EQ(ASCIIToUTF16("foo"), GetFindBarTextForBrowser(browser_incognito)); EXPECT_EQ(ASCIIToUTF16("2/2"), @@ -1547,9 +1539,7 @@ EXPECT_TRUE(chrome::ExecuteCommand(browser_incognito, IDC_FIND_NEXT)); WebContents* web_contents_incognito = browser_incognito->tab_strip_model()->GetActiveWebContents(); - ui_test_utils::FindInPageNotificationObserver observer( - web_contents_incognito); - observer.Wait(); + ui_test_utils::FindResultWaiter(web_contents_incognito).Wait(); EXPECT_EQ(ASCIIToUTF16("bar"), GetFindBarTextForBrowser(browser_incognito)); }
diff --git a/chrome/browser/ui/find_bar/find_bar_host_interactive_uitest.cc b/chrome/browser/ui/find_bar/find_bar_host_interactive_uitest.cc index 404669c1..0a89974 100644 --- a/chrome/browser/ui/find_bar/find_bar_host_interactive_uitest.cc +++ b/chrome/browser/ui/find_bar/find_bar_host_interactive_uitest.cc
@@ -8,6 +8,7 @@ #include "chrome/browser/ui/find_bar/find_bar.h" #include "chrome/browser/ui/find_bar/find_bar_controller.h" #include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" @@ -89,7 +90,7 @@ EXPECT_EQ(1, ordinal); // End the find session, which should set focus to the link. - find_tab_helper->StopFinding(FindBarController::kKeepSelectionOnPage); + find_tab_helper->StopFinding(FindOnPageSelectionAction::kKeep); // Verify that the link is focused. ASSERT_TRUE(FocusedOnPage(web_contents, &result)); @@ -107,7 +108,7 @@ &result)); // End the find session. - find_tab_helper->StopFinding(FindBarController::kKeepSelectionOnPage); + find_tab_helper->StopFinding(FindOnPageSelectionAction::kKeep); // Verify that link2 is not focused. ASSERT_TRUE(FocusedOnPage(web_contents, &result));
diff --git a/chrome/browser/ui/find_bar/find_bar_platform_helper_mac.mm b/chrome/browser/ui/find_bar/find_bar_platform_helper_mac.mm index d332d96..8476edc 100644 --- a/chrome/browser/ui/find_bar/find_bar_platform_helper_mac.mm +++ b/chrome/browser/ui/find_bar/find_bar_platform_helper_mac.mm
@@ -12,6 +12,7 @@ #include "chrome/browser/ui/find_bar/find_bar_controller.h" #import "chrome/browser/ui/find_bar/find_bar_platform_helper.h" #include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "content/public/browser/web_contents.h" #import "ui/base/cocoa/find_pasteboard.h" @@ -70,7 +71,7 @@ continue; FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(web_contents); - find_tab_helper->StopFinding(FindBarController::kClearSelectionOnPage); + find_tab_helper->StopFinding(FindOnPageSelectionAction::kClear); } }
diff --git a/chrome/browser/ui/find_bar/find_bar_platform_helper_mac_interactive_uitest.mm b/chrome/browser/ui/find_bar/find_bar_platform_helper_mac_interactive_uitest.mm index 494dd9f2..6034ff196 100644 --- a/chrome/browser/ui/find_bar/find_bar_platform_helper_mac_interactive_uitest.mm +++ b/chrome/browser/ui/find_bar/find_bar_platform_helper_mac_interactive_uitest.mm
@@ -15,8 +15,9 @@ #include "chrome/browser/ui/find_bar/find_bar.h" #include "chrome/browser/ui/find_bar/find_bar_controller.h" #include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "chrome/browser/ui/view_ids.h" -#include "chrome/test/base/find_in_page_observer.h" +#include "chrome/test/base/find_result_waiter.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" @@ -196,9 +197,7 @@ ASSERT_TRUE(chrome::ExecuteCommand(browser_incognito, IDC_FIND_NEXT)); content::WebContents* web_contents_incognito = browser_incognito->tab_strip_model()->GetActiveWebContents(); - ui_test_utils::FindInPageNotificationObserver observer( - web_contents_incognito); - observer.Wait(); + ui_test_utils::FindResultWaiter(web_contents_incognito).Wait(); FindBarController* find_bar_controller = browser_incognito->GetFindBarController(); @@ -256,8 +255,8 @@ // Go back to the first tab and end the search. browser()->tab_strip_model()->ActivateTabAt(0); - find_bar_controller->EndFindSession(FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + find_bar_controller->EndFindSession(FindOnPageSelectionAction::kKeep, + FindBoxResultAction::kKeep); // Simulate F3. ui_test_utils::FindInPage(first_active_web_contents, base::string16(), true, false, nullptr, nullptr);
diff --git a/chrome/browser/ui/find_bar/find_result_observer.h b/chrome/browser/ui/find_bar/find_result_observer.h new file mode 100644 index 0000000..44947818 --- /dev/null +++ b/chrome/browser/ui/find_bar/find_result_observer.h
@@ -0,0 +1,19 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_FIND_BAR_FIND_RESULT_OBSERVER_H_ +#define CHROME_BROWSER_UI_FIND_BAR_FIND_RESULT_OBSERVER_H_ + +#include "base/observer_list_types.h" + +namespace content { +class WebContents; +} + +class FindResultObserver : public base::CheckedObserver { + public: + virtual void OnFindResultAvailable(content::WebContents* web_contents) = 0; +}; + +#endif // CHROME_BROWSER_UI_FIND_BAR_FIND_RESULT_OBSERVER_H_
diff --git a/chrome/browser/ui/find_bar/find_tab_helper.cc b/chrome/browser/ui/find_bar/find_tab_helper.cc index e72ea07..fb47d5356 100644 --- a/chrome/browser/ui/find_bar/find_tab_helper.cc +++ b/chrome/browser/ui/find_bar/find_tab_helper.cc
@@ -13,6 +13,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/find_bar/find_bar_state.h" #include "chrome/browser/ui/find_bar/find_bar_state_factory.h" +#include "chrome/browser/ui/find_bar/find_result_observer.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" @@ -36,7 +38,14 @@ last_search_result_() { } -FindTabHelper::~FindTabHelper() { +FindTabHelper::~FindTabHelper() = default; + +void FindTabHelper::AddObserver(FindResultObserver* observer) { + observers_.AddObserver(observer); +} + +void FindTabHelper::RemoveObserver(FindResultObserver* observer) { + observers_.RemoveObserver(observer); } void FindTabHelper::StartFinding(base::string16 search_string, @@ -103,9 +112,8 @@ std::move(options)); } -void FindTabHelper::StopFinding( - FindBarController::SelectionAction selection_action) { - if (selection_action == FindBarController::kClearSelectionOnPage) { +void FindTabHelper::StopFinding(FindOnPageSelectionAction selection_action) { + if (selection_action == FindOnPageSelectionAction::kClear) { // kClearSelection means the find string has been cleared by the user, but // the UI has not been dismissed. In that case we want to clear the // previously remembered search (http://crbug.com/42639). @@ -122,13 +130,13 @@ content::StopFindAction action; switch (selection_action) { - case FindBarController::kClearSelectionOnPage: + case FindOnPageSelectionAction::kClear: action = content::STOP_FIND_ACTION_CLEAR_SELECTION; break; - case FindBarController::kKeepSelectionOnPage: + case FindOnPageSelectionAction::kKeep: action = content::STOP_FIND_ACTION_KEEP_SELECTION; break; - case FindBarController::kActivateSelectionOnPage: + case FindOnPageSelectionAction::kActivate: action = content::STOP_FIND_ACTION_ACTIVATE_SELECTION; break; default: @@ -181,10 +189,8 @@ last_search_result_ = FindNotificationDetails( request_id, number_of_matches, selection, active_match_ordinal, final_update); - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, - content::Source<WebContents>(web_contents()), - content::Details<FindNotificationDetails>(&last_search_result_)); + for (auto& observer : observers_) + observer.OnFindResultAvailable(web_contents()); } }
diff --git a/chrome/browser/ui/find_bar/find_tab_helper.h b/chrome/browser/ui/find_bar/find_tab_helper.h index 4b47546..055fc5d 100644 --- a/chrome/browser/ui/find_bar/find_tab_helper.h +++ b/chrome/browser/ui/find_bar/find_tab_helper.h
@@ -7,18 +7,23 @@ #include "base/macros.h" #include "build/build_config.h" -#include "chrome/browser/ui/find_bar/find_bar_controller.h" #include "chrome/browser/ui/find_bar/find_notification_details.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" #include "ui/gfx/range/range.h" +class FindResultObserver; +enum class FindOnPageSelectionAction; + // Per-tab find manager. Handles dealing with the life cycle of find sessions. class FindTabHelper : public content::WebContentsObserver, public content::WebContentsUserData<FindTabHelper> { public: ~FindTabHelper() override; + void AddObserver(FindResultObserver* observer); + void RemoveObserver(FindResultObserver* observer); + // Starts the Find operation by calling StartFinding on the Tab. This function // can be called from the outside as a result of hot-keys, so it uses the // last remembered search string as specified with set_find_string(). This @@ -31,7 +36,7 @@ bool run_synchronously_for_testing = false); // Stops the current Find operation. - void StopFinding(FindBarController::SelectionAction selection_action); + void StopFinding(FindOnPageSelectionAction selection_action); // When the user commits to a search query or jumps from one result // to the next, move accessibility focus to the next find result. @@ -150,6 +155,8 @@ // information to build its presentation. FindNotificationDetails last_search_result_; + base::ObserverList<FindResultObserver> observers_; + WEB_CONTENTS_USER_DATA_KEY_DECL(); DISALLOW_COPY_AND_ASSIGN(FindTabHelper);
diff --git a/chrome/browser/ui/find_bar/find_types.h b/chrome/browser/ui/find_bar/find_types.h new file mode 100644 index 0000000..7da40514 --- /dev/null +++ b/chrome/browser/ui/find_bar/find_types.h
@@ -0,0 +1,23 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_FIND_BAR_FIND_TYPES_H_ +#define CHROME_BROWSER_UI_FIND_BAR_FIND_TYPES_H_ + +// An enum listing the possible actions to take on a find-in-page selection +// in the page when ending the find session. +enum class FindOnPageSelectionAction { + kKeep, // Translate the find selection into a normal selection. + kClear, // Clear the find selection. + kActivate // Focus and click the selected node (for links). +}; + +// An enum listing the possible actions to take on a find-in-page results in +// the Find box when ending the find session. +enum class FindBoxResultAction { + kClear, // Clear search string, ordinal and match count. + kKeep, // Leave the results untouched. +}; + +#endif // CHROME_BROWSER_UI_FIND_BAR_FIND_TYPES_H_
diff --git a/chrome/browser/ui/hats/OWNERS b/chrome/browser/ui/hats/OWNERS new file mode 100644 index 0000000..1d527a2 --- /dev/null +++ b/chrome/browser/ui/hats/OWNERS
@@ -0,0 +1,3 @@ +kylixrd@chromium.org +robliao@chromium.org +weili@chromium.org
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc index 398b2e1..16d6965a 100644 --- a/chrome/browser/ui/hats/hats_service.cc +++ b/chrome/browser/ui/hats/hats_service.cc
@@ -29,34 +29,25 @@ constexpr char kHatsSurveyTriggerSatisfaction[] = "satisfaction"; -HatsFinchConfig CreateHatsFinchConfig() { - HatsFinchConfig config; - config.trigger = base::FeatureParam<std::string>( - &features::kHappinessTrackingSurveysForDesktop, - kHatsSurveyTrigger, kHatsSurveyTriggerDefault) - .Get(); - - config.probability = - base::FeatureParam<double>(&features::kHappinessTrackingSurveysForDesktop, - kHatsSurveyProbability, - kHatsSurveyProbabilityDefault) - .Get(); - - config.site_ids.insert( - std::make_pair("en", base::FeatureParam<std::string>( - &features::kHappinessTrackingSurveysForDesktop, - kHatsSurveyEnSiteID, kHatsSurveyEnSiteIDDefault) - .Get())); - return config; -} } // namespace -HatsFinchConfig::HatsFinchConfig() = default; -HatsFinchConfig::~HatsFinchConfig() = default; -HatsFinchConfig::HatsFinchConfig(const HatsFinchConfig& other) = default; - HatsService::HatsService(Profile* profile) - : profile_(profile), hats_finch_config_(CreateHatsFinchConfig()) {} + : profile_(profile), + trigger_(base::FeatureParam<std::string>( + &features::kHappinessTrackingSurveysForDesktop, + kHatsSurveyTrigger, + kHatsSurveyTriggerDefault) + .Get()), + probability_(base::FeatureParam<double>( + &features::kHappinessTrackingSurveysForDesktop, + kHatsSurveyProbability, + kHatsSurveyProbabilityDefault) + .Get()), + en_site_id_(base::FeatureParam<std::string>( + &features::kHappinessTrackingSurveysForDesktop, + kHatsSurveyEnSiteID, + kHatsSurveyEnSiteIDDefault) + .Get()) {} void HatsService::LaunchSatisfactionSurvey() { if (ShouldShowSurvey(kHatsSurveyTriggerSatisfaction)) { @@ -67,10 +58,9 @@ } bool HatsService::ShouldShowSurvey(const std::string& trigger) const { - if ((hats_finch_config_.trigger == trigger || - hats_finch_config_.trigger == kHatsSurveyTriggerDefault) && + if ((trigger_ == trigger || trigger_ == kHatsSurveyTriggerDefault) && !launch_hats_) { - if (base::RandDouble() < hats_finch_config_.probability) { + if (base::RandDouble() < probability_) { // we only want to ever show hats once per profile. launch_hats_ = true; return true;
diff --git a/chrome/browser/ui/hats/hats_service.h b/chrome/browser/ui/hats/hats_service.h index c7fc370..34d088d 100644 --- a/chrome/browser/ui/hats/hats_service.h +++ b/chrome/browser/ui/hats/hats_service.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_UI_HATS_HATS_SERVICE_H_ #define CHROME_BROWSER_UI_HATS_HATS_SERVICE_H_ -#include <map> #include <string> #include "base/gtest_prod_util.h" @@ -14,20 +13,6 @@ class Profile; -struct HatsFinchConfig { - HatsFinchConfig(); - ~HatsFinchConfig(); - HatsFinchConfig(const HatsFinchConfig& other); - - double probability; // This is the percent of users [0,1] that will see the - // survey - std::string trigger; // This is the name of the survey in question. - - // This is a map between the locale being presented and the site ID used to - // fetch the survey. - std::map<std::string, std::string> site_ids; -}; - // This class provides the client side logic for determining if a // survey should be shown for any trigger based on input from a finch // configuration. It is created on a per profile basis. @@ -39,17 +24,28 @@ // it's appropriate. void LaunchSatisfactionSurvey(); + // Returns the en-us site ID for the HaTS survey. + const std::string& en_site_id() const { return en_site_id_; } + private: + FRIEND_TEST_ALL_PREFIXES(HatsForceEnabledTest, ParamsWithAForcedFlagTest); + // This returns true is the survey trigger specified should be shown. bool ShouldShowSurvey(const std::string& trigger) const; // a temporary flag to ensure that hats is not launched multiple times // TODO: replace with pref lookup static bool launch_hats_; - Profile* profile_; - const HatsFinchConfig hats_finch_config_; + Profile* const profile_; - FRIEND_TEST_ALL_PREFIXES(HatsForceEnabledTest, ParamsWithAForcedFlagTest); + // Trigger string identifier. + const std::string trigger_; + + // Percent of users [0,1] that will see the survey. + const double probability_; + + // Site ID for the survey. + const std::string en_site_id_; DISALLOW_COPY_AND_ASSIGN(HatsService); };
diff --git a/chrome/browser/ui/hats/hats_unittest.cc b/chrome/browser/ui/hats/hats_unittest.cc index ed56f9a42..b2e6cf2b 100644 --- a/chrome/browser/ui/hats/hats_unittest.cc +++ b/chrome/browser/ui/hats/hats_unittest.cc
@@ -30,5 +30,5 @@ }; TEST_F(HatsForceEnabledTest, ParamsWithAForcedFlagTest) { - ASSERT_EQ(1, hats_service_->hats_finch_config_.probability); + ASSERT_EQ(1, hats_service_->probability_); }
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc index 90f77c7..fc6d56c 100644 --- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc +++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -14,6 +14,7 @@ #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "build/build_config.h" @@ -47,6 +48,7 @@ #include "components/omnibox/browser/omnibox_popup_model.h" #include "components/omnibox/browser/omnibox_view.h" #include "components/omnibox/browser/test_location_bar_model.h" +#include "components/omnibox/common/omnibox_features.h" #include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/search_engines/template_url.h" @@ -1331,11 +1333,14 @@ #if !defined(OS_MACOSX) // Mac intentionally does not support this behavior. IN_PROC_BROWSER_TEST_F(OmniboxViewTest, TabTraverseResultsTest) { - OmniboxView* omnibox_view = NULL; + OmniboxView* omnibox_view = nullptr; ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view)); OmniboxPopupModel* popup_model = omnibox_view->model()->popup_model(); ASSERT_TRUE(popup_model); + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(omnibox::kOmniboxWrapPopupPosition); + // Input something to trigger results. const ui::KeyboardCode kKeys[] = { ui::VKEY_B, ui::VKEY_A, ui::VKEY_R, ui::VKEY_UNKNOWN @@ -1352,6 +1357,8 @@ popup_model->selected_line() < size - 1; old_selected_line = popup_model->selected_line()) { ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0)); + ASSERT_FALSE(omnibox_view->model()->is_keyword_hint()); + ASSERT_EQ(base::string16(), omnibox_view->model()->keyword()); ASSERT_LT(old_selected_line, popup_model->selected_line()); } @@ -1391,6 +1398,90 @@ ASSERT_FALSE(omnibox_view->model()->is_keyword_hint()); ASSERT_EQ(text, omnibox_view->model()->keyword()); ASSERT_TRUE(omnibox_view->GetText().empty()); + ASSERT_EQ(0U, omnibox_view->model()->popup_model()->selected_line()); + + // The location bar should still have focus. + ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); + + // Pressing tab again should move to the next result and clear keyword + // mode. + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0)); + ASSERT_FALSE(omnibox_view->model()->is_keyword_hint()); + ASSERT_NE(text, omnibox_view->model()->keyword()); + ASSERT_EQ(1U, omnibox_view->model()->popup_model()->selected_line()); + + // The location bar should still have focus. + ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); + + // Moving back up should not show keyword mode. + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN)); + ASSERT_TRUE(omnibox_view->model()->is_keyword_hint()); + ASSERT_EQ(text, omnibox_view->model()->keyword()); + + ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); +} + +IN_PROC_BROWSER_TEST_F(OmniboxViewTest, WrappingTabTraverseResultsTest) { + OmniboxView* omnibox_view = nullptr; + ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view)); + OmniboxPopupModel* popup_model = omnibox_view->model()->popup_model(); + ASSERT_TRUE(popup_model); + + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(omnibox::kOmniboxWrapPopupPosition); + + // Input something to trigger results. + const ui::KeyboardCode kKeys[] = {ui::VKEY_B, ui::VKEY_A, ui::VKEY_R, + ui::VKEY_UNKNOWN}; + ASSERT_NO_FATAL_FAILURE(SendKeySequence(kKeys)); + ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone()); + ASSERT_TRUE(popup_model->IsOpen()); + + size_t old_selected_line = popup_model->selected_line(); + EXPECT_EQ(0U, old_selected_line); + + // Move down the results. + for (size_t size = popup_model->result().size(); + popup_model->selected_line() < size - 1; + old_selected_line = popup_model->selected_line()) { + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0)); + ASSERT_LT(old_selected_line, popup_model->selected_line()); + } + + // Wrap to top. + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0)); + ASSERT_EQ(0U, popup_model->selected_line()); + ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); + + // Wrap to bottom. + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN)); + ASSERT_EQ(old_selected_line, popup_model->selected_line()); + ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); + + // Move back up the results. + for (; popup_model->selected_line() > 0U; + old_selected_line = popup_model->selected_line()) { + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN)); + ASSERT_GT(old_selected_line, popup_model->selected_line()); + } + + const TestHistoryEntry kHistoryFoo = {"http://foo/", "Page foo", 1, 1, false}; + + // Add a history entry so "foo" gets multiple matches. + ASSERT_NO_FATAL_FAILURE(AddHistoryEntry( + kHistoryFoo, base::Time::Now() - base::TimeDelta::FromHours(1))); + + // Load results. + ASSERT_NO_FATAL_FAILURE(omnibox_view->SelectAll(false)); + ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchKeywordKeys)); + ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone()); + + // Trigger keyword mode by tab. + base::string16 text = ASCIIToUTF16(kSearchKeyword); + ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0)); + ASSERT_FALSE(omnibox_view->model()->is_keyword_hint()); + ASSERT_EQ(text, omnibox_view->model()->keyword()); + ASSERT_TRUE(omnibox_view->GetText().empty()); // The location bar should still have focus. ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index 8530e121..b500be9 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -32,6 +32,7 @@ #include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_observer.h" #include "chrome/browser/metrics/oom/out_of_memory_reporter.h" #include "chrome/browser/metrics/renderer_uptime_web_contents_observer.h" +#include "chrome/browser/native_file_system/native_file_system_permission_request_manager.h" #include "chrome/browser/net/net_error_tab_helper.h" #include "chrome/browser/page_load_metrics/page_load_metrics_initialize.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h" @@ -225,6 +226,7 @@ metrics::RendererUptimeWebContentsObserver::CreateForWebContents( web_contents); MixedContentSettingsTabHelper::CreateForWebContents(web_contents); + NativeFileSystemPermissionRequestManager::CreateForWebContents(web_contents); NavigationCorrectionTabObserver::CreateForWebContents(web_contents); NavigationMetricsRecorder::CreateForWebContents(web_contents); OutOfMemoryReporter::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc index 664ce5ce..7f202a2 100644 --- a/chrome/browser/ui/views/download/download_item_view.cc +++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -88,7 +88,7 @@ constexpr int kMinimumVerticalPadding = 2 + kTopBottomPadding; // The normal height of the item which may be exceeded if text is large. -constexpr int kDefaultHeight = 48; +constexpr int kDefaultDownloadItemHeight = 48; // Amount of time between accessible alert events. constexpr base::TimeDelta kAccessibleAlertInterval = @@ -444,7 +444,7 @@ if (mode_ != DANGEROUS_MODE) width += dropdown_button_->GetPreferredSize().width(); - return gfx::Size(width, std::max(kDefaultHeight, + return gfx::Size(width, std::max(kDefaultDownloadItemHeight, 2 * kMinimumVerticalPadding + child_height)); }
diff --git a/chrome/browser/ui/views/find_bar_host.cc b/chrome/browser/ui/views/find_bar_host.cc index b850e99..49d2bbf 100644 --- a/chrome/browser/ui/views/find_bar_host.cc +++ b/chrome/browser/ui/views/find_bar_host.cc
@@ -9,6 +9,7 @@ #include "build/build_config.h" #include "chrome/browser/ui/find_bar/find_bar_controller.h" #include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/find_bar_view.h" #include "chrome/browser/ui/views/frame/browser_view.h" @@ -192,17 +193,15 @@ ui::KeyboardCode key = accelerator.key_code(); if (key == ui::VKEY_RETURN && accelerator.IsCtrlDown()) { // Ctrl+Enter closes the Find session and navigates any link that is active. - find_bar_controller_->EndFindSession( - FindBarController::kActivateSelectionOnPage, - FindBarController::kClearResultsInFindBox); + find_bar_controller_->EndFindSession(FindOnPageSelectionAction::kActivate, + FindBoxResultAction::kClear); return true; } else if (key == ui::VKEY_ESCAPE) { // This will end the Find session and hide the window, causing it to loose // focus and in the process unregister us as the handler for the Escape // accelerator through the OnWillChangeFocus event. - find_bar_controller_->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + find_bar_controller_->EndFindSession(FindOnPageSelectionAction::kKeep, + FindBoxResultAction::kKeep); return true; } else { NOTREACHED() << "Unknown accelerator";
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc index 2accdcc..cd5d170b 100644 --- a/chrome/browser/ui/views/find_bar_view.cc +++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/ui/find_bar/find_bar_state_factory.h" #include "chrome/browser/ui/find_bar/find_notification_details.h" #include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/find_bar_host.h" @@ -395,8 +396,7 @@ break; case VIEW_ID_FIND_IN_PAGE_CLOSE_BUTTON: find_bar_host_->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); break; default: NOTREACHED() << "Unknown button"; @@ -476,7 +476,7 @@ // The last two params here are forward (true) and case sensitive (false). find_tab_helper->StartFinding(search_text, true, false); } else { - find_tab_helper->StopFinding(FindBarController::kClearSelectionOnPage); + find_tab_helper->StopFinding(FindOnPageSelectionAction::kClear); UpdateForResult(find_tab_helper->find_result(), base::string16()); find_bar_host_->MoveWindowIfNecessary(gfx::Rect());
diff --git a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc index d7c7299..71bce1a 100644 --- a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc +++ b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
@@ -13,10 +13,13 @@ #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/find_bar/find_bar_controller.h" #include "chrome/browser/ui/find_bar/find_notification_details.h" +#include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "chrome/browser/ui/find_bar/find_types.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/find_bar_host.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/test/base/find_result_waiter.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" @@ -78,15 +81,10 @@ } FindNotificationDetails WaitForFindResult() { - content::Source<WebContents> source( - browser()->tab_strip_model()->GetActiveWebContents()); - ui_test_utils::WindowedNotificationObserverWithDetails - <FindNotificationDetails> observer( - chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, source); - observer.Wait(); - FindNotificationDetails details; - EXPECT_TRUE(observer.GetDetailsFor(source.map_key(), &details)); - return details; + WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + ui_test_utils::FindResultWaiter(web_contents).Wait(); + return FindTabHelper::FromWebContents(web_contents)->find_result(); } FindNotificationDetails WaitForFinalFindResult() { @@ -263,8 +261,7 @@ browser()->GetFindBarController()->Show(); EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); browser()->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_OMNIBOX)); // Focus the location bar, find something on the page, close the find box, @@ -276,8 +273,7 @@ browser()->tab_strip_model()->GetActiveWebContents(), ASCIIToUTF16("a"), true, false, NULL, NULL); browser()->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); // Focus the location bar, open and close the find box, focus should return to @@ -288,8 +284,7 @@ browser()->GetFindBarController()->Show(); EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); browser()->GetFindBarController()->EndFindSession( - FindBarController::kKeepSelectionOnPage, - FindBarController::kKeepResultsInFindBox); + FindOnPageSelectionAction::kKeep, FindBoxResultAction::kKeep); EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_OMNIBOX)); }
diff --git a/chrome/browser/ui/views/hats/hats_web_dialog.cc b/chrome/browser/ui/views/hats/hats_web_dialog.cc index ac5e20a..dd98b7c 100644 --- a/chrome/browser/ui/views/hats/hats_web_dialog.cc +++ b/chrome/browser/ui/views/hats/hats_web_dialog.cc
@@ -11,6 +11,8 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/hats/hats_service.h" +#include "chrome/browser/ui/hats/hats_service_factory.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/common/pref_names.h" #include "chrome/grit/browser_resources.h" @@ -29,13 +31,8 @@ namespace { // Default width/height of the dialog in screen size. -const int kDefaultWidth = 400; -const int kDefaultHeight = 420; - -// Site ID of HaTS survey for Chrome Desktop. -// TODO(weili): Replace this with the pilot survey site ID retrieved from finch -// config. -constexpr char kSiteID[] = "z4cctguzopq5x2ftal6vdgjrui"; +const int kDefaultHatsDialogWidth = 400; +const int kDefaultHatsDialogHeight = 420; // Placeholder strings in html file to be replaced when the file is loaded. constexpr char kScriptSrcReplacementToken[] = "$SCRIPT_SRC"; @@ -80,16 +77,19 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(browser); + Profile* profile = browser->profile(); + // Self deleting upon close. - auto* hats_dialog = new HatsWebDialog(); + auto* hats_dialog = new HatsWebDialog( + HatsServiceFactory::GetForProfile(profile, true)->en_site_id()); BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); - chrome::ShowWebDialog(browser_view->GetWidget()->GetNativeView(), - browser->profile(), hats_dialog); + chrome::ShowWebDialog(browser_view->GetWidget()->GetNativeView(), profile, + hats_dialog); } -HatsWebDialog::HatsWebDialog() { +HatsWebDialog::HatsWebDialog(const std::string& site_id) : site_id_(site_id) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } @@ -108,7 +108,7 @@ GURL HatsWebDialog::GetDialogContentURL() const { // Load the html data and use it in a data URL to be displayed in the dialog. std::string url_str = - LoadLocalHtmlAsString(kSiteID, version_info::GetVersionNumber()); + LoadLocalHtmlAsString(site_id_, version_info::GetVersionNumber()); url::RawCanonOutputT<char> url; url::EncodeURIComponent(url_str.c_str(), url_str.length(), &url); return GURL("data:text/html;charset=utf-8," + @@ -119,7 +119,7 @@ std::vector<content::WebUIMessageHandler*>* handlers) const {} void HatsWebDialog::GetDialogSize(gfx::Size* size) const { - size->SetSize(kDefaultWidth, kDefaultHeight); + size->SetSize(kDefaultHatsDialogWidth, kDefaultHatsDialogHeight); } bool HatsWebDialog::CanResizeDialog() const {
diff --git a/chrome/browser/ui/views/hats/hats_web_dialog.h b/chrome/browser/ui/views/hats/hats_web_dialog.h index 223ff4b5..93615c1c 100644 --- a/chrome/browser/ui/views/hats/hats_web_dialog.h +++ b/chrome/browser/ui/views/hats/hats_web_dialog.h
@@ -22,8 +22,8 @@ static void Show(const Browser* browser); private: - // Use Show() above. - HatsWebDialog(); + // Use Show() above. |site_id| is used to select the survey. + explicit HatsWebDialog(const std::string& site_id); ~HatsWebDialog() override; // ui::WebDialogDelegate implementation. @@ -44,6 +44,7 @@ const content::ContextMenuParams& params) override; const std::string html_data_; + const std::string site_id_; DISALLOW_COPY_AND_ASSIGN(HatsWebDialog); };
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_access_icon_view.cc b/chrome/browser/ui/views/native_file_system/native_file_system_access_icon_view.cc index b3b4b86f..6d945140 100644 --- a/chrome/browser/ui/views/native_file_system/native_file_system_access_icon_view.cc +++ b/chrome/browser/ui/views/native_file_system/native_file_system_access_icon_view.cc
@@ -6,6 +6,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/app/vector_icons/vector_icons.h" +#include "chrome/browser/native_file_system/chrome_native_file_system_permission_context.h" #include "chrome/browser/ui/views/native_file_system/native_file_system_usage_bubble_view.h" #include "chrome/grit/generated_resources.h" #include "components/vector_icons/vector_icons.h" @@ -51,15 +52,33 @@ url::Origin origin = url::Origin::Create(GetWebContents()->GetLastCommittedURL()); - // TODO(https://crbug.com/979684): Display actual files and directories, - // rather than these random hard coded values. - NativeFileSystemUsageBubbleView::Usage usage; - usage.readable_directories.emplace_back(FILE_PATH_LITERAL("My Fonts")); - usage.writable_files.emplace_back(FILE_PATH_LITERAL("/foo/bar/demo.txt")); - usage.writable_files.emplace_back(FILE_PATH_LITERAL("README.md")); - usage.writable_directories.emplace_back(FILE_PATH_LITERAL("My Project")); - NativeFileSystemUsageBubbleView::ShowBubble(GetWebContents(), origin, - std::move(usage)); + ChromeNativeFileSystemPermissionContext::GetPermissionGrantsFromUIThread( + GetWebContents()->GetBrowserContext(), origin, + base::BindOnce( + [](int frame_tree_node_id, const url::Origin& origin, + ChromeNativeFileSystemPermissionContext::Grants grants) { + auto* web_contents = + content::WebContents::FromFrameTreeNodeId(frame_tree_node_id); + if (!web_contents || + url::Origin::Create(web_contents->GetLastCommittedURL()) != + origin) { + // If web-contents has navigated to a different origin while we + // were looking up current usage, don't show the dialog to avoid + // showing the dialog for the wrong origin. + return; + } + + NativeFileSystemUsageBubbleView::Usage usage; + usage.readable_directories = + web_contents->GetNativeFileSystemDirectoryHandles(); + usage.writable_files = std::move(grants.file_write_grants); + usage.writable_directories = + std::move(grants.directory_write_grants); + + NativeFileSystemUsageBubbleView::ShowBubble(web_contents, origin, + std::move(usage)); + }, + GetWebContents()->GetMainFrame()->GetFrameTreeNodeId(), origin)); } const gfx::VectorIcon& NativeFileSystemAccessIconView::GetVectorIcon() const {
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.cc b/chrome/browser/ui/views/translate/translate_bubble_view.cc index 24af817..ceb6b3f5 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view.cc +++ b/chrome/browser/ui/views/translate/translate_bubble_view.cc
@@ -140,6 +140,17 @@ view->SetHighlightedButton(highlighted_button); views::Widget* bubble_widget = views::BubbleDialogDelegateView::CreateBubble(view); + + // TAB UI has the same view throughout. Select the right tab based on |step| + // upon initialization. + if (step != translate::TRANSLATE_STEP_TRANSLATE_ERROR) { + TranslateBubbleModel::ViewState state = + TranslateBubbleModelImpl::TranslateStepToViewState(step); + translate_bubble_view_->SwitchView(state); + } else { + translate_bubble_view_->SwitchToErrorView(error_type); + } + // |allow_refocus_alert| is set to false because translate bubble does not // have an additional screen reader alert instructing the user to use a // hotkey combination to focus the bubble. @@ -202,9 +213,9 @@ void TranslateBubbleView::TabSelectedAt(int index) { // Tabbed pane is indexed from left to right starting at 0. - if (index == 1) { + if (!model_->IsPageTranslatedInCurrentLanguages() && index == 1) { Translate(); - } else { + } else if (index == 0) { ShowOriginal(); } } @@ -755,8 +766,9 @@ for (views::View* view : children()) view->SetVisible(view == GetCurrentView()); - // Not required for TAB ui because the title is not shown. - if (bubble_ui_model_ != language::TranslateUIBubbleModel::TAB && + // Not required for TAB UI or Button_GM2 UI because the title is not shown. + if (bubble_ui_model_ != language::TranslateUIBubbleModel::BUTTON_GM2 && + bubble_ui_model_ != language::TranslateUIBubbleModel::TAB && GetWidget()) { GetWidget()->UpdateWindowTitle(); } @@ -888,6 +900,7 @@ tab_translate_options_button->set_ink_drop_base_color(gfx::kChromeIconGrey); tab_translate_options_button->SetInkDropMode(views::Button::InkDropMode::ON); tab_translate_options_button->SetID(BUTTON_ID_OPTIONS_MENU_TAB); + tab_translate_options_button->SetFocusForPlatform(); tab_translate_options_button->set_request_focus_on_press(true); // Close button @@ -1659,10 +1672,11 @@ void TranslateBubbleView::SwitchView( TranslateBubbleModel::ViewState view_state) { TranslateBubbleModel::ViewState current_state = model_->GetViewState(); - if ((bubble_ui_model_ == language::TranslateUIBubbleModel::TAB && - TabUiIsEquivalentState(view_state) && - TabUiIsEquivalentState(current_state)) || - current_state == view_state) { + if (bubble_ui_model_ == language::TranslateUIBubbleModel::TAB) { + SwitchTabForViewState(view_state); + } + + if (current_state == view_state) { return; } @@ -1673,6 +1687,17 @@ SizeToContents(); } +void TranslateBubbleView::SwitchTabForViewState( + TranslateBubbleModel::ViewState view_state) { + if ((view_state == TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE || + view_state == TranslateBubbleModel::VIEW_STATE_TRANSLATING) && + tabbed_pane_->GetSelectedTabIndex() != 1) { + tabbed_pane_->SelectTabAt(1); + } else if (view_state == TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE && + tabbed_pane_->GetSelectedTabIndex() != 0) { + tabbed_pane_->SelectTabAt(0); + } +} void TranslateBubbleView::SwitchToErrorView( translate::TranslateErrors::Type error_type) { SwitchView(TranslateBubbleModel::VIEW_STATE_ERROR); @@ -1680,13 +1705,6 @@ model_->ShowError(error_type); } -bool TranslateBubbleView::TabUiIsEquivalentState( - TranslateBubbleModel::ViewState view_state) { - return view_state == TranslateBubbleModel::VIEW_STATE_BEFORE_TRANSLATE || - view_state == TranslateBubbleModel::VIEW_STATE_TRANSLATING || - view_state == TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE; -} - void TranslateBubbleView::UpdateAdvancedView() { DCHECK(advanced_done_button_); advanced_done_button_->SetText(
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.h b/chrome/browser/ui/views/translate/translate_bubble_view.h index 0cc9092..91f45c1 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view.h +++ b/chrome/browser/ui/views/translate/translate_bubble_view.h
@@ -200,6 +200,8 @@ AlwaysTranslateLanguageMenuItem); FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, TabUiAlwaysTranslateLanguageMenuItem); + FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, + TabUiTabSelectedAfterTranslation); FRIEND_TEST_ALL_PREFIXES(TranslateLanguageBrowserTest, TranslateAndRevert); FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewBrowserTest, CheckNeverTranslateThisSiteBlacklist); @@ -304,6 +306,9 @@ // Switches the view type. void SwitchView(TranslateBubbleModel::ViewState view_state); + // SwitchView handler for TAB UI since TAB UI has the same view throughout. + void SwitchTabForViewState(TranslateBubbleModel::ViewState view_state); + // Switches to the error view. void SwitchToErrorView(translate::TranslateErrors::Type error_type); @@ -315,9 +320,6 @@ void ShowOriginal(); void ConfirmAdvancedOptions(); - // Return true if the current state is in advanced state for TAB UI. - bool TabUiIsEquivalentState(TranslateBubbleModel::ViewState view_state); - // Handles the reset button in advanced view under Tab UI. void ResetLanguage();
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc b/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc index 87a190cc..018f5bd 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc
@@ -707,4 +707,20 @@ TriggerOptionsMenuTab(); EXPECT_FALSE(bubble_->tab_options_menu_model_->IsItemCheckedAt(index)); -} \ No newline at end of file +} + +TEST_F(TranslateBubbleViewTest, TabUiTabSelectedAfterTranslation) { + scoped_feature_list_.InitAndEnableFeatureWithParameters( + language::kUseButtonTranslateBubbleUi, + {{language::kTranslateUIBubbleKey, + language::kTranslateUIBubbleTabValue}}); + + CreateAndShowBubble(); + EXPECT_EQ(bubble_->tabbed_pane_->GetSelectedTabIndex(), + static_cast<size_t>(0)); + mock_model_->Translate(); + EXPECT_TRUE(mock_model_->translate_called_); + bubble_->SwitchView(TranslateBubbleModel::VIEW_STATE_AFTER_TRANSLATE); + EXPECT_EQ(bubble_->tabbed_pane_->GetSelectedTabIndex(), + static_cast<size_t>(1)); +}
diff --git a/chrome/browser/ui/webui/chromeos/account_manager_welcome_dialog.cc b/chrome/browser/ui/webui/chromeos/account_manager_welcome_dialog.cc index 4dcc6ff..ae19e2b9 100644 --- a/chrome/browser/ui/webui/chromeos/account_manager_welcome_dialog.cc +++ b/chrome/browser/ui/webui/chromeos/account_manager_welcome_dialog.cc
@@ -14,6 +14,7 @@ #include "chrome/common/webui_url_constants.h" #include "components/prefs/pref_service.h" #include "ui/aura/window.h" +#include "ui/views/widget/widget.h" #include "ui/wm/core/shadow_types.h" #include "url/gurl.h" @@ -60,12 +61,12 @@ // Will be deleted by |SystemWebDialogDelegate::OnDialogClosed|. g_dialog = new AccountManagerWelcomeDialog(); g_dialog->ShowSystemDialog(); - return true; } void AccountManagerWelcomeDialog::AdjustWidgetInitParams( views::Widget::InitParams* params) { + params->keep_on_top = false; params->type = views::Widget::InitParams::Type::TYPE_WINDOW_FRAMELESS; params->shadow_type = views::Widget::InitParams::ShadowType::SHADOW_TYPE_DROP; params->shadow_elevation = wm::kShadowElevationActiveWindow;
diff --git a/chrome/browser/ui/webui/chromeos/account_migration_welcome_dialog.cc b/chrome/browser/ui/webui/chromeos/account_migration_welcome_dialog.cc index a165ac6..51ff02f 100644 --- a/chrome/browser/ui/webui/chromeos/account_migration_welcome_dialog.cc +++ b/chrome/browser/ui/webui/chromeos/account_migration_welcome_dialog.cc
@@ -17,6 +17,7 @@ #include "components/prefs/pref_service.h" #include "net/base/url_util.h" #include "ui/aura/window.h" +#include "ui/views/widget/widget.h" #include "ui/wm/core/shadow_types.h" namespace chromeos { @@ -62,6 +63,7 @@ void AccountMigrationWelcomeDialog::AdjustWidgetInitParams( views::Widget::InitParams* params) { + params->keep_on_top = false; params->type = views::Widget::InitParams::Type::TYPE_WINDOW_FRAMELESS; params->shadow_type = views::Widget::InitParams::ShadowType::SHADOW_TYPE_DROP; params->shadow_elevation = wm::kShadowElevationActiveWindow;
diff --git a/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc b/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc index 7a246fc..d1acb913 100644 --- a/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc +++ b/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc
@@ -31,10 +31,10 @@ add_supervision::mojom::AddSupervisionHandlerRequest request, content::WebUI* web_ui, Delegate* delegate) - : binding_(this, std::move(request)), - web_ui_(web_ui), + : web_ui_(web_ui), identity_manager_( IdentityManagerFactory::GetForProfile(Profile::FromWebUI(web_ui))), + binding_(this, std::move(request)), delegate_(delegate) {} AddSupervisionHandler::~AddSupervisionHandler() = default;
diff --git a/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.h b/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.h index cd7c3dec..b085b43 100644 --- a/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.h +++ b/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.h
@@ -56,8 +56,6 @@ GoogleServiceAuthError error, identity::AccessTokenInfo access_token_info); - mojo::Binding<add_supervision::mojom::AddSupervisionHandler> binding_; - // The AddSupervisionUI that this AddSupervisionHandler belongs to. content::WebUI* web_ui_; @@ -65,6 +63,8 @@ identity::IdentityManager* identity_manager_; std::unique_ptr<identity::AccessTokenFetcher> oauth2_access_token_fetcher_; + mojo::Binding<add_supervision::mojom::AddSupervisionHandler> binding_; + Delegate* delegate_; base::WeakPtrFactory<AddSupervisionHandler> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index 67ce027..3fa20360 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -244,8 +244,7 @@ } bool ExtractSamlPasswordAttributesEnabled() { - return ProfileHelper::Get()->GetSigninProfile()->GetPrefs()->GetBoolean( - prefs::kSamlInSessionPasswordChangeEnabled); + return base::FeatureList::IsEnabled(features::kInSessionPasswordChange); } } // namespace
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc index 5c60c661..2becb485 100644 --- a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc +++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc
@@ -32,6 +32,7 @@ const char kNoScriptPreviewsHtmlId[] = "noscript-preview-status"; const char kResourceLoadingHintsHtmlId[] = "resource-loading-hints-status"; const char kOfflinePreviewsHtmlId[] = "offline-preview-status"; +const char kDeferAllScriptPreviewsHtmlId[] = "defer-all-script-preview-status"; // Descriptions for previews. const char kPreviewsAllowedDescription[] = "Previews Allowed"; @@ -39,6 +40,7 @@ "Lite Page Redirect / Server Previews"; const char kNoScriptDescription[] = "NoScript Previews"; const char kResourceLoadingHintsDescription[] = "ResourceLoadingHints Previews"; +const char kDeferAllScriptPreviewsDescription[] = "DeferAllScript Previews"; const char kOfflineDesciption[] = "Offline Previews"; // Flag feature name. @@ -46,6 +48,7 @@ const char kLitePageRedirectFeatureName[] = "LitePageServerPreviews"; const char kNoScriptFeatureName[] = "NoScriptPreviews"; const char kResourceLoadingHintsFeatureName[] = "ResourceLoadingHints"; +const char kDeferAllScriptFeatureName[] = "DeferAllScript"; #if defined(OS_ANDROID) const char kOfflinePageFeatureName[] = "OfflinePreviews"; #endif // OS_ANDROID @@ -56,6 +59,7 @@ const char kOfflinePageFlagHtmlId[] = "offline-page-flag"; const char kLitePageRedirectFlagHtmlId[] = "lite-page-redirect-flag"; const char kResourceLoadingHintsFlagHtmlId[] = "resource-loading-hints-flag"; +const char kDeferAllScriptFlagHtmlId[] = "defer-all-script-flag"; const char kNoScriptFlagHtmlId[] = "noscript-flag"; const char kEctFlagHtmlId[] = "ect-flag"; const char kIgnorePreviewsBlacklistFlagHtmlId[] = "ignore-previews-blacklist"; @@ -70,6 +74,8 @@ "chrome://flags/#enable-lite-page-server-previews"; const char kResourceLoadingHintsFlagLink[] = "chrome://flags/#enable-resource-loading-hints"; +const char kDeferAllScriptFlagLink[] = + "chrome://flags/#enable-defer-all-script"; const char kNoScriptFlagLink[] = "chrome://flags/#enable-noscript-previews"; const char kEctFlagLink[] = "chrome://flags/#force-effective-connection-type"; const char kIgnorePreviewsBlacklistLink[] = @@ -241,6 +247,14 @@ resource_loading_hints_status->htmlId = kResourceLoadingHintsHtmlId; statuses.push_back(std::move(resource_loading_hints_status)); + auto defer_all_script_preview_status = mojom::PreviewsStatus::New(); + defer_all_script_preview_status->description = + kDeferAllScriptPreviewsDescription; + defer_all_script_preview_status->enabled = + previews::params::IsDeferAllScriptPreviewsEnabled(); + defer_all_script_preview_status->htmlId = kDeferAllScriptPreviewsHtmlId; + statuses.push_back(std::move(defer_all_script_preview_status)); + auto noscript_status = mojom::PreviewsStatus::New(); noscript_status->description = kNoScriptDescription; noscript_status->enabled = previews::params::IsNoScriptPreviewsEnabled(); @@ -294,6 +308,15 @@ resource_loading_hints_status->htmlId = kResourceLoadingHintsFlagHtmlId; flags.push_back(std::move(resource_loading_hints_status)); + auto defer_all_script_status = mojom::PreviewsFlag::New(); + defer_all_script_status->description = + flag_descriptions::kEnableDeferAllScriptName; + defer_all_script_status->link = kDeferAllScriptFlagLink; + defer_all_script_status->value = + GetFeatureFlagStatus(kDeferAllScriptFeatureName); + defer_all_script_status->htmlId = kDeferAllScriptFlagHtmlId; + flags.push_back(std::move(defer_all_script_status)); + auto noscript_status = mojom::PreviewsFlag::New(); noscript_status->description = flag_descriptions::kEnableNoScriptPreviewsName; noscript_status->link = kNoScriptFlagLink;
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc index b594b454..3f8998a 100644 --- a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
@@ -54,6 +54,8 @@ constexpr char kOfflinePreviewsHtmlId[] = "offline-preview-status"; constexpr char kLitePageRedirectHtmlId[] = "lite-page-redirect-status"; constexpr char kResourceLoadingHintsHtmlId[] = "resource-loading-hints-status"; +constexpr char kDeferAllScriptPreviewsHtmlId[] = + "defer-all-script-preview-status"; constexpr char kNoScriptPreviewsHtmlId[] = "noscript-preview-status"; // Descriptions for previews. @@ -63,6 +65,7 @@ "Lite Page Redirect / Server Previews"; constexpr char kResourceLoadingHintsDescription[] = "ResourceLoadingHints Previews"; +constexpr char kDeferAllScriptPreviewsDescription[] = "DeferAllScript Previews"; constexpr char kNoScriptDescription[] = "NoScript Previews"; // The HTML DOM ID used in Javascript. @@ -70,6 +73,7 @@ constexpr char kLitePageRedirectFlagHtmlId[] = "lite-page-redirect-flag"; constexpr char kResourceLoadingHintsFlagHtmlId[] = "resource-loading-hints-flag"; +constexpr char kDeferAllScriptFlagHtmlId[] = "defer-all-script-flag"; constexpr char kNoScriptFlagHtmlId[] = "noscript-flag"; constexpr char kEctFlagHtmlId[] = "ect-flag"; constexpr char kIgnorePreviewsBlacklistFlagHtmlId[] = @@ -84,6 +88,8 @@ "chrome://flags/#enable-lite-page-server-previews"; constexpr char kResourceLoadingHintsFlagLink[] = "chrome://flags/#enable-resource-loading-hints"; +constexpr char kDeferAllScriptFlagLink[] = + "chrome://flags/#enable-defer-all-script"; constexpr char kNoScriptFlagLink[] = "chrome://flags/#enable-noscript-previews"; constexpr char kEctFlagLink[] = "chrome://flags/#force-effective-connection-type"; @@ -96,6 +102,7 @@ constexpr char kOfflinePageFeatureName[] = "OfflinePreviews"; constexpr char kLitePageRedirectFeatureName[] = "LitePageServerPreviews"; constexpr char kResourceLoadingHintsFeatureName[] = "ResourceLoadingHints"; +constexpr char kDeferAllScriptFeatureName[] = "DeferAllScriptPreviews"; constexpr char kNoScriptFeatureName[] = "NoScriptPreviews"; constexpr char kDefaultFlagValue[] = "Default"; @@ -325,7 +332,7 @@ page_handler_->GetPreviewsEnabled( base::BindOnce(&MockGetPreviewsEnabledCallback)); - constexpr size_t expected = 5; + constexpr size_t expected = 6; EXPECT_EQ(expected, passed_in_modes.size()); } @@ -464,11 +471,39 @@ EXPECT_TRUE(resource_loading_hints->second->enabled); } +TEST_F(InterventionsInternalsPageHandlerTest, DeferAllScriptPreviewsDisabled) { + // Init with kDeferAllScriptPreviews disabled. + scoped_feature_list_->InitWithFeatures( + {}, {previews::features::kDeferAllScriptPreviews}); + + page_handler_->GetPreviewsEnabled( + base::BindOnce(&MockGetPreviewsEnabledCallback)); + auto defer_all_script = passed_in_modes.find(kDeferAllScriptPreviewsHtmlId); + ASSERT_NE(passed_in_modes.end(), defer_all_script); + EXPECT_EQ(kDeferAllScriptPreviewsDescription, + defer_all_script->second->description); + EXPECT_FALSE(defer_all_script->second->enabled); +} + +TEST_F(InterventionsInternalsPageHandlerTest, DeferAllScriptPreviewsEnabled) { + // Init with kDeferAllScriptPreviews enabled. + scoped_feature_list_->InitWithFeatures( + {previews::features::kDeferAllScriptPreviews}, {}); + + page_handler_->GetPreviewsEnabled( + base::BindOnce(&MockGetPreviewsEnabledCallback)); + auto defer_all_script = passed_in_modes.find(kDeferAllScriptPreviewsHtmlId); + ASSERT_NE(passed_in_modes.end(), defer_all_script); + EXPECT_EQ(kDeferAllScriptPreviewsDescription, + defer_all_script->second->description); + EXPECT_TRUE(defer_all_script->second->enabled); +} + TEST_F(InterventionsInternalsPageHandlerTest, GetFlagsCount) { page_handler_->GetPreviewsFlagsDetails( base::BindOnce(&MockGetPreviewsFlagsCallback)); - constexpr size_t expected = 8; + constexpr size_t expected = 9; EXPECT_EQ(expected, passed_in_flags.size()); } @@ -663,6 +698,53 @@ } TEST_F(InterventionsInternalsPageHandlerTest, + GetFlagsDeferAllScriptDefaultValue) { + page_handler_->GetPreviewsFlagsDetails( + base::BindOnce(&MockGetPreviewsFlagsCallback)); + auto defer_all_script_flag = passed_in_flags.find(kDeferAllScriptFlagHtmlId); + + ASSERT_NE(passed_in_flags.end(), defer_all_script_flag); + EXPECT_EQ(flag_descriptions::kEnableDeferAllScriptName, + defer_all_script_flag->second->description); + EXPECT_EQ(kDefaultFlagValue, defer_all_script_flag->second->value); + EXPECT_EQ(kDeferAllScriptFlagLink, defer_all_script_flag->second->link); +} + +TEST_F(InterventionsInternalsPageHandlerTest, GetFlagsDeferAllScriptEnabled) { + base::test::ScopedCommandLine scoped_command_line; + base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine(); + command_line->AppendSwitchASCII(switches::kEnableFeatures, + kDeferAllScriptFeatureName); + + page_handler_->GetPreviewsFlagsDetails( + base::BindOnce(&MockGetPreviewsFlagsCallback)); + auto defer_all_script_flag = passed_in_flags.find(kDeferAllScriptFlagHtmlId); + + ASSERT_NE(passed_in_flags.end(), defer_all_script_flag); + EXPECT_EQ(flag_descriptions::kEnableDeferAllScriptName, + defer_all_script_flag->second->description); + EXPECT_EQ(kEnabledFlagValue, defer_all_script_flag->second->value); + EXPECT_EQ(kDeferAllScriptFlagLink, defer_all_script_flag->second->link); +} + +TEST_F(InterventionsInternalsPageHandlerTest, GetFlagsDeferAllScriptDisabled) { + base::test::ScopedCommandLine scoped_command_line; + base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine(); + command_line->AppendSwitchASCII(switches::kDisableFeatures, + kDeferAllScriptFeatureName); + + page_handler_->GetPreviewsFlagsDetails( + base::BindOnce(&MockGetPreviewsFlagsCallback)); + auto defer_all_script_flag = passed_in_flags.find(kDeferAllScriptFlagHtmlId); + + ASSERT_NE(passed_in_flags.end(), defer_all_script_flag); + EXPECT_EQ(flag_descriptions::kEnableDeferAllScriptName, + defer_all_script_flag->second->description); + EXPECT_EQ(kDisabledFlagValue, defer_all_script_flag->second->value); + EXPECT_EQ(kDeferAllScriptFlagLink, defer_all_script_flag->second->link); +} + +TEST_F(InterventionsInternalsPageHandlerTest, GetFlagsLitePageRedirectDefaultValue) { page_handler_->GetPreviewsFlagsDetails( base::BindOnce(&MockGetPreviewsFlagsCallback));
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index 41ceadb..7f2e1ff 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1037,48 +1037,53 @@ html_source->AddString("naturalScrollLearnMoreLink", GetHelpUrlWithBoard(chrome::kNaturalScrollHelpURL)); } -#endif -void AddDownloadsStrings(content::WebUIDataSource* html_source) { +void AddFilesStrings(content::WebUIDataSource* html_source) { static constexpr LocalizedString kLocalizedStrings[] = { - {"downloadsPageTitle", IDS_SETTINGS_DOWNLOADS}, - {"downloadLocation", IDS_SETTINGS_DOWNLOAD_LOCATION}, - {"changeDownloadLocation", IDS_SETTINGS_CHANGE_DOWNLOAD_LOCATION}, - {"promptForDownload", IDS_SETTINGS_PROMPT_FOR_DOWNLOAD}, - {"disconnectGoogleDriveAccount", IDS_SETTINGS_DISCONNECT_GOOGLE_DRIVE}, - {"openFileTypesAutomatically", IDS_SETTINGS_OPEN_FILE_TYPES_AUTOMATICALLY}, -#if defined(OS_CHROMEOS) - {"smbSharesTitle", IDS_SETTINGS_DOWNLOADS_SMB_SHARES}, - {"smbSharesLearnMoreLabel", - IDS_SETTINGS_DOWNLOADS_SMB_SHARES_LEARN_MORE_LABEL}, - {"addSmbShare", IDS_SETTINGS_DOWNLOADS_SMB_SHARES_ADD_SHARE}, - {"smbShareAddedSuccessfulMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_SUCCESS_MESSAGE}, - {"smbShareAddedErrorMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_ERROR_MESSAGE}, - {"smbShareAddedAuthFailedMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_AUTH_FAILED_MESSAGE}, - {"smbShareAddedNotFoundMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_NOT_FOUND_MESSAGE}, - {"smbShareAddedUnsupportedDeviceMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_UNSUPPORTED_DEVICE_MESSAGE}, - {"smbShareAddedMountExistsMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_EXISTS_MESSAGE}, - {"smbShareAddedInvalidURLMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_INVALID_URL_MESSAGE}, - {"smbShareAddedInvalidSSOURLMessage", - IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_INVALID_SSO_URL_MESSAGE}, -#endif + {"filesPageTitle", IDS_OS_SETTINGS_FILES}, + {"smbSharesTitle", IDS_SETTINGS_DOWNLOADS_SMB_SHARES}, + {"smbSharesLearnMoreLabel", + IDS_SETTINGS_DOWNLOADS_SMB_SHARES_LEARN_MORE_LABEL}, + {"addSmbShare", IDS_SETTINGS_DOWNLOADS_SMB_SHARES_ADD_SHARE}, + {"smbShareAddedSuccessfulMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_SUCCESS_MESSAGE}, + {"smbShareAddedErrorMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_ERROR_MESSAGE}, + {"smbShareAddedAuthFailedMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_AUTH_FAILED_MESSAGE}, + {"smbShareAddedNotFoundMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_NOT_FOUND_MESSAGE}, + {"smbShareAddedUnsupportedDeviceMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_UNSUPPORTED_DEVICE_MESSAGE}, + {"smbShareAddedMountExistsMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_EXISTS_MESSAGE}, + {"smbShareAddedInvalidURLMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_INVALID_URL_MESSAGE}, + {"smbShareAddedInvalidSSOURLMessage", + IDS_SETTINGS_DOWNLOADS_SHARE_ADDED_MOUNT_INVALID_SSO_URL_MESSAGE}, }; AddLocalizedStringsBulk(html_source, kLocalizedStrings, base::size(kLocalizedStrings)); -#if defined(OS_CHROMEOS) chromeos::smb_dialog::AddLocalizedStrings(html_source); html_source->AddString("smbSharesLearnMoreURL", GetHelpUrlWithBoard(chrome::kSmbSharesLearnMoreURL)); -#endif +} +#endif // defined(OS_CHROMEOS) + +void AddDownloadsStrings(content::WebUIDataSource* html_source) { + static constexpr LocalizedString kLocalizedStrings[] = { + {"downloadsPageTitle", IDS_SETTINGS_DOWNLOADS}, + {"downloadLocation", IDS_SETTINGS_DOWNLOAD_LOCATION}, + {"changeDownloadLocation", IDS_SETTINGS_CHANGE_DOWNLOAD_LOCATION}, + {"promptForDownload", IDS_SETTINGS_PROMPT_FOR_DOWNLOAD}, + {"disconnectGoogleDriveAccount", IDS_SETTINGS_DISCONNECT_GOOGLE_DRIVE}, + {"openFileTypesAutomatically", + IDS_SETTINGS_OPEN_FILE_TYPES_AUTOMATICALLY}, + }; + AddLocalizedStringsBulk(html_source, kLocalizedStrings, + base::size(kLocalizedStrings)); } #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) @@ -3221,6 +3226,7 @@ AddDateTimeStrings(html_source); AddDeviceStrings(html_source); AddEasyUnlockStrings(html_source); + AddFilesStrings(html_source); AddInternetStrings(html_source); AddMultideviceStrings(html_source); AddParentalControlStrings(html_source);
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc index aaab6f0..856ad1a2 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
@@ -16,6 +16,7 @@ #include "ui/aura/window.h" #include "ui/display/display.h" #include "ui/display/screen.h" +#include "ui/views/widget/widget.h" #include "url/gurl.h" namespace chromeos { @@ -46,6 +47,11 @@ dialog->ShowSystemDialog(); } +void InlineLoginHandlerDialogChromeOS::AdjustWidgetInitParams( + views::Widget::InitParams* params) { + params->keep_on_top = false; +} + gfx::Size InlineLoginHandlerDialogChromeOS::GetMaximumDialogSize() { gfx::Size size; GetDialogSize(&size);
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h index 703e4a2..5a5e94f 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h +++ b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h
@@ -28,6 +28,9 @@ // account re-authentication. static void Show(const std::string& email = std::string()); + // ui::SystemWebDialogDelegate overrides. + void AdjustWidgetInitParams(views::Widget::InitParams* params) override; + // web_modal::WebContentsModalDialogHost overrides. gfx::Size GetMaximumDialogSize() override; gfx::NativeView GetHostView() const override;
diff --git a/chrome/browser/ui/webui/webapks_handler.cc b/chrome/browser/ui/webui/webapks_handler.cc index 73e48ff..bd24b8b 100644 --- a/chrome/browser/ui/webui/webapks_handler.cc +++ b/chrome/browser/ui/webui/webapks_handler.cc
@@ -4,7 +4,9 @@ #include "chrome/browser/ui/webui/webapks_handler.h" +#include <memory> #include <string> +#include <vector> #include "base/bind.h" #include "base/callback_forward.h" @@ -25,6 +27,10 @@ "requestWebApksInfo", base::BindRepeating(&WebApksHandler::HandleRequestWebApksInfo, base::Unretained(this))); + web_ui()->RegisterMessageCallback( + "requestWebApkUpdate", + base::BindRepeating(&WebApksHandler::HandleRequestWebApkUpdate, + base::Unretained(this))); } void WebApksHandler::HandleRequestWebApksInfo(const base::ListValue* args) { @@ -33,13 +39,21 @@ &WebApksHandler::OnWebApkInfoRetrieved, weak_ptr_factory_.GetWeakPtr())); } +void WebApksHandler::HandleRequestWebApkUpdate(const base::ListValue* args) { + AllowJavascript(); + for (const auto& val : args->GetList()) { + if (val.is_string()) + ShortcutHelper::SetForceWebApkUpdate(val.GetString()); + } +} + void WebApksHandler::OnWebApkInfoRetrieved( const std::vector<WebApkInfo>& webapks_list) { if (!IsJavascriptAllowed()) return; base::ListValue list; for (const auto& webapk_info : webapks_list) { - std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); + auto result = std::make_unique<base::DictionaryValue>(); result->SetString("name", webapk_info.name); result->SetString("shortName", webapk_info.short_name); result->SetString("packageName", webapk_info.package_name); @@ -61,6 +75,7 @@ result->SetDouble("lastUpdateCheckTimeMs", webapk_info.last_update_check_time.ToJsTime()); result->SetBoolean("relaxUpdates", webapk_info.relax_updates); + result->SetString("updateStatus", webapk_info.update_status); list.Append(std::move(result)); }
diff --git a/chrome/browser/ui/webui/webapks_handler.h b/chrome/browser/ui/webui/webapks_handler.h index 7d051ee8..1ecda6f 100644 --- a/chrome/browser/ui/webui/webapks_handler.h +++ b/chrome/browser/ui/webui/webapks_handler.h
@@ -28,7 +28,12 @@ // Handler for the "requestWebApksInfo" message. This requests // information for the installed WebAPKs and returns it to JS using // OnWebApkInfoReceived(). - virtual void HandleRequestWebApksInfo(const base::ListValue* args); + void HandleRequestWebApksInfo(const base::ListValue* args); + + // Handler for the "requestWebApkUpdate" message. This sets the + // update flag for a set of WebAPKs. |args| should contain the + // webapp IDs of the WebAPKs to update. + void HandleRequestWebApkUpdate(const base::ListValue* args); private: // Sends information for the installed WebAPKs to JS.
diff --git a/chrome/browser/vr/service/arcore_consent_prompt_interface.cc b/chrome/browser/vr/service/arcore_consent_prompt_interface.cc index b7ecf750..80ece6d9 100644 --- a/chrome/browser/vr/service/arcore_consent_prompt_interface.cc +++ b/chrome/browser/vr/service/arcore_consent_prompt_interface.cc
@@ -7,17 +7,17 @@ namespace vr { namespace { -ArcoreConsentPromptInterface* g_arcore_consent_prompt = nullptr; +ArCoreConsentPromptInterface* g_arcore_consent_prompt = nullptr; } // static -void ArcoreConsentPromptInterface::SetInstance( - ArcoreConsentPromptInterface* instance) { +void ArCoreConsentPromptInterface::SetInstance( + ArCoreConsentPromptInterface* instance) { g_arcore_consent_prompt = instance; } // static -ArcoreConsentPromptInterface* ArcoreConsentPromptInterface::GetInstance() { +ArCoreConsentPromptInterface* ArCoreConsentPromptInterface::GetInstance() { return g_arcore_consent_prompt; }
diff --git a/chrome/browser/vr/service/arcore_consent_prompt_interface.h b/chrome/browser/vr/service/arcore_consent_prompt_interface.h index 442c908..44249ecf 100644 --- a/chrome/browser/vr/service/arcore_consent_prompt_interface.h +++ b/chrome/browser/vr/service/arcore_consent_prompt_interface.h
@@ -12,10 +12,10 @@ // TODO(crbug.com/968233): Unify consent flow. // This class solves layering problem until the above bug gets fixed. -class VR_EXPORT ArcoreConsentPromptInterface { +class VR_EXPORT ArCoreConsentPromptInterface { public: - static void SetInstance(ArcoreConsentPromptInterface*); - static ArcoreConsentPromptInterface* GetInstance(); + static void SetInstance(ArCoreConsentPromptInterface*); + static ArCoreConsentPromptInterface* GetInstance(); virtual void ShowConsentPrompt( int render_process_id,
diff --git a/chrome/browser/vr/service/xr_device_impl.cc b/chrome/browser/vr/service/xr_device_impl.cc index db3b47b..097f1ed 100644 --- a/chrome/browser/vr/service/xr_device_impl.cc +++ b/chrome/browser/vr/service/xr_device_impl.cc
@@ -211,7 +211,7 @@ if (IsXrDeviceConsentPromptDisabledForTesting()) { DoRequestSession(std::move(options), std::move(callback)); } else { - ArcoreConsentPromptInterface::GetInstance()->ShowConsentPrompt( + ArCoreConsentPromptInterface::GetInstance()->ShowConsentPrompt( render_frame_host_->GetProcess()->GetID(), render_frame_host_->GetRoutingID(), base::BindOnce(&XRDeviceImpl::OnConsentResult,
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index bde87c7..a33daf3 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -368,6 +368,19 @@ "IncompatibleApplicationsWarning", base::FEATURE_ENABLED_BY_DEFAULT}; #endif +#if defined(OS_CHROMEOS) +// Enables scraping of password-expiry information during SAML login flow, which +// can lead to an in-session flow for changing SAML password if it has expired. +// This is safe to enable by default since it does not cause the password-expiry +// information to be stored, or any user-visible change - in order for anything +// to happen, the domain administrator has to intentionally send this extra +// info in the SAML response, and enable the InSessionPasswordChange policy. +// So, this feature is just for disabling the scraping code if it causes +// any unforeseen issues. +const base::Feature kInSessionPasswordChange{"InSessionPasswordChange", + base::FEATURE_ENABLED_BY_DEFAULT}; +#endif // defined(OS_CHROMEOS) + #if defined(OS_ANDROID) // Enables or disables the installable ambient badge infobar. const base::Feature kInstallableAmbientBadgeInfoBar{
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 97f35037..0e618cb 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -240,6 +240,11 @@ extern const base::Feature kIncompatibleApplicationsWarning; #endif +#if defined(OS_CHROMEOS) +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kInSessionPasswordChange; +#endif + #if defined(OS_ANDROID) COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kInstallableAmbientBadgeInfoBar;
diff --git a/chrome/installer/mac/signing/commands.py b/chrome/installer/mac/signing/commands.py index fa23202..c6ec720 100644 --- a/chrome/installer/mac/signing/commands.py +++ b/chrome/installer/mac/signing/commands.py
@@ -18,7 +18,34 @@ def copy_files(source, dest): assert source[-1] != '/' - subprocess.check_call(['rsync', '-a', '--delete', source, dest]) + subprocess.check_call( + ['rsync', '--archive', '--checksum', '--delete', source, dest]) + + +def copy_dir_overwrite_and_count_changes(source, dest, dry_run=False): + assert source[-1] != '/' + command = [ + 'rsync', '--archive', '--checksum', '--itemize-changes', '--delete', + source + '/', dest + ] + if dry_run: + command.append('--dry-run') + output = subprocess.check_output(command) + + # --itemize-changes will print a '.' in the first column if the item is not + # being updated, created, or deleted. This happens if only attributes + # change, such as a timestamp or permissions. Timestamp changes are + # uninteresting for the purposes of determining changed content, but + # permissions changes are not. Columns 6-8 are also checked so that files + # that have potentially interesting attributes (permissions, owner, or + # group) changing are counted, but column 5 for the timestamp is not + # considered. + changes = 0 + for line in output.split('\n'): + if line == '' or (line[0] == '.' and line[5:8] == '...'): + continue + changes += 1 + return changes def move_file(source, dest):
diff --git a/chrome/installer/mac/signing/commands_test.py b/chrome/installer/mac/signing/commands_test.py index ad57f02..1fe17396 100644 --- a/chrome/installer/mac/signing/commands_test.py +++ b/chrome/installer/mac/signing/commands_test.py
@@ -29,6 +29,110 @@ os.unlink(path) self.assertFalse(commands.file_exists(path)) + def test_copy_dir_overwrite_and_count_changes(self): + source_dir = os.path.join(self.tempdir, 'source') + os.mkdir(source_dir) + + os.mkdir(os.path.join(source_dir, 'dir')) + open(os.path.join(source_dir, 'dir', 'file'), 'w').close() + with open(os.path.join(source_dir, 'file'), 'w') as file: + file.write('contents') + + dest_dir = os.path.join(self.tempdir, 'dest') + + # Make sure that dry_run doesn't actually change anything by testing it + # a couple of times before doing any real work. + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=True), 4) + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=True), 4) + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=False), 4) + + # Now test that a subsequent copy of the same thing doesn't report any + # changes. + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=True), 0) + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=False), 0) + + self.assertTrue(os.path.isdir(dest_dir)) + self.assertTrue(os.path.isfile(os.path.join(dest_dir, 'file'))) + self.assertTrue(os.path.isdir(os.path.join(dest_dir, 'dir'))) + self.assertTrue(os.path.isfile(os.path.join(dest_dir, 'dir', 'file'))) + + self.assertEqual( + os.path.getsize(os.path.join(dest_dir, 'dir', 'file')), 0) + with open(os.path.join(dest_dir, 'file')) as file: + self.assertEqual(file.read(), 'contents') + + # No changes to source should result in no changes reported. + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=False), 0) + + # Changing a timestamp isn't reported, but the timestamp does get + # updated. + os.utime(os.path.join(source_dir, 'dir', 'file'), (0, 0)) + + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=False), 0) + + self.assertEqual( + os.path.getmtime(os.path.join(dest_dir, 'dir', 'file')), 0) + + # Changing a file is reported. + with open(os.path.join(source_dir, 'file'), 'w') as file: + file.write('new contents') + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=False), 1) + + with open(os.path.join(dest_dir, 'file')) as file: + self.assertEqual(file.read(), 'new contents') + + # Changing a file whose length doesn't change is reported. + with open(os.path.join(source_dir, 'file'), 'w') as file: + file.write('new_contents') + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=False), 1) + + with open(os.path.join(dest_dir, 'file')) as file: + self.assertEqual(file.read(), 'new_contents') + + # Creating directories and files are reported. + os.mkdir(os.path.join(source_dir, 'new_dir')) + open(os.path.join(source_dir, 'new_file'), 'w').close() + + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=False), 2) + + self.assertTrue(os.path.isfile(os.path.join(dest_dir, 'new_file'))) + self.assertTrue(os.path.isdir(os.path.join(dest_dir, 'new_dir'))) + + # Removing files and directories is also reported. + os.rmdir(os.path.join(source_dir, 'new_dir')) + os.unlink(os.path.join(source_dir, 'new_file')) + os.mkdir(os.path.join(source_dir, 'newer_dir')) + open(os.path.join(source_dir, 'newer_file'), 'w').close() + + self.assertEqual( + commands.copy_dir_overwrite_and_count_changes( + source_dir, dest_dir, dry_run=False), 4) + + self.assertFalse(os.path.exists(os.path.join(dest_dir, 'new_file'))) + self.assertFalse(os.path.exists(os.path.join(dest_dir, 'new_dir'))) + self.assertTrue(os.path.isfile(os.path.join(dest_dir, 'newer_file'))) + self.assertTrue(os.path.isdir(os.path.join(dest_dir, 'newer_dir'))) + def test_move_file(self): orig_path = os.path.join(self.tempdir, 'file.txt') new_path = os.path.join(self.tempdir, 'renamed.txt')
diff --git a/chrome/installer/mac/signing/modification_test.py b/chrome/installer/mac/signing/modification_test.py index 32f3b9b2..6e546d93b 100644 --- a/chrome/installer/mac/signing/modification_test.py +++ b/chrome/installer/mac/signing/modification_test.py
@@ -51,6 +51,34 @@ self.paths = model.Paths('$I', '$O', '$W') self.config = test_config.TestConfig() + def _is_framework_unchanged(self, plistlib, mocks): + # Determines whether any modifications were made within the framework + # according to calls to plistlib.writePlist or any of the mocked calls + # in |mocks|. This is done by examining the calls' arguments for a + # substring pointing into the framework. + + def _do_mock_calls_mention_framework(mock_calls): + for call in mock_calls: + for tup in call: + for arg in tup: + # Don't anchor this substring in a particular directory + # because it may appear in any of $I, $O, or $W. Don't + # anchor it with App Product.app either, because it may + # be renamed (to App Product Canary.app). + if 'Contents/Frameworks/Product Framework.framework' in arg: + return True + + return False + + if _do_mock_calls_mention_framework(plistlib.writePlist.mock_calls): + return False + + for mocked in mocks.values(): + if _do_mock_calls_mention_framework(mocked): + return False + + return True + def test_base_distribution(self, plistlib, **kwargs): dist = model.Distribution() config = dist.to_config(self.config) @@ -78,6 +106,8 @@ self.assertEqual(0, kwargs['move_file'].call_count) self.assertEqual(0, kwargs['write_file'].call_count) + self.assertTrue(self._is_framework_unchanged(plistlib, kwargs)) + def test_distribution_with_brand(self, plistlib, **kwargs): dist = model.Distribution(branding_code='MOO') config = dist.to_config(self.config) @@ -105,6 +135,8 @@ ]) self.assertEqual(0, kwargs['move_file'].call_count) + self.assertTrue(self._is_framework_unchanged(plistlib, kwargs)) + def test_distribution_with_channel(self, plistlib, **kwargs): dist = model.Distribution(channel='dev') config = dist.to_config(self.config) @@ -134,6 +166,8 @@ self.assertEqual(0, kwargs['move_file'].call_count) self.assertEqual(0, kwargs['write_file'].call_count) + self.assertTrue(self._is_framework_unchanged(plistlib, kwargs)) + def test_distribution_with_product_dirname(self, plistlib, **kwargs): dist = model.Distribution(product_dirname='Farmland/Cows') config = dist.to_config(self.config) @@ -162,6 +196,8 @@ self.assertEqual(0, kwargs['move_file'].call_count) self.assertEqual(0, kwargs['write_file'].call_count) + self.assertTrue(self._is_framework_unchanged(plistlib, kwargs)) + def test_distribution_with_creator_code(self, plistlib, **kwargs): dist = model.Distribution(creator_code='Mooo') config = dist.to_config(self.config) @@ -292,3 +328,5 @@ }, '$W/App Product Canary.app/Contents/Resources/test.signing.bundle_id.canary.manifest/Contents/Resources/test.signing.bundle_id.canary.manifest' ) ]) + + self.assertFalse(self._is_framework_unchanged(plistlib, kwargs))
diff --git a/chrome/installer/mac/signing/pipeline.py b/chrome/installer/mac/signing/pipeline.py index 8f8185b..f8318c3b 100644 --- a/chrome/installer/mac/signing/pipeline.py +++ b/chrome/installer/mac/signing/pipeline.py
@@ -14,7 +14,7 @@ from . import commands, model, modification, notarize, signing -def _customize_and_sign_chrome(paths, dist_config, dest_dir): +def _customize_and_sign_chrome(paths, dist_config, dest_dir, signed_frameworks): """Does channel customization and signing of a Chrome distribution. The resulting app bundle is moved into |dest_dir|. @@ -23,6 +23,14 @@ dist_config: A |config.CodeSignConfig| for the |model.Distribution|. dest_dir: The directory into which the product will be placed when the operations are completed. + signed_frameworks: A dict that will store paths and change counts of + already-signed inner frameworks keyed by bundle ID. Paths are used + to recycle already-signed frameworks instead of re-signing them. + Change counts are used to verify equivalence of frameworks when + recycling them. Callers can pass an empty dict on the first call, + and reuse the same dict for subsequent calls. This function will + produce and consume entries in the dict. If this sharing is + undesired, pass None instead of a dict. """ # Copy the app to sign into the work dir. commands.copy_files( @@ -32,7 +40,53 @@ modification.customize_distribution(paths, dist_config.distribution, dist_config) - signing.sign_chrome(paths, dist_config) + work_dir_framework_path = os.path.join(paths.work, + dist_config.framework_dir) + if signed_frameworks is not None and dist_config.base_bundle_id in signed_frameworks: + # If the inner framework has already been modified and signed for this + # bundle ID, recycle the existing signed copy without signing a new + # copy. This ensures that bit-for-bit identical input will result in + # bit-for-bit identical signatures not affected by differences in, for + # example, the signature's timestamp. All variants of a product sharing + # the same bundle ID are assumed to have bit-for-bit identical + # frameworks. + # + # This is significant because of how binary diff updates work. Binary + # diffs are built between two successive versions on the basis of their + # inner frameworks being bit-for-bit identical without regard to any + # customizations applied only to the outer app. In order for these to + # apply to all installations regardless of the presence or specific + # values of any app-level customizations, all inner frameworks for a + # single version and base bundle ID must always remain bit-for-bit + # identical, including their signatures. + (signed_framework_path, signed_framework_change_count + ) = signed_frameworks[dist_config.base_bundle_id] + actual_framework_change_count = commands.copy_dir_overwrite_and_count_changes( + os.path.join(dest_dir, signed_framework_path), + work_dir_framework_path, + dry_run=False) + + if actual_framework_change_count != signed_framework_change_count: + raise ValueError( + 'While customizing and signing {} ({}), actual_framework_change_count {} != signed_framework_change_count {}' + .format(dist_config.base_bundle_id, dist_config.dmg_basename, + actual_framework_change_count, + signed_framework_change_count)) + + signing.sign_chrome(paths, dist_config, sign_framework=False) + else: + unsigned_framework_path = os.path.join(paths.work, + 'modified_unsigned_framework') + commands.copy_dir_overwrite_and_count_changes( + work_dir_framework_path, unsigned_framework_path, dry_run=False) + signing.sign_chrome(paths, dist_config, sign_framework=True) + actual_framework_change_count = commands.copy_dir_overwrite_and_count_changes( + work_dir_framework_path, unsigned_framework_path, dry_run=True) + if signed_frameworks is not None: + dest_dir_framework_path = os.path.join(dest_dir, + dist_config.framework_dir) + signed_frameworks[dist_config.base_bundle_id] = ( + dest_dir_framework_path, actual_framework_change_count) app_path = os.path.join(paths.work, dist_config.app_dir) commands.make_dir(dest_dir) @@ -212,6 +266,7 @@ # First, sign all the distributions and optionally submit the # notarization requests. uuids_to_config = {} + signed_frameworks = {} for dist in config.distributions: with commands.WorkDirectory(orig_paths) as paths: dist_config = dist.to_config(config) @@ -224,7 +279,8 @@ dest_dir = notary_paths.work dest_dir = os.path.join(dest_dir, dist_config.dmg_basename) - _customize_and_sign_chrome(paths, dist_config, dest_dir) + _customize_and_sign_chrome(paths, dist_config, dest_dir, + signed_frameworks) # If the build products are to be notarized, ZIP the app bundle # and submit it for notarization.
diff --git a/chrome/installer/mac/signing/pipeline_test.py b/chrome/installer/mac/signing/pipeline_test.py index e4c831f..a0d65d8 100644 --- a/chrome/installer/mac/signing/pipeline_test.py +++ b/chrome/installer/mac/signing/pipeline_test.py
@@ -28,8 +28,9 @@ @mock.patch.multiple( 'signing.commands', **{ - m: mock.DEFAULT for m in ('move_file', 'copy_files', 'run_command', - 'make_dir', 'shutil') + m: mock.DEFAULT for m in ('move_file', 'copy_files', + 'copy_dir_overwrite_and_count_changes', + 'run_command', 'make_dir', 'shutil') }) @mock.patch.multiple( 'signing.signing', @@ -53,35 +54,138 @@ dist_config = dist.to_config(config) paths = self.paths.replace_work('$W') - pipeline._customize_and_sign_chrome(paths, dist_config, '$D') + pipeline._customize_and_sign_chrome(paths, dist_config, '$D', None) manager.assert_has_calls([ mock.call.copy_files('$I/App Product.app', '$W'), mock.call.customize_distribution(paths, dist, dist_config), - mock.call.sign_chrome(paths, dist_config), + mock.call.copy_dir_overwrite_and_count_changes( + '$W/App Product.app/Contents/Frameworks/Product Framework.framework', + '$W/modified_unsigned_framework', + dry_run=False), + mock.call.sign_chrome(paths, dist_config, sign_framework=True), + mock.call.copy_dir_overwrite_and_count_changes( + '$W/App Product.app/Contents/Frameworks/Product Framework.framework', + '$W/modified_unsigned_framework', + dry_run=True), mock.call.make_dir('$D'), mock.call.move_file('$W/App Product.app', '$D/App Product.app') ]) @mock.patch('signing.modification.customize_distribution') - def test_customize_and_sign_chrome_customize(self, customize, **kwargs): + def test_customize_and_sign_chrome_customize_different_product( + self, customize, **kwargs): manager = mock.Mock() for attr in kwargs: manager.attach_mock(kwargs[attr], attr) manager.attach_mock(customize, 'customize_distribution') dist = model.Distribution( - channel_customize=True, app_name_fragment='Canary') + channel_customize=True, + channel='canary', + app_name_fragment='Canary') config = test_config.TestConfig() dist_config = dist.to_config(config) paths = self.paths.replace_work('$W') - pipeline._customize_and_sign_chrome(paths, dist_config, '$D') + pipeline._customize_and_sign_chrome(paths, dist_config, '$D', None) manager.assert_has_calls([ mock.call.copy_files('$I/App Product.app', '$W'), mock.call.customize_distribution(paths, dist, dist_config), - mock.call.sign_chrome(paths, dist_config), + mock.call.copy_dir_overwrite_and_count_changes( + '$W/App Product Canary.app/Contents/Frameworks/Product Framework.framework', + '$W/modified_unsigned_framework', + dry_run=False), + mock.call.sign_chrome(paths, dist_config, sign_framework=True), + mock.call.copy_dir_overwrite_and_count_changes( + '$W/App Product Canary.app/Contents/Frameworks/Product Framework.framework', + '$W/modified_unsigned_framework', + dry_run=True), + mock.call.make_dir('$D'), + mock.call.move_file('$W/App Product Canary.app', + '$D/App Product Canary.app') + ]) + + @mock.patch('signing.modification.customize_distribution') + def test_customize_and_sign_chrome_customize_multiple_times( + self, customize, **kwargs): + kwargs['copy_dir_overwrite_and_count_changes'].return_value = 0 + + manager = mock.Mock() + for attr in kwargs: + manager.attach_mock(kwargs[attr], attr) + manager.attach_mock(customize, 'customize_distribution') + + config = test_config.TestConfig() + + base_dist = model.Distribution() + base_dist_config = base_dist.to_config(config) + paths = self.paths.replace_work('$W') + + signed_frameworks = {} + pipeline._customize_and_sign_chrome(paths, base_dist_config, '$D', + signed_frameworks) + + branded_dist = model.Distribution( + branding_code='c0de', dmg_name_fragment='Branded') + branded_dist_config = branded_dist.to_config(config) + paths = self.paths.replace_work('$W') + + pipeline._customize_and_sign_chrome(paths, branded_dist_config, '$D', + signed_frameworks) + + channel_dist = model.Distribution( + channel_customize=True, + channel='canary', + app_name_fragment='Canary') + channel_dist_config = channel_dist.to_config(config) + paths = self.paths.replace_work('$W') + + pipeline._customize_and_sign_chrome(paths, channel_dist_config, '$D', + signed_frameworks) + + manager.assert_has_calls([ + mock.call.copy_files('$I/App Product.app', '$W'), + mock.call.customize_distribution(paths, base_dist, + base_dist_config), + mock.call.copy_dir_overwrite_and_count_changes( + '$W/App Product.app/Contents/Frameworks/Product Framework.framework', + '$W/modified_unsigned_framework', + dry_run=False), + mock.call.sign_chrome(paths, base_dist_config, sign_framework=True), + mock.call.copy_dir_overwrite_and_count_changes( + '$W/App Product.app/Contents/Frameworks/Product Framework.framework', + '$W/modified_unsigned_framework', + dry_run=True), + mock.call.make_dir('$D'), + mock.call.move_file('$W/App Product.app', '$D/App Product.app'), + mock.call.copy_files('$I/App Product.app', '$W'), + mock.call.customize_distribution(paths, branded_dist, + branded_dist_config), + # TODO(https://crbug.com/964608): $D/$D is a relative path treatment + # bug. + mock.call.copy_dir_overwrite_and_count_changes( + '$D/$D/App Product.app/Contents/Frameworks/Product Framework.framework', + '$W/App Product.app/Contents/Frameworks/Product Framework.framework', + dry_run=False), + mock.call.sign_chrome( + paths, branded_dist_config, sign_framework=False), + mock.call.make_dir('$D'), + mock.call.move_file('$W/App Product.app', '$D/App Product.app'), + mock.call.copy_files('$I/App Product.app', '$W'), + mock.call.customize_distribution(paths, channel_dist, + channel_dist_config), + mock.call.copy_dir_overwrite_and_count_changes( + '$W/App Product Canary.app/Contents/Frameworks/Product Framework.framework', + '$W/modified_unsigned_framework', + dry_run=False), + mock.call.sign_chrome( + paths, channel_dist_config, sign_framework=True), + mock.call.copy_dir_overwrite_and_count_changes( + '$W/App Product Canary.app/Contents/Frameworks/Product Framework.framework', + '$W/modified_unsigned_framework', + dry_run=True), mock.call.make_dir('$D'), mock.call.move_file('$W/App Product Canary.app', '$D/App Product Canary.app') @@ -374,7 +478,7 @@ manager.assert_has_calls([ # First customize the distribution and sign it. mock.call._customize_and_sign_chrome( - mock.ANY, mock.ANY, '$W_1/AppProduct-99.0.9999.99'), + mock.ANY, mock.ANY, '$W_1/AppProduct-99.0.9999.99', mock.ANY), # Prepare the app for notarization. mock.call.run_command([ @@ -422,7 +526,7 @@ manager.assert_has_calls([ # First customize the distribution and sign it. mock.call._customize_and_sign_chrome( - mock.ANY, mock.ANY, '$W_1/AppProduct-99.0.9999.99'), + mock.ANY, mock.ANY, '$W_1/AppProduct-99.0.9999.99', mock.ANY), # Prepare the app for notarization. mock.call.run_command([ @@ -461,7 +565,7 @@ manager.assert_has_calls([ # First customize the distribution and sign it. mock.call._customize_and_sign_chrome( - mock.ANY, mock.ANY, '$W_1/AppProduct-99.0.9999.99'), + mock.ANY, mock.ANY, '$W_1/AppProduct-99.0.9999.99', mock.ANY), mock.call.shutil.rmtree('$W_2'), # Make the DMG. @@ -483,8 +587,8 @@ manager.assert_has_calls([ # First customize the distribution and sign it. - mock.call._customize_and_sign_chrome(mock.ANY, mock.ANY, - '$O/AppProduct-99.0.9999.99'), + mock.call._customize_and_sign_chrome( + mock.ANY, mock.ANY, '$O/AppProduct-99.0.9999.99', mock.ANY), mock.call.shutil.rmtree('$W_2'), mock.call.shutil.rmtree('$W_1'), @@ -522,10 +626,11 @@ manager.assert_has_calls([ mock.call._customize_and_sign_chrome( - mock.ANY, mock.ANY, '$W_1/AppProduct-99.0.9999.99'), + mock.ANY, mock.ANY, '$W_1/AppProduct-99.0.9999.99', mock.ANY), mock.call.shutil.rmtree('$W_2'), mock.call._customize_and_sign_chrome( - mock.ANY, mock.ANY, '$W_1/AppProduct-99.0.9999.99-ForCows'), + mock.ANY, mock.ANY, '$W_1/AppProduct-99.0.9999.99-ForCows', + mock.ANY), mock.call.shutil.rmtree('$W_3'), mock.call._package_and_sign_dmg( self.paths.replace_work('$W_1/AppProduct-99.0.9999.99'),
diff --git a/chrome/installer/mac/signing/signing.py b/chrome/installer/mac/signing/signing.py index b1673a02..de69f7ba 100644 --- a/chrome/installer/mac/signing/signing.py +++ b/chrome/installer/mac/signing/signing.py
@@ -85,8 +85,7 @@ '{}.helper.renderer'.format(uncustomized_bundle_id), # Do not use |full_hardened_runtime_options| because library # validation is incompatible with the JIT entitlement. - options=CodeSignOptions.RESTRICT + - CodeSignOptions.KILL + + options=CodeSignOptions.RESTRICT + CodeSignOptions.KILL + CodeSignOptions.HARDENED_RUNTIME, entitlements='helper-renderer-entitlements.plist', verify_options=VerifyOptions.DEEP), @@ -98,8 +97,7 @@ # Do not use |full_hardened_runtime_options| because library # validation is incompatible with the disable-library-validation # entitlement. - options=CodeSignOptions.RESTRICT + - CodeSignOptions.KILL + + options=CodeSignOptions.RESTRICT + CodeSignOptions.KILL + CodeSignOptions.HARDENED_RUNTIME, entitlements='helper-plugin-entitlements.plist', verify_options=VerifyOptions.DEEP), @@ -226,7 +224,7 @@ commands.run_command(['spctl', '--assess', '-vv', app_path]) -def sign_chrome(paths, config): +def sign_chrome(paths, config, sign_framework=False): """Code signs the Chrome application bundle and all of its internal nested code parts. @@ -234,6 +232,9 @@ paths: A |model.Paths| object. config: The |model.CodeSignConfig| object. The |app_product| binary and nested binaries must exist in |paths.work|. + sign_framework: True if the inner framework is to be signed in addition + to the outer application. False if only the outer application is to + be signed. """ parts = get_parts(config) @@ -247,18 +248,20 @@ _sanity_check_version_keys(paths, parts) - # To sign an .app bundle that contains nested code, the nested components - # themselves must be signed. Each of these components is signed below. Note - # that unless a framework has multiple versions (which is discouraged), - # signing the entire framework is equivalent to signing the Current version. - # https://developer.apple.com/library/content/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG13 - for name, part in parts.items(): - if name in ('app', 'framework'): - continue - sign_part(paths, config, part) + if sign_framework: + # To sign an .app bundle that contains nested code, the nested + # components themselves must be signed. Each of these components is + # signed below. Note that unless a framework has multiple versions + # (which is discouraged), signing the entire framework is equivalent to + # signing the Current version. + # https://developer.apple.com/library/content/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG13 + for name, part in parts.items(): + if name in ('app', 'framework'): + continue + sign_part(paths, config, part) - # Sign the framework bundle. - sign_part(paths, config, parts['framework']) + # Sign the framework bundle. + sign_part(paths, config, parts['framework']) provisioning_profile_basename = config.provisioning_profile_basename if provisioning_profile_basename:
diff --git a/chrome/installer/mac/signing/signing_test.py b/chrome/installer/mac/signing/signing_test.py index 5163b68..8555d3d 100644 --- a/chrome/installer/mac/signing/signing_test.py +++ b/chrome/installer/mac/signing/signing_test.py
@@ -57,7 +57,6 @@ self.assertEqual('test.signing.bundle_id.helper', all_parts['helper-app'].identifier) - def test_part_options(self): parts = signing.get_parts(test_config.TestConfig()) self.assertEqual( @@ -73,13 +72,11 @@ model.CodeSignOptions.HARDENED_RUNTIME), set(parts['helper-app'].options)) self.assertEqual( - set(model.CodeSignOptions.RESTRICT + - model.CodeSignOptions.KILL + + set(model.CodeSignOptions.RESTRICT + model.CodeSignOptions.KILL + model.CodeSignOptions.HARDENED_RUNTIME), set(parts['helper-renderer-app'].options)) self.assertEqual( - set(model.CodeSignOptions.RESTRICT + - model.CodeSignOptions.KILL + + set(model.CodeSignOptions.RESTRICT + model.CodeSignOptions.KILL + model.CodeSignOptions.HARDENED_RUNTIME), set(parts['helper-plugin-app'].options)) self.assertEqual( @@ -266,7 +263,7 @@ dist = model.Distribution() config = dist.to_config(test_config.TestConfig()) - signing.sign_chrome(self.paths, config) + signing.sign_chrome(self.paths, config, sign_framework=True) # No files should be moved. self.assertEqual(0, kwargs['move_file'].call_count) @@ -314,7 +311,7 @@ config = dist.to_config(Config()) - signing.sign_chrome(self.paths, config) + signing.sign_chrome(self.paths, config, sign_framework=True) self.assertEqual(kwargs['run_command'].mock_calls, [ mock.call.run_command([ @@ -334,7 +331,7 @@ return None config = dist.to_config(Config()) - signing.sign_chrome(self.paths, config) + signing.sign_chrome(self.paths, config, sign_framework=True) self.assertEqual(0, kwargs['copy_files'].call_count) @@ -355,8 +352,9 @@ # If the file is missing, signing should fail since TestConfig has # no optional parts. config = model.Distribution().to_config(test_config.TestConfig()) - self.assertRaises(FileNotFoundError, - lambda: signing.sign_chrome(self.paths, config)) + self.assertRaises( + FileNotFoundError, + lambda: signing.sign_chrome(self.paths, config, sign_framework=True)) class Config(test_config.TestConfig): @@ -366,14 +364,50 @@ # With the part marked as optional, it should succeed. config = model.Distribution().to_config(Config()) - signing.sign_chrome(self.paths, config) + signing.sign_chrome(self.paths, config, sign_framework=True) + + @mock.patch('signing.signing._sanity_check_version_keys') + def test_sign_chrome_no_framework(self, *args, **kwargs): + manager = mock.Mock() + for kwarg in kwargs: + manager.attach_mock(kwargs[kwarg], kwarg) + + dist = model.Distribution() + config = dist.to_config(test_config.TestConfig()) + + signing.sign_chrome(self.paths, config, sign_framework=False) + + # No files should be moved. + self.assertEqual(0, kwargs['move_file'].call_count) + + # Test that the provisioning profile is copied. + self.assertEqual(kwargs['copy_files'].mock_calls, [ + mock.call.copy_files( + '$I/Product Packaging/provisiontest.provisionprofile', + '$W/App Product.app/Contents/embedded.provisionprofile') + ]) + + # Ensure that only the app is signed. + signed_paths = [ + call[1][2].path for call in kwargs['sign_part'].mock_calls + ] + self.assertEqual(signed_paths, ['App Product.app']) + + self.assertEqual(kwargs['run_command'].mock_calls, [ + mock.call.run_command([ + 'codesign', '--display', '--requirements', '-', '--verbose=5', + '$W/App Product.app' + ]), + mock.call.run_command( + ['spctl', '--assess', '-vv', '$W/App Product.app']), + ]) @mock.patch( 'signing.commands.plistlib.readPlist', side_effect=_get_plist_read('99.0.9999.99')) def test_sanity_check_ok(self, read_plist, **kwargs): config = model.Distribution().to_config(test_config.TestConfig()) - signing.sign_chrome(self.paths, config) + signing.sign_chrome(self.paths, config, sign_framework=True) @mock.patch( 'signing.commands.plistlib.readPlist', @@ -381,4 +415,4 @@ def test_sanity_check_bad(self, read_plist, **kwargs): config = model.Distribution().to_config(test_config.TestConfig()) self.assertRaises(ValueError, - lambda: signing.sign_chrome(self.paths, config)) + lambda: signing.sign_chrome(self.paths, config, sign_framework=True))
diff --git a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/KeyNavigationUtil.java b/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/KeyNavigationUtil.java index be18b30..5fb8057 100644 --- a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/KeyNavigationUtil.java +++ b/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/KeyNavigationUtil.java
@@ -52,6 +52,18 @@ } /** + * Checks whether the given event is any of DPAD left or NUMPAD left. + * @param event Event to be checked. + * @return Whether the event should be processed as a navigation left. + */ + public static boolean isGoLeft(KeyEvent event) { + return isActionDown(event) + && (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT + || (!event.isNumLockOn() + && event.getKeyCode() == KeyEvent.KEYCODE_NUMPAD_4)); + } + + /** * Checks whether the given event is any of DPAD down, DPAD up, NUMPAD down or NUMPAD up. * @param event Event to be checked. * @return Whether the event should be processed as any of navigation up or navigation down.
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc index ddf4f1d..5a78397 100644 --- a/chrome/renderer/searchbox/searchbox_extension.cc +++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -539,9 +539,8 @@ "if (window.chrome &&" " window.chrome.embeddedSearch &&" " window.chrome.embeddedSearch.newTabPage &&" - " window.chrome.embeddedSearch.newTabPage.onlocalbackgroundselected &&" - " typeof " - "window.chrome.embeddedSearch.newTabPage.onlocalbackgroundselected ==" + " window.chrome.embeddedSearch.newTabPage.onthemechange &&" + " typeof window.chrome.embeddedSearch.newTabPage.onthemechange ==" " 'function') {" " " "window.chrome.embeddedSearch.newTabPage."
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index c50a31d..1f4a5551 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -108,8 +108,8 @@ "base/chrome_test_utils.h", "base/chrome_unit_test_suite.cc", "base/chrome_unit_test_suite.h", - "base/find_in_page_observer.cc", - "base/find_in_page_observer.h", + "base/find_result_waiter.cc", + "base/find_result_waiter.h", "base/process_inspector_win.cc", "base/process_inspector_win.h", "base/process_lineage_win.cc", @@ -2981,6 +2981,7 @@ "../browser/performance_manager/performance_manager_unittest.cc", "../browser/performance_manager/persistence/site_data/exponential_moving_average_unittest.cc", "../browser/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc", + "../browser/performance_manager/persistence/site_data/non_recording_site_data_cache_unittest.cc", "../browser/performance_manager/persistence/site_data/site_data_cache_factory_unittest.cc", "../browser/performance_manager/persistence/site_data/site_data_cache_impl_unittest.cc", "../browser/performance_manager/persistence/site_data/site_data_impl_unittest.cc",
diff --git a/chrome/test/base/find_in_page_observer.cc b/chrome/test/base/find_in_page_observer.cc deleted file mode 100644 index 4cfce7c5..0000000 --- a/chrome/test/base/find_in_page_observer.cc +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/test/base/find_in_page_observer.h" - -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/ui/find_bar/find_tab_helper.h" -#include "content/public/test/test_utils.h" - -namespace ui_test_utils { - -FindInPageNotificationObserver::FindInPageNotificationObserver( - content::WebContents* parent_tab) - : active_match_ordinal_(-1), - number_of_matches_(0), - current_find_request_id_(0), - seen_(false), - running_(false) { - FindTabHelper* find_tab_helper = - FindTabHelper::FromWebContents(parent_tab); - current_find_request_id_ = find_tab_helper->current_find_request_id(); - registrar_.Add(this, chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, - content::Source<content::WebContents>(parent_tab)); -} - -FindInPageNotificationObserver::~FindInPageNotificationObserver() {} - -void FindInPageNotificationObserver::Wait() { - if (seen_) - return; - running_ = true; - message_loop_runner_ = new content::MessageLoopRunner; - message_loop_runner_->Run(); -} - -void FindInPageNotificationObserver::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK_EQ(chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, type); - - content::Details<FindNotificationDetails> find_details(details); - if (find_details->request_id() != current_find_request_id_) - return; - - // We get multiple responses and one of those will contain the ordinal. - // This message comes to us before the final update is sent. - if (find_details->active_match_ordinal() > -1) { - active_match_ordinal_ = find_details->active_match_ordinal(); - selection_rect_ = find_details->selection_rect(); - } - if (find_details->final_update()) { - number_of_matches_ = find_details->number_of_matches(); - seen_ = true; - if (running_) { - running_ = false; - message_loop_runner_->Quit(); - } - } else { - DVLOG(1) << "Ignoring, since we only care about the final message"; - } -} - -} // namespace ui_test_utils -
diff --git a/chrome/test/base/find_in_page_observer.h b/chrome/test/base/find_in_page_observer.h deleted file mode 100644 index 5bff63a..0000000 --- a/chrome/test/base/find_in_page_observer.h +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_TEST_BASE_FIND_IN_PAGE_OBSERVER_H_ -#define CHROME_TEST_BASE_FIND_IN_PAGE_OBSERVER_H_ - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "ui/gfx/geometry/rect.h" - -namespace content { -class MessageLoopRunner; -class WebContents; -} - -namespace ui_test_utils { - -// FindInPageNotificationObserver allows blocking UI thread until find results -// are available. Typical usage: -// FindInPageWchar(); -// FindInPageNotificationObserver observer(tab); -// observer.Wait(); - -// Always construct FindInPageNotificationObserver AFTER initiating the search. -// It captures the current search ID in constructor and waits for it only. -class FindInPageNotificationObserver : public content::NotificationObserver { - public: - explicit FindInPageNotificationObserver(content::WebContents* parent_tab); - ~FindInPageNotificationObserver() override; - - void Wait(); - - int active_match_ordinal() const { return active_match_ordinal_; } - int number_of_matches() const { return number_of_matches_; } - gfx::Rect selection_rect() const { return selection_rect_; } - - private: - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - content::NotificationRegistrar registrar_; - // We will at some point (before final update) be notified of the ordinal and - // we need to preserve it so we can send it later. - int active_match_ordinal_; - int number_of_matches_; - gfx::Rect selection_rect_; - // The id of the current find request, obtained from WebContents. Allows us - // to monitor when the search completes. - int current_find_request_id_; - scoped_refptr<content::MessageLoopRunner> message_loop_runner_; - - bool seen_; // true after transition to expected state has been seen - bool running_; // indicates whether message loop is running - - DISALLOW_COPY_AND_ASSIGN(FindInPageNotificationObserver); -}; - -} // namespace ui_test_utils - -#endif // CHROME_TEST_BASE_FIND_IN_PAGE_OBSERVER_H_
diff --git a/chrome/test/base/find_result_waiter.cc b/chrome/test/base/find_result_waiter.cc new file mode 100644 index 0000000..50ebaa0 --- /dev/null +++ b/chrome/test/base/find_result_waiter.cc
@@ -0,0 +1,52 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/test/base/find_result_waiter.h" + +#include "base/run_loop.h" +#include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "content/public/test/test_utils.h" + +namespace ui_test_utils { + +FindResultWaiter::FindResultWaiter(content::WebContents* parent_tab) { + FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(parent_tab); + current_find_request_id_ = find_tab_helper->current_find_request_id(); + observer_.Add(find_tab_helper); +} + +FindResultWaiter::~FindResultWaiter() = default; + +void FindResultWaiter::Wait() { + if (seen_) + return; + run_loop_ = std::make_unique<base::RunLoop>(); + run_loop_->Run(); +} + +void FindResultWaiter::OnFindResultAvailable( + content::WebContents* web_contents) { + const FindNotificationDetails& find_details = + FindTabHelper::FromWebContents(web_contents)->find_result(); + + if (find_details.request_id() != current_find_request_id_) + return; + + // We get multiple responses and one of those will contain the ordinal. + // This message comes to us before the final update is sent. + if (find_details.active_match_ordinal() > -1) { + active_match_ordinal_ = find_details.active_match_ordinal(); + selection_rect_ = find_details.selection_rect(); + } + if (find_details.final_update()) { + number_of_matches_ = find_details.number_of_matches(); + seen_ = true; + if (run_loop_ && run_loop_->running()) + run_loop_->Quit(); + } else { + DVLOG(1) << "Ignoring, since we only care about the final message"; + } +} + +} // namespace ui_test_utils
diff --git a/chrome/test/base/find_result_waiter.h b/chrome/test/base/find_result_waiter.h new file mode 100644 index 0000000..b4d1231 --- /dev/null +++ b/chrome/test/base/find_result_waiter.h
@@ -0,0 +1,69 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_TEST_BASE_FIND_RESULT_WAITER_H_ +#define CHROME_TEST_BASE_FIND_RESULT_WAITER_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/scoped_observer.h" +#include "chrome/browser/ui/find_bar/find_result_observer.h" +#include "chrome/browser/ui/find_bar/find_tab_helper.h" +#include "ui/gfx/geometry/rect.h" + +namespace base { +class RunLoop; +} + +namespace content { +class WebContents; +} // namespace content + +namespace ui_test_utils { + +// FindResultWaiter allows blocking UI thread until find results are available. +// Typical usage: +// +// FindInPageWchar(); +// FindResultWaiter observer(tab); +// observer.Wait(); +// +// Always construct FindResultWaiter AFTER initiating the search. It captures +// the current search ID in the constructor and waits for it only. +class FindResultWaiter : public FindResultObserver { + public: + explicit FindResultWaiter(content::WebContents* parent_tab); + ~FindResultWaiter() override; + + void Wait(); + + int active_match_ordinal() const { return active_match_ordinal_; } + int number_of_matches() const { return number_of_matches_; } + gfx::Rect selection_rect() const { return selection_rect_; } + + private: + // FindResultObserver: + void OnFindResultAvailable(content::WebContents* web_contents) override; + + std::unique_ptr<base::RunLoop> run_loop_; + ScopedObserver<FindTabHelper, FindResultObserver> observer_{this}; + + // We will at some point (before final update) be notified of the ordinal and + // we need to preserve it so we can send it later. + int active_match_ordinal_ = -1; + int number_of_matches_ = 0; + gfx::Rect selection_rect_; + // The id of the current find request, obtained from WebContents. Allows us + // to monitor when the search completes. + int current_find_request_id_ = 0; + + bool seen_ = false; // true after transition to expected state has been seen + + DISALLOW_COPY_AND_ASSIGN(FindResultWaiter); +}; + +} // namespace ui_test_utils + +#endif // CHROME_TEST_BASE_FIND_RESULT_WAITER_H_
diff --git a/chrome/test/base/ui_test_utils.cc b/chrome/test/base/ui_test_utils.cc index b6b8ee0..210c3ce 100644 --- a/chrome/test/base/ui_test_utils.cc +++ b/chrome/test/base/ui_test_utils.cc
@@ -43,7 +43,7 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" -#include "chrome/test/base/find_in_page_observer.h" +#include "chrome/test/base/find_result_waiter.h" #include "components/app_modal/app_modal_dialog_queue.h" #include "components/app_modal/javascript_app_modal_dialog.h" #include "components/bookmarks/browser/bookmark_model.h" @@ -442,7 +442,7 @@ FindTabHelper* find_tab_helper = FindTabHelper::FromWebContents(tab); find_tab_helper->StartFinding(search_string, forward, match_case, true /* run_synchronously_for_testing */); - FindInPageNotificationObserver observer(tab); + FindResultWaiter observer(tab); observer.Wait(); if (ordinal) *ordinal = observer.active_match_ordinal();
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.cc b/chrome/test/chromedriver/chrome/chrome_impl.cc index 71d46c42..67b8fe6 100644 --- a/chrome/test/chromedriver/chrome/chrome_impl.cc +++ b/chrome/test/chromedriver/chrome/chrome_impl.cc
@@ -182,19 +182,10 @@ if (status.IsError()) return status; - if (window.state != "normal") { - // restore window to normal first to allow position change. - auto bounds = std::make_unique<base::DictionaryValue>(); - bounds->SetString("windowState", "normal"); - status = SetWindowBounds(window.id, std::move(bounds)); - if (status.IsError()) - return status; - } - auto bounds = std::make_unique<base::DictionaryValue>(); bounds->SetInteger("left", x); bounds->SetInteger("top", y); - return SetWindowBounds(window.id, std::move(bounds)); + return SetWindowBounds(&window, std::move(bounds)); } Status ChromeImpl::MaximizeWindow(const std::string& target_id) { @@ -206,19 +197,9 @@ if (window.state == "maximized") return Status(kOk); - if (window.state != "normal") { - // always restore window to normal first, since chrome ui doesn't allow - // maximizing a minimized or fullscreen window. - auto bounds = std::make_unique<base::DictionaryValue>(); - bounds->SetString("windowState", "normal"); - status = SetWindowBounds(window.id, std::move(bounds)); - if (status.IsError()) - return status; - } - auto bounds = std::make_unique<base::DictionaryValue>(); bounds->SetString("windowState", "maximized"); - return SetWindowBounds(window.id, std::move(bounds)); + return SetWindowBounds(&window, std::move(bounds)); } Status ChromeImpl::MinimizeWindow(const std::string& target_id) { @@ -230,18 +211,9 @@ if (window.state == "minimized") return Status(kOk); - if (window.state != "normal") { - // restore window to normal first - auto bounds = std::make_unique<base::DictionaryValue>(); - bounds->SetString("windowState", "normal"); - status = SetWindowBounds(window.id, std::move(bounds)); - if (status.IsError()) - return status; - } - auto bounds = std::make_unique<base::DictionaryValue>(); bounds->SetString("windowState", "minimized"); - return SetWindowBounds(window.id, std::move(bounds)); + return SetWindowBounds(&window, std::move(bounds)); } Status ChromeImpl::FullScreenWindow(const std::string& target_id) { @@ -253,17 +225,9 @@ if (window.state == "fullscreen") return Status(kOk); - if (window.state != "normal") { - auto bounds = std::make_unique<base::DictionaryValue>(); - bounds->SetString("windowState", "normal"); - status = SetWindowBounds(window.id, std::move(bounds)); - if (status.IsError()) - return status; - } - auto bounds = std::make_unique<base::DictionaryValue>(); bounds->SetString("windowState", "fullscreen"); - return SetWindowBounds(window.id, std::move(bounds)); + return SetWindowBounds(&window, std::move(bounds)); } Status ChromeImpl::SetWindowRect(const std::string& target_id, @@ -275,15 +239,6 @@ auto bounds = std::make_unique<base::DictionaryValue>(); - // fully exit fullscreen - if (window.state != "normal") { - auto bounds = std::make_unique<base::DictionaryValue>(); - bounds->SetString("windowState", "normal"); - status = SetWindowBounds(window.id, std::move(bounds)); - if (status.IsError()) - return status; - } - // window position int x = 0; int y = 0; @@ -300,7 +255,7 @@ bounds->SetInteger("height", height); } - return SetWindowBounds(window.id, std::move(bounds)); + return SetWindowBounds(&window, std::move(bounds)); } Status ChromeImpl::GetWindowSize(const std::string& target_id, @@ -333,14 +288,23 @@ } Status ChromeImpl::SetWindowBounds( - int window_id, + Window* window, std::unique_ptr<base::DictionaryValue> bounds) { Status status = devtools_websocket_client_->ConnectIfNecessary(); if (status.IsError()) return status; base::DictionaryValue params; - params.SetInteger("windowId", window_id); + params.SetInteger("windowId", window->id); + if (window->state != "normal") { + params.SetString("bounds.windowState", "normal"); + status = devtools_websocket_client_->SendCommand("Browser.setWindowBounds", + params); + if (status.IsError()) + return status; + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); + } + params.Set("bounds", bounds->CreateDeepCopy()); status = devtools_websocket_client_->SendCommand("Browser.setWindowBounds", params); @@ -352,14 +316,13 @@ if (!bounds->GetString("windowState", &state)) return Status(kOk); - Window window; - status = GetWindowBounds(window_id, &window); + status = GetWindowBounds(window->id, window); if (status.IsError()) return status; - if (window.state == state) + if (window->state == state) return Status(kOk); - if (state == "maximized" && window.state == "normal") { + if (state == "maximized" && window->state == "normal") { // Maximize window is not supported in some environment, such as Mac Chrome // version 70 and above, or Linux without a window manager. // In these cases, we simulate window maximization by setting window size @@ -391,7 +354,7 @@ params); } else { return Status(kUnknownError, "failed to change window state to " + state + - ", current state is " + window.state); + ", current state is " + window->state); } } @@ -404,19 +367,10 @@ if (status.IsError()) return status; - if (window.state != "normal") { - // restore window to normal first to allow size change. - auto bounds = std::make_unique<base::DictionaryValue>(); - bounds->SetString("windowState", "normal"); - status = SetWindowBounds(window.id, std::move(bounds)); - if (status.IsError()) - return status; - } - auto bounds = std::make_unique<base::DictionaryValue>(); bounds->SetInteger("width", width); bounds->SetInteger("height", height); - return SetWindowBounds(window.id, std::move(bounds)); + return SetWindowBounds(&window, std::move(bounds)); } Status ChromeImpl::ParseWindow(std::unique_ptr<base::DictionaryValue> params,
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.h b/chrome/test/chromedriver/chrome/chrome_impl.h index 3204a85..652e8e2 100644 --- a/chrome/test/chromedriver/chrome/chrome_impl.h +++ b/chrome/test/chromedriver/chrome/chrome_impl.h
@@ -79,7 +79,7 @@ Status ParseWindowBounds(std::unique_ptr<base::DictionaryValue> params, Window* window); Status GetWindowBounds(int window_id, Window* window); - Status SetWindowBounds(int window_id, + Status SetWindowBounds(Window* window, std::unique_ptr<base::DictionaryValue> bounds); bool quit_;
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.cc b/chrome/test/chromedriver/chrome/stub_web_view.cc index bb3a0b4b..4c86e253 100644 --- a/chrome/test/chromedriver/chrome/stub_web_view.cc +++ b/chrome/test/chromedriver/chrome/stub_web_view.cc
@@ -222,14 +222,6 @@ return Status(kOk); } -Status StubWebView::GetScreenOrientation(std::string* orientation) { - return Status(kOk); -} - -Status StubWebView::SetScreenOrientation(std::string orientation) { - return Status(kOk); -} - bool StubWebView::IsOOPIF(const std::string& frame_id) { return false; }
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.h b/chrome/test/chromedriver/chrome/stub_web_view.h index 5bad1cd2..6710df9 100644 --- a/chrome/test/chromedriver/chrome/stub_web_view.h +++ b/chrome/test/chromedriver/chrome/stub_web_view.h
@@ -109,8 +109,6 @@ int xoffset, int yoffset) override; Status SynthesizePinchGesture(int x, int y, double scale_factor) override; - Status GetScreenOrientation(std::string* orientation) override; - Status SetScreenOrientation(std::string orientation) override; bool IsOOPIF(const std::string& frame_id) override; FrameTracker* GetFrameTracker() const override; std::unique_ptr<base::Value> GetCastSinks() override;
diff --git a/chrome/test/chromedriver/chrome/web_view.h b/chrome/test/chromedriver/chrome/web_view.h index 3fd9f3ce..36e7329 100644 --- a/chrome/test/chromedriver/chrome/web_view.h +++ b/chrome/test/chromedriver/chrome/web_view.h
@@ -235,10 +235,6 @@ virtual Status SynthesizePinchGesture(int x, int y, double scale_factor) = 0; - virtual Status GetScreenOrientation(std::string* orientation) = 0; - - virtual Status SetScreenOrientation(std::string orientation) = 0; - virtual bool IsOOPIF(const std::string& frame_id) = 0; virtual FrameTracker* GetFrameTracker() const = 0;
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.cc b/chrome/test/chromedriver/chrome/web_view_impl.cc index 75847a56..f02fb577 100644 --- a/chrome/test/chromedriver/chrome/web_view_impl.cc +++ b/chrome/test/chromedriver/chrome/web_view_impl.cc
@@ -970,28 +970,6 @@ return client_->SendCommand("Input.synthesizePinchGesture", params); } -Status WebViewImpl::GetScreenOrientation(std::string* orientation) { - base::DictionaryValue empty_params; - std::unique_ptr<base::DictionaryValue> result; - Status status = - client_->SendCommandAndGetResult("Emulation.getScreenOrientation", - empty_params, - &result); - if (status.IsError() || !result->GetString("orientation", orientation)) - return status; - return Status(kOk); -} - -Status WebViewImpl::SetScreenOrientation(std::string orientation) { - base::DictionaryValue params; - params.SetString("screenOrientation", orientation); - Status status = - client_->SendCommand("Emulation.lockScreenOrientation", params); - if (status.IsError()) - return status; - return Status(kOk); -} - Status WebViewImpl::CallAsyncFunctionInternal( const std::string& frame, const std::string& function,
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.h b/chrome/test/chromedriver/chrome/web_view_impl.h index ac52367..bb00be6 100644 --- a/chrome/test/chromedriver/chrome/web_view_impl.h +++ b/chrome/test/chromedriver/chrome/web_view_impl.h
@@ -149,8 +149,6 @@ int xoffset, int yoffset) override; Status SynthesizePinchGesture(int x, int y, double scale_factor) override; - Status GetScreenOrientation(std::string* orientation) override; - Status SetScreenOrientation(std::string orientation) override; bool IsOOPIF(const std::string& frame_id) override; FrameTracker* GetFrameTracker() const override; std::unique_ptr<base::Value> GetCastSinks() override;
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py index f2712fe..a29f59e0 100644 --- a/chrome/test/chromedriver/client/chromedriver.py +++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -611,16 +611,6 @@ params = {'cmd': cmd, 'params': cmd_params}; return self.ExecuteCommand(Command.SEND_COMMAND_AND_GET_RESULT, params) - def GetScreenOrientation(self): - screen_orientation = self.ExecuteCommand(Command.GET_SCREEN_ORIENTATION) - return { - 'orientation': screen_orientation['orientation'] - } - - def SetScreenOrientation(self, orientation_type): - params = {'parameters': {'orientation': orientation_type}} - self.ExecuteCommand(Command.SET_SCREEN_ORIENTATION, params) - def SendKeys(self, *values): typing = [] for value in values:
diff --git a/chrome/test/chromedriver/client/command_executor.py b/chrome/test/chromedriver/client/command_executor.py index ba4390a..a608deb 100644 --- a/chrome/test/chromedriver/client/command_executor.py +++ b/chrome/test/chromedriver/client/command_executor.py
@@ -143,8 +143,6 @@ _Method.DELETE, '/session/:sessionId/session_storage') GET_SESSION_STORAGE_SIZE = ( _Method.GET, '/session/:sessionId/session_storage/size') - GET_SCREEN_ORIENTATION = (_Method.GET, '/session/:sessionId/orientation') - SET_SCREEN_ORIENTATION = (_Method.POST, '/session/:sessionId/orientation') MOUSE_CLICK = (_Method.POST, '/session/:sessionId/click') MOUSE_DOUBLE_CLICK = (_Method.POST, '/session/:sessionId/doubleclick') MOUSE_BUTTON_DOWN = (_Method.POST, '/session/:sessionId/buttondown')
diff --git a/chrome/test/chromedriver/log_replay/client_replay.py b/chrome/test/chromedriver/log_replay/client_replay.py index 6418470..1d94f20 100755 --- a/chrome/test/chromedriver/log_replay/client_replay.py +++ b/chrome/test/chromedriver/log_replay/client_replay.py
@@ -129,7 +129,6 @@ (Method.GET, "/session/:sessionId/chromium/network_conditions"), "GetNetworkConnection": (Method.GET, "/session/:sessionId/network_connection"), - "GetScreenOrientation": (Method.GET, "/session/:sessionId/orientation"), "GetSessionCapabilities": (Method.GET, "/session/:sessionId"), "GetSessionStorageItem": (Method.GET, "/session/:sessionId/session_storage/key/:key"), @@ -196,7 +195,6 @@ (Method.POST, "/session/:sessionId/chromium/network_conditions"), "SetNetworkConnection": (Method.POST, "/session/:sessionId/network_connection"), - "SetScreenOrientation": (Method.POST, "/session/:sessionId/orientation"), "SetScriptTimeout": (Method.POST, "/session/:sessionId/timeouts/async_script"), "SetSessionStorageItem":
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc index ec43e01fb..3c80a219 100644 --- a/chrome/test/chromedriver/server/http_handler.cc +++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -514,20 +514,6 @@ base::BindRepeating(&ExecuteGetElementSize), false /*w3c_standard_command*/)), - // No W3C equivalent. - CommandMapping( - kGet, "session/:sessionId/orientation", - WrapToCommand("GetScreenOrientation", - base::BindRepeating(&ExecuteGetScreenOrientation), - false /*w3c_standard_command*/)), - - // No W3C equivalent. - CommandMapping( - kPost, "session/:sessionId/orientation", - WrapToCommand("SetScreenOrientation", - base::BindRepeating(&ExecuteSetScreenOrientation), - false /*w3c_standard_command*/)), - // Similar to W3C GET /session/:sessionId/alert/text. CommandMapping( kGet, "session/:sessionId/alert_text",
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc index 57e09d0..6e4a160 100644 --- a/chrome/test/chromedriver/session_commands.cc +++ b/chrome/test/chromedriver/session_commands.cc
@@ -111,7 +111,7 @@ } } - if (!params.HasKey("capabilities")) { + if (!params.HasKey("capabilities") && params.HasKey("desiredCapabilities")) { return false; } @@ -1191,41 +1191,6 @@ return Status(kUnknownCommand); } -Status ExecuteGetScreenOrientation(Session* session, - const base::DictionaryValue& params, - std::unique_ptr<base::Value>* value) { - WebView* web_view = nullptr; - Status status = session->GetTargetWindow(&web_view); - if (status.IsError()) - return status; - - std::string screen_orientation; - status = web_view->GetScreenOrientation(&screen_orientation); - if (status.IsError()) - return status; - - base::DictionaryValue orientation_value; - orientation_value.SetString("orientation", screen_orientation); - value->reset(orientation_value.DeepCopy()); - return Status(kOk); -} - -Status ExecuteSetScreenOrientation(Session* session, - const base::DictionaryValue& params, - std::unique_ptr<base::Value>* value) { - WebView* web_view = nullptr; - Status status = session->GetTargetWindow(&web_view); - if (status.IsError()) - return status; - - std::string screen_orientation; - params.GetString("parameters.orientation", &screen_orientation); - status = web_view->SetScreenOrientation(screen_orientation); - if (status.IsError()) - return status; - return Status(kOk); -} - Status ExecuteGenerateTestReport(Session* session, const base::DictionaryValue& params, std::unique_ptr<base::Value>* value) {
diff --git a/chrome/test/chromedriver/session_commands.h b/chrome/test/chromedriver/session_commands.h index 4d21e343..2b457fb 100644 --- a/chrome/test/chromedriver/session_commands.h +++ b/chrome/test/chromedriver/session_commands.h
@@ -168,14 +168,6 @@ const base::DictionaryValue& params, std::unique_ptr<base::Value>* value); -Status ExecuteGetScreenOrientation(Session* session, - const base::DictionaryValue& params, - std::unique_ptr<base::Value>* value); - -Status ExecuteSetScreenOrientation(Session* session, - const base::DictionaryValue& params, - std::unique_ptr<base::Value>* value); - Status ExecuteGenerateTestReport(Session* session, const base::DictionaryValue& params, std::unique_ptr<base::Value>* value);
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index 97af6ea..e214f90b 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -76,10 +76,6 @@ 'ChromeDriverTest.testEmulateNetworkConditionsSpeed', # crbug.com/469947 'ChromeDriverTest.testTouchPinch', - # TODO: re-enable tests when DevTools supports ScreenOrientation commands. - 'ChromeDriverAndroidTest.testScreenOrientation', - 'ChromeDriverAndroidTest.testMultipleScreenOrientationChanges', - 'ChromeDriverAndroidTest.testScreenOrientationAcrossMultipleTabs', # https://bugs.chromium.org/p/chromedriver/issues/detail?id=833 'ChromeDriverTest.testAlertOnNewWindow', # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2532 @@ -2505,89 +2501,6 @@ self._drivers[0].Quit() self._drivers[0] = self.CreateDriver() - def testScreenOrientation(self): - self._driver = self.CreateDriver() - self._driver.Load( - ChromeDriverTest.GetHttpUrlForFile('/chromedriver/orientation_test.html')) - screen_orientation_js = self._driver.ExecuteScript( - 'return screen.orientation.type') - screen_orientation = self._driver.GetScreenOrientation()['orientation'] - if screen_orientation == "LANDSCAPE": - screen_orientation = 'landscape-primary' - elif screen_orientation == "PORTRAIT": - screen_orientation = 'portrait-primary' - self.assertEqual(screen_orientation, screen_orientation_js) - - self._driver.SetScreenOrientation("portrait-primary") - screen_orientation = self._driver.GetScreenOrientation() - self.WaitForCondition( - lambda: 'orientation change 1' in self._driver.FindElement( - 'tag name', 'div').GetText()) - self.assertEqual(screen_orientation['orientation'], "PORTRAIT") - - self._driver.SetScreenOrientation("portrait-secondary") - self.WaitForCondition( - lambda: 'orientation change 2' in self._driver.FindElement( - 'tag name', 'div').GetText()) - screen_orientation = self._driver.GetScreenOrientation() - self.assertEqual(screen_orientation['orientation'], "PORTRAIT") - - self._driver.SetScreenOrientation("PORTRAIT") - self.WaitForCondition( - lambda: 'orientation change 3' in self._driver.FindElement( - 'tag name', 'div').GetText()) - screen_orientation = self._driver.GetScreenOrientation() - self.assertEqual(screen_orientation['orientation'], "PORTRAIT") - - self._driver.SetScreenOrientation("landscape-primary") - self.WaitForCondition( - lambda: 'orientation change 4' in self._driver.FindElement( - 'tag name', 'div').GetText()) - screen_orientation = self._driver.GetScreenOrientation() - self.assertEqual(screen_orientation['orientation'], "LANDSCAPE") - - self._driver.SetScreenOrientation("landscape-secondary") - self.WaitForCondition( - lambda: 'orientation change 5' in self._driver.FindElement( - 'tag name', 'div').GetText()) - screen_orientation = self._driver.GetScreenOrientation() - self.assertEqual(screen_orientation['orientation'], "LANDSCAPE") - - self._driver.SetScreenOrientation("LANDSCAPE") - self.WaitForCondition( - lambda: 'orientation change 6' in self._driver.FindElement( - 'tag name', 'div').GetText()) - screen_orientation = self._driver.GetScreenOrientation() - self.assertEqual(screen_orientation['orientation'], "LANDSCAPE") - - def testMultipleScreenOrientationChanges(self): - self._driver = self.CreateDriver() - - self._driver.SetScreenOrientation('PORTRAIT') - self.assertEqual( - self._driver.GetScreenOrientation()['orientation'], 'PORTRAIT') - - self._driver.SetScreenOrientation('PORTRAIT') - self.assertEqual( - self._driver.GetScreenOrientation()['orientation'], 'PORTRAIT') - - def testScreenOrientationAcrossMultipleTabs(self): - self._driver = self.CreateDriver() - - self._driver.SetScreenOrientation('LANDSCAPE') - self._driver.Load( - ChromeDriverTest.GetHttpUrlForFile('/chromedriver/page_test.html')) - window1 = self._driver.GetCurrentWindowHandle() - self._driver.FindElement('css selector', '#link').Click() - orientation = self._driver.GetScreenOrientation() - self.assertEqual(orientation['orientation'], 'LANDSCAPE') - - self._driver.ExecuteScript('window.name = "oldWindow";') - self._driver.SwitchToWindow('oldWindow') - self.assertEqual(window1, self._driver.GetCurrentWindowHandle()) - orientation = self._driver.GetScreenOrientation() - self.assertEqual(orientation['orientation'], 'LANDSCAPE') - def testAndroidGetWindowSize(self): self._driver = self.CreateDriver() size = self._driver.GetWindowRect()
diff --git a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js index 7839793..f57447767 100644 --- a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js +++ b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
@@ -242,42 +242,43 @@ }); } - test('close on Tab', function() { - return testFocusAfterClosing('Tab'); - }); - test('close on Escape', function() { - return testFocusAfterClosing('Escape'); - }); + test('close on Tab', () => testFocusAfterClosing('Tab')); - test('mouse movement focus options', function() { - function makeMouseoverEvent(node) { - const e = new MouseEvent('mouseover', {bubbles: true}); - node.dispatchEvent(e); - } + test('close on Escape', () => testFocusAfterClosing('Escape')); + /** @param {!EventTarget} eventTarget */ + function dispatchMouseoverEvent(eventTarget) { + eventTarget.dispatchEvent(new MouseEvent('mouseover', {bubbles: true})); + } + + test('moving mouse on option 1 should focus it', () => { menu.showAt(dots); - - // Moving mouse on option 1 should focus it. assertNotEquals(items[0], getDeepActiveElement()); - makeMouseoverEvent(items[0]); + dispatchMouseoverEvent(items[0]); assertEquals(items[0], getDeepActiveElement()); + }); - // Moving mouse on the menu (not on option) should focus the menu. - makeMouseoverEvent(menu); - assertNotEquals(items[0], getDeepActiveElement()); - assertEquals(menu, document.activeElement); + test('moving mouse on the menu (not on option) should focus the menu', () => { + menu.showAt(dots); + items[0].focus(); + dispatchMouseoverEvent(menu); + assertEquals(dialog, getDeepActiveElement()); + }); - // Moving mouse on a disabled item should focus the menu. + test('moving mouse on a disabled item should focus the menu', () => { + menu.showAt(dots); items[2].toggleAttribute('disabled', true); - makeMouseoverEvent(items[2]); - assertNotEquals(checkboxFocusableElement, getDeepActiveElement()); - assertEquals(menu, document.activeElement); + items[0].focus(); + dispatchMouseoverEvent(items[2]); + assertEquals(dialog, getDeepActiveElement()); + }); - // Mouse movements should override keyboard focus. - down(); + test('mouse movements should override keyboard focus', () => { + menu.showAt(dots); + items[0].focus(); down(); assertEquals(items[1], getDeepActiveElement()); - makeMouseoverEvent(items[0]); + dispatchMouseoverEvent(items[0]); assertEquals(items[0], getDeepActiveElement()); });
diff --git a/chrome/test/data/webui/resources/list_property_update_behavior_tests.js b/chrome/test/data/webui/resources/list_property_update_behavior_tests.js index f1893fd..8121b66 100644 --- a/chrome/test/data/webui/resources/list_property_update_behavior_tests.js +++ b/chrome/test/data/webui/resources/list_property_update_behavior_tests.js
@@ -71,7 +71,9 @@ * called for the |words| property on an item of |complexArray|. */ updateComplexArray(newArray) { - if (this.updateList('complexArray', x => x.letter, newArray)) { + if (this.updateList( + 'complexArray', x => x.letter, newArray, + true /* uidBasedUpdate */)) { return {topArrayChanged: true, wordsArrayChanged: false}; } @@ -280,4 +282,24 @@ assertTrue(result.wordsArrayChanged); assertComplexArrayEquals(testElement.complexArray, newArray); }); + + test('first item with same uid modified', () => { + const newArray = JSON.parse(JSON.stringify(testElement.complexArray)); + assertTrue(newArray[0].words.length > 0); + assertNotEquals('apricot', newArray[0].words[0]); + newArray[0].words = ['apricot']; + assertTrue(testElement.updateList('complexArray', x => x.letter, newArray)); + assertDeepEquals(['apricot'], testElement.complexArray[0].words); + }); + + test('first item modified with same uid and last item removed', () => { + const newArray = JSON.parse(JSON.stringify(testElement.complexArray)); + assertTrue(newArray[0].words.length > 0); + assertNotEquals('apricot', newArray[0].words[0]); + newArray[0].words = ['apricot']; + assertTrue(newArray.length > 1); + newArray.pop(); + assertTrue(testElement.updateList('complexArray', x => x.letter, newArray)); + assertDeepEquals(['apricot'], testElement.complexArray[0].words); + }); });
diff --git a/chrome/test/data/webui/settings/chromeos/os_advanced_page_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_advanced_page_browsertest.js index 3256734..f440aa8e 100644 --- a/chrome/test/data/webui/settings/chromeos/os_advanced_page_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_advanced_page_browsertest.js
@@ -71,7 +71,7 @@ const page = settingsMain.$$('os-settings-page'); assertTrue(!!page); let sections = - ['privacy', 'languages', 'downloads', 'reset', 'dateTime', 'a11y']; + ['privacy', 'languages', 'files', 'reset', 'dateTime', 'a11y']; for (let i = 0; i < sections.length; i++) { const section = getSection(page, sections[i]);
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js index d7848c4..ac7bb953 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -45,8 +45,7 @@ var OSSettingsSmbPageTest = class extends OSSettingsBrowserTest { /** @override */ get browsePreload() { - return super.browsePreload + - 'chromeos/os_downloads_page/smb_shares_page.html'; + return super.browsePreload + 'chromeos/os_files_page/smb_shares_page.html'; } /** @override */
diff --git a/chromecast/browser/exo/wm_helper_cast_shell.cc b/chromecast/browser/exo/wm_helper_cast_shell.cc index f9ab15d..61c54d4 100644 --- a/chromecast/browser/exo/wm_helper_cast_shell.cc +++ b/chromecast/browser/exo/wm_helper_cast_shell.cc
@@ -108,7 +108,8 @@ void WMHelperCastShell::OnDragExited() {} -int WMHelperCastShell::OnPerformDrop(const ui::DropTargetEvent& event) { +int WMHelperCastShell::OnPerformDrop(const ui::DropTargetEvent& event, + std::unique_ptr<ui::OSExchangeData> data) { NOTIMPLEMENTED(); return ui::DragDropTypes::DRAG_MOVE; }
diff --git a/chromecast/browser/exo/wm_helper_cast_shell.h b/chromecast/browser/exo/wm_helper_cast_shell.h index ade7b234..206bac3 100644 --- a/chromecast/browser/exo/wm_helper_cast_shell.h +++ b/chromecast/browser/exo/wm_helper_cast_shell.h
@@ -104,7 +104,8 @@ void OnDragEntered(const ui::DropTargetEvent& event) override; int OnDragUpdated(const ui::DropTargetEvent& event) override; void OnDragExited() override; - int OnPerformDrop(const ui::DropTargetEvent& event) override; + int OnPerformDrop(const ui::DropTargetEvent& event, + std::unique_ptr<ui::OSExchangeData> data) override; // Overridden from VSyncTimingManager::Delegate: void AddVSyncParameterObserver(
diff --git a/chromecast/browser/extension_page.cc b/chromecast/browser/extension_page.cc index d72bf754..197a9ac2 100644 --- a/chromecast/browser/extension_page.cc +++ b/chromecast/browser/extension_page.cc
@@ -50,7 +50,6 @@ window_->CreateWindowForWebContents( web_contents(), window_manager_, CastWindowManager::APP, chromecast::shell::VisibilityPriority::STICKY_ACTIVITY); - web_contents()->Focus(); } void ExtensionPage::RenderViewCreated( @@ -60,6 +59,7 @@ if (view) { view->SetBackgroundColor(SK_ColorTRANSPARENT); } + web_contents()->Focus(); } } // namespace chromecast
diff --git a/chromecast/browser/ui/aura/accessibility/automation_manager_aura.h b/chromecast/browser/ui/aura/accessibility/automation_manager_aura.h index f9c2cb3..c1304eb 100644 --- a/chromecast/browser/ui/aura/accessibility/automation_manager_aura.h +++ b/chromecast/browser/ui/aura/accessibility/automation_manager_aura.h
@@ -74,6 +74,8 @@ event_bundle_sink_ = sink; } + int32_t GetIDFromWindow(aura::Window* window) { return cache_.GetID(window); } + private: friend class base::NoDestructor<AutomationManagerAura>;
diff --git a/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.cc b/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.cc index 4df11a8..6ca2402 100644 --- a/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.cc +++ b/chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.cc
@@ -4,9 +4,15 @@ #include "chromecast/browser/ui/aura/accessibility/ax_tree_source_aura.h" +#include "chromecast/browser/accessibility/accessibility_manager.h" +#include "chromecast/browser/cast_browser_process.h" +#include "chromecast/browser/ui/aura/accessibility/automation_manager_aura.h" #include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_node_data.h" #include "ui/accessibility/ax_tree_data.h" +#include "ui/aura/client/focus_client.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" #include "ui/views/accessibility/ax_aura_obj_wrapper.h" AXTreeSourceAura::AXTreeSourceAura(views::AXAuraObjWrapper* root, @@ -19,19 +25,20 @@ bool AXTreeSourceAura::GetTreeData(ui::AXTreeData* tree_data) const { AXTreeSourceViews::GetTreeData(tree_data); - // TODO(b/111911092): AXTreeData::focus_id represents the node within the - // tree with 'keyboard focus'. We have no keyboard focus on chromecast so - // this is being left as -1. This prevents getFocus calls from the chromevox - // background page from finding any window in focus and interferes with - // gesture event processing. Since we only ever have one top level window - // and one ax tree, temporarily returning 1 here to indicate the root node - // is always the focused window. A better solution would be to fix the focus - // issues on chromecast which relies on a) the root window to be focused via - // Focus() and 2) a native widget being registered with the root window so - // the above GetFocus call will work. When this code is re-unified with - // chrome, this will need to be a special case for chromecast unless the - // better solution described above is implemented. - tree_data->focus_id = 1; + aura::Window* root_window = + chromecast::shell::CastBrowserProcess::GetInstance() + ->accessibility_manager() + ->window_tree_host() + ->window(); + if (root_window) { + aura::client::FocusClient* focus_client = + aura::client::GetFocusClient(root_window); + if (focus_client) { + aura::Window* window = focus_client->GetFocusedWindow(); + tree_data->focus_id = + AutomationManagerAura::GetInstance()->GetIDFromWindow(window); + } + } return true; }
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn index bf11007..045f5899 100644 --- a/chromecast/media/cma/backend/BUILD.gn +++ b/chromecast/media/cma/backend/BUILD.gn
@@ -258,6 +258,7 @@ ":volume_map", "//base", "//chromecast/base", + "//chromecast/base:thread_health_checker", "//chromecast/media/audio:libcast_external_audio_pipeline_1.0", "//chromecast/media/base", "//chromecast/media/cma/base",
diff --git a/chromecast/media/cma/backend/stream_mixer.cc b/chromecast/media/cma/backend/stream_mixer.cc index d621ac2..af8955f2 100644 --- a/chromecast/media/cma/backend/stream_mixer.cc +++ b/chromecast/media/cma/backend/stream_mixer.cc
@@ -22,6 +22,7 @@ #include "build/build_config.h" #include "chromecast/base/chromecast_switches.h" #include "chromecast/base/serializers.h" +#include "chromecast/base/thread_health_checker.h" #include "chromecast/media/base/audio_device_ids.h" #include "chromecast/media/cma/backend/audio_output_redirector.h" #include "chromecast/media/cma/backend/cast_audio_json.h" @@ -56,6 +57,11 @@ namespace chromecast { namespace media { +constexpr base::TimeDelta kMixerThreadCheckTimeout = + base::TimeDelta::FromSeconds(10); +constexpr base::TimeDelta kHealthCheckInterval = + base::TimeDelta::FromSeconds(5); + class StreamMixer::ExternalLoopbackAudioObserver : public CastMediaShlib::LoopbackAudioObserver { public: @@ -221,6 +227,13 @@ loopback_options.priority = base::ThreadPriority::REALTIME_AUDIO; loopback_thread_->StartWithOptions(loopback_options); loopback_task_runner_ = loopback_thread_->task_runner(); + + health_checker_ = std::make_unique<ThreadHealthChecker>( + mixer_task_runner_, loopback_task_runner_, kHealthCheckInterval, + kMixerThreadCheckTimeout, + base::BindRepeating(&StreamMixer::OnHealthCheckFailed, + base::Unretained(this))); + LOG(INFO) << "Mixer health checker started"; } else { loopback_task_runner_ = mixer_task_runner_; } @@ -249,6 +262,10 @@ } } +void StreamMixer::OnHealthCheckFailed() { + LOG(FATAL) << "Crash on mixer thread health check failure!"; +} + void StreamMixer::ResetPostProcessors(CastMediaShlib::ResultCallback callback) { RUN_ON_MIXER_THREAD(ResetPostProcessorsOnThread, std::move(callback), ""); }
diff --git a/chromecast/media/cma/backend/stream_mixer.h b/chromecast/media/cma/backend/stream_mixer.h index d917684..8f575ac 100644 --- a/chromecast/media/cma/backend/stream_mixer.h +++ b/chromecast/media/cma/backend/stream_mixer.h
@@ -28,6 +28,8 @@ #include "chromecast/public/volume_control.h" namespace chromecast { +class ThreadHealthChecker; + namespace media { class AudioOutputRedirector; @@ -195,6 +197,9 @@ scoped_refptr<base::SingleThreadTaskRunner> mixer_task_runner_; std::unique_ptr<base::Thread> loopback_thread_; scoped_refptr<base::SingleThreadTaskRunner> loopback_task_runner_; + std::unique_ptr<ThreadHealthChecker> health_checker_; + + void OnHealthCheckFailed(); int num_output_channels_; const int low_sample_rate_cutoff_;
diff --git a/chromeos/dbus/update_engine_client.cc b/chromeos/dbus/update_engine_client.cc index d6e05b3d..7e2206e 100644 --- a/chromeos/dbus/update_engine_client.cc +++ b/chromeos/dbus/update_engine_client.cc
@@ -120,12 +120,15 @@ weak_ptr_factory_.GetWeakPtr(), callback)); return; } - dbus::MethodCall method_call( - update_engine::kUpdateEngineInterface, - update_engine::kAttemptUpdate); + // TODO(crbug.com/982438): Use newer version of kAttemptUpdate instead once + // it was enhanced with protobuf arguments. + dbus::MethodCall method_call(update_engine::kUpdateEngineInterface, + update_engine::kAttemptUpdateWithFlags); dbus::MessageWriter writer(&method_call); - writer.AppendString(""); // Unused. - writer.AppendString(""); // Unused. + writer.AppendString(""); // app_version + writer.AppendString(""); // omaha_url + writer.AppendInt32(0); // flags, default is 0 (interactive). See + // org.chromium.UpdateEngineInterface.dbus-xml. VLOG(1) << "Requesting an update check"; update_engine_proxy_->CallMethod(
diff --git a/chromeos/printing/ppd_provider.cc b/chromeos/printing/ppd_provider.cc index 7958605..44b035d 100644 --- a/chromeos/printing/ppd_provider.cc +++ b/chromeos/printing/ppd_provider.cc
@@ -491,9 +491,17 @@ RunPpdReferenceResolutionSucceeded(std::move(next.cb), kEpsonGenericPPD); } else { - // We don't have anything else left to try. We've reached unsupported - // USB printer, try to grab the manufacturer name. - ResolveUsbManufacturer(std::move(next.cb), search_data.usb_vendor_id); + // We don't have anything else left to try. + if (search_data.discovery_type == + PrinterSearchData::PrinterDiscoveryType::kUsb) { + // We've reached unsupported USB printer, try to grab the manufacturer + // name. + ResolveUsbManufacturer(std::move(next.cb), search_data.usb_vendor_id); + } else { + // Non-USB printer, so we fail resolution normally. + RunPpdReferenceResolutionNotFound(std::move(next.cb), + "" /* Empty Manufacturer */); + } } } // Didn't start any fetches.
diff --git a/chromeos/printing/ppd_provider_unittest.cc b/chromeos/printing/ppd_provider_unittest.cc index 3ea200b..b78427a5 100644 --- a/chromeos/printing/ppd_provider_unittest.cc +++ b/chromeos/printing/ppd_provider_unittest.cc
@@ -35,6 +35,8 @@ namespace { +using PrinterDiscoveryType = PrinterSearchData::PrinterDiscoveryType; + // Name of the fake server we're resolving ppds from. const char kPpdServer[] = "bogus.google.com"; @@ -402,12 +404,15 @@ auto provider = CreateProvider("en", false); PrinterSearchData unrecognized_printer; + unrecognized_printer.discovery_type = PrinterDiscoveryType::kManual; unrecognized_printer.make_and_model = {"Printer Printer"}; PrinterSearchData recognized_printer; + recognized_printer.discovery_type = PrinterDiscoveryType::kManual; recognized_printer.make_and_model = {"printer_a_ref"}; PrinterSearchData mixed; + mixed.discovery_type = PrinterDiscoveryType::kManual; mixed.make_and_model = {"printer_a_ref", "Printer Printer"}; // Resolve the same thing repeatedly. @@ -440,6 +445,7 @@ auto provider = CreateProvider("en", false); PrinterSearchData search_data; + search_data.discovery_type = PrinterDiscoveryType::kUsb; // Should get back "Some canonical reference" search_data.usb_vendor_id = 0x031f; @@ -954,6 +960,7 @@ auto provider = CreateProvider("en", false); PrinterSearchData search_data; + search_data.discovery_type = PrinterDiscoveryType::kUsb; // Vendor id that exists, nonexistent device id, should get a NOT_FOUND. // Although this is an unsupported printer model, we can still expect to get
diff --git a/chromeos/services/assistant/platform/audio_stream_handler.cc b/chromeos/services/assistant/platform/audio_stream_handler.cc index 8b9d58d..00e2afa88 100644 --- a/chromeos/services/assistant/platform/audio_stream_handler.cc +++ b/chromeos/services/assistant/platform/audio_stream_handler.cc
@@ -112,7 +112,7 @@ if (!stopped_) OnError(assistant_client::AudioOutput::Error::FATAL_ERROR); - std::move(start_device_owner_on_main_thread_); + start_device_owner_on_main_thread_.Reset(); return; } @@ -169,7 +169,7 @@ void AudioStreamHandler::OnFillBufferOnThread( assistant_client::Callback1<int> on_filled, int num_bytes) { - std::move(on_filled)(num_bytes); + on_filled(num_bytes); } void AudioStreamHandler::DecodeOnThread() {
diff --git a/chromeos/services/device_sync/cryptauth_device_sync_result.cc b/chromeos/services/device_sync/cryptauth_device_sync_result.cc index 0ceca42a..1affb80a 100644 --- a/chromeos/services/device_sync/cryptauth_device_sync_result.cc +++ b/chromeos/services/device_sync/cryptauth_device_sync_result.cc
@@ -10,8 +10,11 @@ CryptAuthDeviceSyncResult::CryptAuthDeviceSyncResult( ResultCode result_code, + bool did_device_registry_change, const base::Optional<cryptauthv2::ClientDirective>& client_directive) - : result_code_(result_code), client_directive_(client_directive) {} + : result_code_(result_code), + did_device_registry_change_(did_device_registry_change), + client_directive_(client_directive) {} CryptAuthDeviceSyncResult::CryptAuthDeviceSyncResult( const CryptAuthDeviceSyncResult& other) = default; @@ -45,8 +48,146 @@ case ResultCode::kSuccess: stream << "[Success]"; break; - case ResultCode::kError: - stream << "[Error]"; + case ResultCode::kErrorMissingUserKeyPair: + stream << "[Error: No user key pair in registry]"; + break; + case ResultCode::kErrorEncryptingDeviceMetadata: + stream << "[Error: Could not encrypt local device metadata]"; + break; + case ResultCode::kErrorEstablishingGroupPublicKey: + stream << "[Error: Could not establish group public key]"; + break; + case ResultCode::kErrorNoMetadataInResponse: + stream << "[Error: No encrypted metadata in SyncMetadata response]"; + break; + case ResultCode::kErrorInvalidMetadataInResponse: + stream << "[Error: Invalid DeviceMetadataPacket in SyncMetadata " + << "response]"; + break; + case ResultCode::kErrorDuplicateDeviceIdsInResponse: + stream << "[Error: Duplicate device IDs in SyncMetadata response]"; + break; + case ResultCode::kErrorNoLocalDeviceMetadataInResponse: + stream << "[Error: No local device metadata in SyncMetadata response]"; + break; + case ResultCode::kErrorMissingFeatureStatuses: + stream << "[Error: Feature statuses not received for device(s)]"; + break; + case ResultCode::kErrorMissingLocalDeviceSyncBetterTogetherKey: + stream << "[Error: No DeviceSync:BetterTogether key in registry]"; + break; + case ResultCode::kErrorDecryptingGroupPrivateKey: + stream << "[Error: Could not decrypt group private key]"; + break; + case ResultCode::kErrorInconsistentGroupPrivateKeys: + stream << "[Error: Group private key from SyncMetadata response " + << "unexpectedly disagrees with the one in local storage]"; + break; + case ResultCode::kErrorDecryptingMetadata: + stream << "[Error: Could not decrypt device metadata]"; + break; + case ResultCode::kErrorParsingMetadata: + stream << "[Error: Could not parse device metadata]"; + break; + case ResultCode::kErrorInconsistentLocalDeviceMetadata: + stream << "[Error: Local device metadata disagrees with that in " + << "SyncMetadata response]"; + break; + case ResultCode::kErrorEncryptingGroupPrivateKey: + stream << "[Error: Could not encrypt group private key]"; + break; + case ResultCode::kErrorSyncMetadataApiCallOffline: + stream << "[SyncMetadata API call failed: Offline]"; + break; + case ResultCode::kErrorSyncMetadataApiCallEndpointNotFound: + stream << "[SyncMetadata API call failed: Endpoint not found]"; + break; + case ResultCode::kErrorSyncMetadataApiCallAuthenticationError: + stream << "[SyncMetadata API call failed: Authentication error]"; + break; + case ResultCode::kErrorSyncMetadataApiCallBadRequest: + stream << "[SyncMetadata API call failed: Bad request]"; + break; + case ResultCode::kErrorSyncMetadataApiCallResponseMalformed: + stream << "[SyncMetadata API call failed: Response malformed]"; + break; + case ResultCode::kErrorSyncMetadataApiCallInternalServerError: + stream << "[SyncMetadata API call failed: Internal server error]"; + break; + case ResultCode::kErrorSyncMetadataApiCallUnknownError: + stream << "[SyncMetadata API call failed: Unknown error]"; + break; + case ResultCode::kErrorBatchGetFeatureStatusesApiCallOffline: + stream << "[BatchGetFeatureStatuses API call failed: Offline]"; + break; + case ResultCode::kErrorBatchGetFeatureStatusesApiCallEndpointNotFound: + stream << "[BatchGetFeatureStatuses API call failed: Endpoint not found]"; + break; + case ResultCode::kErrorBatchGetFeatureStatusesApiCallAuthenticationError: + stream << "[BatchGetFeatureStatuses API call failed: Authentication " + << "error]"; + break; + case ResultCode::kErrorBatchGetFeatureStatusesApiCallBadRequest: + stream << "[BatchGetFeatureStatuses API call failed: Bad request]"; + break; + case ResultCode::kErrorBatchGetFeatureStatusesApiCallResponseMalformed: + stream << "[BatchGetFeatureStatuses API call failed: Response malformed]"; + break; + case ResultCode::kErrorBatchGetFeatureStatusesApiCallInternalServerError: + stream << "[BatchGetFeatureStatuses API call failed: Internal server " + << "error]"; + break; + case ResultCode::kErrorBatchGetFeatureStatusesApiCallUnknownError: + stream << "[BatchGetFeatureStatuses API call failed: Unknown error]"; + break; + case ResultCode::kErrorShareGroupPrivateKeyApiCallOffline: + stream << "[ShareGroupPrivateKey API call failed: Offline]"; + break; + case ResultCode::kErrorShareGroupPrivateKeyApiCallEndpointNotFound: + stream << "[ShareGroupPrivateKey API call failed: Endpoint not found]"; + break; + case ResultCode::kErrorShareGroupPrivateKeyApiCallAuthenticationError: + stream << "[ShareGroupPrivateKey API call failed: Authentication error]"; + break; + case ResultCode::kErrorShareGroupPrivateKeyApiCallBadRequest: + stream << "[ShareGroupPrivateKey API call failed: Bad request]"; + break; + case ResultCode::kErrorShareGroupPrivateKeyApiCallResponseMalformed: + stream << "[ShareGroupPrivateKey API call failed: Response malformed]"; + break; + case ResultCode::kErrorShareGroupPrivateKeyApiCallInternalServerError: + stream << "[ShareGroupPrivateKey API call failed: Internal server error]"; + break; + case ResultCode::kErrorShareGroupPrivateKeyApiCallUnknownError: + stream << "[ShareGroupPrivateKey API call failed: Unknown error]"; + break; + case ResultCode::kErrorTimeoutWaitingForGroupKeyCreation: + stream << "[Error: Timeout waiting for group key creation]"; + break; + case ResultCode::kErrorTimeoutWaitingForLocalDeviceMetadataEncryption: + stream << "[Error: Timeout waiting for local device metadata encryption]"; + break; + case ResultCode::kErrorTimeoutWaitingForFirstSyncMetadataResponse: + stream << "[Error: Timeout waiting for first SyncMetadata response]"; + break; + case ResultCode::kErrorTimeoutWaitingForSecondSyncMetadataResponse: + stream << "[Error: Timeout waiting for second SyncMetadata response]"; + break; + case ResultCode::kErrorTimeoutWaitingForGroupPrivateKeyDecryption: + stream << "[Error: Timeout waiting for group private key decryption]"; + break; + case ResultCode::kErrorTimeoutWaitingForDeviceMetadataDecryption: + stream << "[Error: Timeout waiting for remote device metadata " + << "decryption]"; + break; + case ResultCode::kErrorTimeoutWaitingForBatchGetFeatureStatusesResponse: + stream << "[Error: Timeout waiting for BatchGetFeatureStatuses response]"; + break; + case ResultCode::kErrorTimeoutWaitingForGroupPrivateKeyEncryption: + stream << "[Error: Timeout waiting for group private key encryption]"; + break; + case ResultCode::kErrorTimeoutWaitingForShareGroupPrivateKeyResponse: + stream << "[Error: Timeout waiting for ShareGroupPrivateKey response]"; break; }
diff --git a/chromeos/services/device_sync/cryptauth_device_sync_result.h b/chromeos/services/device_sync/cryptauth_device_sync_result.h index 651fe1b..f6dc61a 100644 --- a/chromeos/services/device_sync/cryptauth_device_sync_result.h +++ b/chromeos/services/device_sync/cryptauth_device_sync_result.h
@@ -15,24 +15,67 @@ namespace device_sync { // Information about the result of a CryptAuth v2 DeviceSync attempt. -// TODO(nohle): Add a HaveDevicesChanged() function that returns true if the -// synced-device registry changes. class CryptAuthDeviceSyncResult { public: // Enum class to denote the result of a CryptAuth v2 DeviceSync attempt. // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. If entries are added, kMaxValue // should be updated. - // TODO(nohle): Add more values after DeviceSync flow is implemented. + // TODO(nohle): Add numeric values. enum class ResultCode { - kSuccess = 0, - kError = 1, + kSuccess, + kErrorMissingUserKeyPair, + kErrorEncryptingDeviceMetadata, + kErrorEstablishingGroupPublicKey, + kErrorNoMetadataInResponse, + kErrorInvalidMetadataInResponse, + kErrorDuplicateDeviceIdsInResponse, + kErrorNoLocalDeviceMetadataInResponse, + kErrorMissingFeatureStatuses, + kErrorMissingLocalDeviceSyncBetterTogetherKey, + kErrorDecryptingGroupPrivateKey, + kErrorInconsistentGroupPrivateKeys, + kErrorDecryptingMetadata, + kErrorParsingMetadata, + kErrorInconsistentLocalDeviceMetadata, + kErrorEncryptingGroupPrivateKey, + kErrorSyncMetadataApiCallOffline, + kErrorSyncMetadataApiCallEndpointNotFound, + kErrorSyncMetadataApiCallAuthenticationError, + kErrorSyncMetadataApiCallBadRequest, + kErrorSyncMetadataApiCallResponseMalformed, + kErrorSyncMetadataApiCallInternalServerError, + kErrorSyncMetadataApiCallUnknownError, + kErrorBatchGetFeatureStatusesApiCallOffline, + kErrorBatchGetFeatureStatusesApiCallEndpointNotFound, + kErrorBatchGetFeatureStatusesApiCallAuthenticationError, + kErrorBatchGetFeatureStatusesApiCallBadRequest, + kErrorBatchGetFeatureStatusesApiCallResponseMalformed, + kErrorBatchGetFeatureStatusesApiCallInternalServerError, + kErrorBatchGetFeatureStatusesApiCallUnknownError, + kErrorShareGroupPrivateKeyApiCallOffline, + kErrorShareGroupPrivateKeyApiCallEndpointNotFound, + kErrorShareGroupPrivateKeyApiCallAuthenticationError, + kErrorShareGroupPrivateKeyApiCallBadRequest, + kErrorShareGroupPrivateKeyApiCallResponseMalformed, + kErrorShareGroupPrivateKeyApiCallInternalServerError, + kErrorShareGroupPrivateKeyApiCallUnknownError, + kErrorTimeoutWaitingForGroupKeyCreation, + kErrorTimeoutWaitingForLocalDeviceMetadataEncryption, + kErrorTimeoutWaitingForFirstSyncMetadataResponse, + kErrorTimeoutWaitingForSecondSyncMetadataResponse, + kErrorTimeoutWaitingForGroupPrivateKeyDecryption, + kErrorTimeoutWaitingForDeviceMetadataDecryption, + kErrorTimeoutWaitingForBatchGetFeatureStatusesResponse, + kErrorTimeoutWaitingForGroupPrivateKeyEncryption, + kErrorTimeoutWaitingForShareGroupPrivateKeyResponse, // Used for UMA logs. - kMaxValue = kError + kMaxValue = kErrorTimeoutWaitingForShareGroupPrivateKeyResponse }; CryptAuthDeviceSyncResult( ResultCode result_code, + bool did_device_registry_change, const base::Optional<cryptauthv2::ClientDirective>& client_directive); CryptAuthDeviceSyncResult(const CryptAuthDeviceSyncResult& other); @@ -44,6 +87,10 @@ return client_directive_; } + bool did_device_registry_change() const { + return did_device_registry_change_; + } + bool IsSuccess() const; bool operator==(const CryptAuthDeviceSyncResult& other) const; @@ -51,6 +98,7 @@ private: ResultCode result_code_; + bool did_device_registry_change_; base::Optional<cryptauthv2::ClientDirective> client_directive_; };
diff --git a/chromeos/services/device_sync/cryptauth_scheduler_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_scheduler_impl_unittest.cc index 0a48a8d..fedf1c9 100644 --- a/chromeos/services/device_sync/cryptauth_scheduler_impl_unittest.cc +++ b/chromeos/services/device_sync/cryptauth_scheduler_impl_unittest.cc
@@ -497,7 +497,9 @@ CryptAuthEnrollmentResult::ResultCode::kErrorCryptAuthServerOverloaded, base::nullopt /* client_directive */)); scheduler()->HandleDeviceSyncResult( - CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode::kError, + CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode:: + kErrorSyncMetadataApiCallBadRequest, + false /* device_registry_changed */, base::nullopt /* client_directive */)); expected_request.set_retry_count(attempt); @@ -582,7 +584,9 @@ CryptAuthEnrollmentResult::ResultCode::kErrorCryptAuthServerOverloaded, cryptauthv2::GetClientDirectiveForTest())); scheduler()->HandleDeviceSyncResult( - CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode::kError, + CryptAuthDeviceSyncResult(CryptAuthDeviceSyncResult::ResultCode:: + kErrorSyncMetadataApiCallBadRequest, + false /* device_registry_changed */, cryptauthv2::GetClientDirectiveForTest())); // Pending request scheduled after current attempt finishes, even if it fails.
diff --git a/components/autofill/core/browser/autofill_field.h b/components/autofill/core/browser/autofill_field.h index eeb64b7..e46ff91 100644 --- a/components/autofill/core/browser/autofill_field.h +++ b/components/autofill/core/browser/autofill_field.h
@@ -132,6 +132,9 @@ void set_default_value(const std::string& value) { default_value_ = value; } const std::string& default_value() const { return default_value_; } + void set_initial_value_hash(uint32_t value) { initial_value_hash_ = value; } + base::Optional<uint32_t> initial_value_hash() { return initial_value_hash_; } + void set_credit_card_number_offset(size_t position) { credit_card_number_offset_ = position; } @@ -224,6 +227,10 @@ // The default value returned by the Autofill server. std::string default_value_; + // A low-entropy hash of the field's initial value before user-interactions or + // automatic fillings. This field is used to detect static placeholders. + base::Optional<uint32_t> initial_value_hash_; + // Used to hold the position of the first digit to be copied as a substring // from credit card number. size_t credit_card_number_offset_;
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc index 020fd9f..98c2230 100644 --- a/components/autofill/core/browser/form_structure.cc +++ b/components/autofill/core/browser/form_structure.cc
@@ -1886,6 +1886,10 @@ added_field->set_vote_type(field->vote_type()); } + if (field->initial_value_hash()) { + added_field->set_initial_value_hash(field->initial_value_hash().value()); + } + added_field->set_signature(field->GetFieldSignature()); if (field->properties_mask)
diff --git a/components/autofill/core/browser/proto/server.proto b/components/autofill/core/browser/proto/server.proto index a77adf9..67002a1 100644 --- a/components/autofill/core/browser/proto/server.proto +++ b/components/autofill/core/browser/proto/server.proto
@@ -186,7 +186,7 @@ // This message contains information about the field types in a single form. // It is sent by the toolbar to contribute to the field type statistics. -// Next available id: 40 +// Next available id: 41 message AutofillUploadContents { required string client_version = 1; required fixed64 form_signature = 2; @@ -305,6 +305,11 @@ // A list of possible types for the field with their corresponding validity // states based on the user's data. repeated AutofillTypeValiditiesPair autofill_type_validities = 35; + + // A low-entropy hash of the field's initial value before user-interactions + // or automatic fillings. This field is used to detect static + // placeholders. + optional uint32 initial_value_hash = 40; } // Signature of the form action host (e.g. Hash64Bit("example.com")). optional fixed64 action_signature = 13; @@ -320,7 +325,7 @@ // The form name. optional string form_name = 16; - // True iff the the non-obfuscated password values were shown to the user. + // True if the non-obfuscated password values were shown to the user. optional bool passwords_revealed = 24; // The section of noisified data about password. @@ -341,10 +346,10 @@ // Whether the password has any special symbol. optional bool password_has_special_symbol = 28; - // Noisifed password length. + // Noisified password length. optional uint32 password_length = 29; - // If |password_has_special_symbol| is true, this field contains nosified + // If |password_has_special_symbol| is true, this field contains noisified // information about a special symbol used in a user-created password stored // in ASCII code. // Otherwise, this field is unset.
diff --git a/components/cloud_devices/common/printer_description.cc b/components/cloud_devices/common/printer_description.cc index f96b8f9..922a9688 100644 --- a/components/cloud_devices/common/printer_description.cc +++ b/components/cloud_devices/common/printer_description.cc
@@ -583,13 +583,13 @@ void RangeVendorCapability::SaveTo(base::Value* dict) const { DCHECK(IsValid()); - dict->SetKey( + dict->SetStringKey( kKeyValueType, - base::Value(TypeToString(kRangeVendorCapabilityTypeNames, value_type_))); - dict->SetKey(kVendorCapabilityMinValue, base::Value(min_value_)); - dict->SetKey(kVendorCapabilityMaxValue, base::Value(max_value_)); + TypeToString(kRangeVendorCapabilityTypeNames, value_type_)); + dict->SetStringKey(kVendorCapabilityMinValue, min_value_); + dict->SetStringKey(kVendorCapabilityMaxValue, max_value_); if (!default_value_.empty()) - dict->SetKey(kVendorCapabilityDefaultValue, base::Value(default_value_)); + dict->SetStringKey(kVendorCapabilityDefaultValue, default_value_); } SelectVendorCapabilityOption::SelectVendorCapabilityOption() = default; @@ -670,14 +670,14 @@ void TypedValueVendorCapability::SaveTo(base::Value* dict) const { DCHECK(IsValid()); - dict->SetKey(kKeyValueType, - base::Value(TypeToString(kTypedValueVendorCapabilityTypeNames, - value_type_))); + dict->SetStringKey( + kKeyValueType, + TypeToString(kTypedValueVendorCapabilityTypeNames, value_type_)); if (!default_value_.empty()) - dict->SetKey(kVendorCapabilityDefaultValue, base::Value(default_value_)); + dict->SetStringKey(kVendorCapabilityDefaultValue, default_value_); } -VendorCapability::VendorCapability() = default; +VendorCapability::VendorCapability() : type_(Type::NONE) {} VendorCapability::VendorCapability(const std::string& id, const std::string& display_name, @@ -704,108 +704,170 @@ display_name_(display_name), typed_value_capability_(std::move(typed_value_capability)) {} -VendorCapability::VendorCapability(VendorCapability&& other) = default; +VendorCapability::VendorCapability(VendorCapability&& other) + : type_(other.type_), id_(other.id_), display_name_(other.display_name_) { + switch (type_) { + case Type::NONE: + // No-op; + break; + case Type::RANGE: + new (&range_capability_) + RangeVendorCapability(std::move(other.range_capability_)); + break; + case Type::SELECT: + new (&select_capability_) + SelectVendorCapability(std::move(other.select_capability_)); + break; + case Type::TYPED_VALUE: + new (&typed_value_capability_) + TypedValueVendorCapability(std::move(other.typed_value_capability_)); + break; + default: + NOTREACHED(); + } +} -VendorCapability::~VendorCapability() = default; +VendorCapability::~VendorCapability() { + InternalCleanup(); +} + +void VendorCapability::InternalCleanup() { + switch (type_) { + case Type::NONE: + break; + case Type::RANGE: + range_capability_.~RangeVendorCapability(); + break; + case Type::SELECT: + select_capability_.~SelectVendorCapability(); + break; + case Type::TYPED_VALUE: + typed_value_capability_.~TypedValueVendorCapability(); + break; + default: + NOTREACHED(); + } + type_ = Type::NONE; +} bool VendorCapability::operator==(const VendorCapability& other) const { - return type_ == other.type_ && id_ == other.id_ && - display_name_ == other.display_name_ && - range_capability_ == other.range_capability_ && - select_capability_ == other.select_capability_ && - typed_value_capability_ == other.typed_value_capability_; + if (type_ != other.type_ || id_ != other.id_ || + display_name_ != other.display_name_) { + return false; + } + switch (type_) { + case Type::NONE: + return true; + case Type::RANGE: + return range_capability_ == other.range_capability_; + case Type::SELECT: + return select_capability_ == other.select_capability_; + case Type::TYPED_VALUE: + return typed_value_capability_ == other.typed_value_capability_; + } + NOTREACHED() << "Bad vendor capability type"; } bool VendorCapability::IsValid() const { if (id_.empty() || display_name_.empty()) return false; switch (type_) { + case Type::NONE: + return false; case Type::RANGE: - return !select_capability_ && !typed_value_capability_ && - range_capability_ && range_capability_.value().IsValid(); + return range_capability_.IsValid(); case Type::SELECT: - return !range_capability_ && !typed_value_capability_ && - select_capability_ && select_capability_.value().IsValid(); + return select_capability_.IsValid(); case Type::TYPED_VALUE: - return !range_capability_ && !select_capability_ && - typed_value_capability_ && - typed_value_capability_.value().IsValid(); + return typed_value_capability_.IsValid(); } NOTREACHED() << "Bad vendor capability type"; return false; } bool VendorCapability::LoadFrom(const base::Value& dict) { + InternalCleanup(); const std::string* type_str = dict.FindStringKey(kKeyType); + Type type; if (!type_str || - !TypeFromString(kVendorCapabilityTypeNames, *type_str, &type_)) { + !TypeFromString(kVendorCapabilityTypeNames, *type_str, &type)) { return false; } + const std::string* id_str = dict.FindStringKey(kKeyId); if (!id_str) return false; + id_ = *id_str; const std::string* display_name_str = dict.FindStringKey(kKeyDisplayName); if (!display_name_str) return false; - display_name_ = *display_name_str; + display_name_ = *display_name_str; const base::Value* range_capability_value = - dict.FindKey(kOptionRangeCapability); - if (range_capability_value) { - if (!range_capability_value->is_dict()) - return false; - range_capability_ = RangeVendorCapability(); - if (!range_capability_.value().LoadFrom(*range_capability_value)) - return false; - } + dict.FindDictKey(kOptionRangeCapability); + if (!range_capability_value == (type == Type::RANGE)) + return false; const base::Value* select_capability_value = - dict.FindKey(kOptionSelectCapability); - if (select_capability_value) { - if (!select_capability_value->is_dict()) - return false; - select_capability_ = SelectVendorCapability(); - if (!select_capability_.value().LoadFrom(*select_capability_value)) - return false; - } + dict.FindDictKey(kOptionSelectCapability); + if (!select_capability_value == (type == Type::SELECT)) + return false; const base::Value* typed_value_capability_value = - dict.FindKey(kOptionTypedValueCapability); - if (typed_value_capability_value) { - if (!typed_value_capability_value->is_dict()) - return false; - typed_value_capability_ = TypedValueVendorCapability(); - if (!typed_value_capability_.value().LoadFrom( - *typed_value_capability_value)) { - return false; - } + dict.FindDictKey(kOptionTypedValueCapability); + if (!typed_value_capability_value == (type == Type::TYPED_VALUE)) + return false; + + type_ = type; + switch (type_) { + case Type::NONE: + default: + NOTREACHED(); + break; + case Type::RANGE: + new (&range_capability_) RangeVendorCapability(); + return range_capability_.LoadFrom(*range_capability_value); + case Type::SELECT: + new (&select_capability_) SelectVendorCapability(); + return select_capability_.LoadFrom(*select_capability_value); + case Type::TYPED_VALUE: + new (&typed_value_capability_) TypedValueVendorCapability(); + return typed_value_capability_.LoadFrom(*typed_value_capability_value); } - return IsValid(); + return false; } void VendorCapability::SaveTo(base::Value* dict) const { DCHECK(IsValid()); - dict->SetKey(kKeyType, - base::Value(TypeToString(kVendorCapabilityTypeNames, type_))); - dict->SetKey(kKeyId, base::Value(id_)); - dict->SetKey(kKeyDisplayName, base::Value(display_name_)); + dict->SetStringKey(kKeyType, TypeToString(kVendorCapabilityTypeNames, type_)); + dict->SetStringKey(kKeyId, id_); + dict->SetStringKey(kKeyDisplayName, display_name_); - if (range_capability_) { - base::Value range_capability_value(base::Value::Type::DICTIONARY); - range_capability_.value().SaveTo(&range_capability_value); - dict->SetKey(kOptionRangeCapability, std::move(range_capability_value)); - } else if (select_capability_) { - base::Value select_capability_value(base::Value::Type::DICTIONARY); - select_capability_.value().SaveTo(&select_capability_value); - dict->SetKey(kOptionSelectCapability, std::move(select_capability_value)); - } else { - DCHECK(typed_value_capability_); - base::Value typed_value_capability_value(base::Value::Type::DICTIONARY); - typed_value_capability_.value().SaveTo(&typed_value_capability_value); - dict->SetKey(kOptionTypedValueCapability, - std::move(typed_value_capability_value)); + switch (type_) { + case Type::NONE: + NOTREACHED(); + break; + case Type::RANGE: { + base::Value range_capability_value(base::Value::Type::DICTIONARY); + range_capability_.SaveTo(&range_capability_value); + dict->SetKey(kOptionRangeCapability, std::move(range_capability_value)); + break; + } + case Type::SELECT: { + base::Value select_capability_value(base::Value::Type::DICTIONARY); + select_capability_.SaveTo(&select_capability_value); + dict->SetKey(kOptionSelectCapability, std::move(select_capability_value)); + break; + } + case Type::TYPED_VALUE: { + base::Value typed_value_capability_value(base::Value::Type::DICTIONARY); + typed_value_capability_.SaveTo(&typed_value_capability_value); + dict->SetKey(kOptionTypedValueCapability, + std::move(typed_value_capability_value)); + break; + } } }
diff --git a/components/cloud_devices/common/printer_description.h b/components/cloud_devices/common/printer_description.h index 786b5e5..6807559 100644 --- a/components/cloud_devices/common/printer_description.h +++ b/components/cloud_devices/common/printer_description.h
@@ -11,7 +11,6 @@ #include <vector> #include "base/logging.h" -#include "base/optional.h" #include "build/build_config.h" #include "components/cloud_devices/common/description_items.h" @@ -143,6 +142,7 @@ class VendorCapability { public: enum class Type { + NONE, RANGE, SELECT, TYPED_VALUE, @@ -171,14 +171,18 @@ void SaveTo(base::Value* dict) const; private: + void InternalCleanup(); + Type type_; std::string id_; std::string display_name_; - // If the CDD is valid, exactly one of the capabilities has non-nullopt value. - base::Optional<RangeVendorCapability> range_capability_; - base::Optional<SelectVendorCapability> select_capability_; - base::Optional<TypedValueVendorCapability> typed_value_capability_; + // If the CDD is valid, exactly one of the capabilities has a value. + union { + RangeVendorCapability range_capability_; + SelectVendorCapability select_capability_; + TypedValueVendorCapability typed_value_capability_; + }; DISALLOW_COPY_AND_ASSIGN(VendorCapability); };
diff --git a/components/flags_ui/resources/flags.html b/components/flags_ui/resources/flags.html index 4fcd53d..ff7f3596 100644 --- a/components/flags_ui/resources/flags.html +++ b/components/flags_ui/resources/flags.html
@@ -99,7 +99,7 @@ <textarea class="experiment-origin-list-value" jsvalues=".internal_name:internal_name; .value:origin_list_value; aria-labelledby:internal_name + '_name'" - tabindex="7"></textarea> + tabindex="6"></textarea> </div> <a class="permalink" jsvalues="href: '#' + internal_name" jscontent="'#' + internal_name" tabindex="6"></a> @@ -146,7 +146,7 @@ <textarea class="experiment-origin-list-value" jsvalues=".internal_name:internal_name; .value:origin_list_value; aria-labelledby:internal_name + '_name'" - tabindex="7"></textarea> + tabindex="6"></textarea> </div> <a class="permalink" jsvalues="href: '#' + internal_name" jscontent="'#' + internal_name" tabindex="6"></a>
diff --git a/components/metrics/persistent_histograms.cc b/components/metrics/persistent_histograms.cc index 4071b83..29a54f5 100644 --- a/components/metrics/persistent_histograms.cc +++ b/components/metrics/persistent_histograms.cc
@@ -43,12 +43,11 @@ // then fails to remove them. See https://crbug.com/934164 void DeleteOldWindowsTempFiles(const base::FilePath& dir) { // Look for any temp files older than one day and remove them. The time check - // unsures that nothing in active transition gets deleted; these names only + // ensures that nothing in active transition gets deleted; these names only // exists on the order of milliseconds when working properly so "one day" is // generous but still ensures no big build up of these files. This is an // I/O intensive task so do it in the background (enforced by "file" calls). base::Time one_day_ago = base::Time::Now() - base::TimeDelta::FromDays(1); - int delete_count = 0; base::FileEnumerator file_iter(dir, /*recursive=*/false, base::FileEnumerator::FILES); for (base::FilePath path = file_iter.Next(); !path.empty(); @@ -67,11 +66,7 @@ continue; base::DeleteFile(path, /*recursive=*/false); - delete_count++; } - - base::UmaHistogramCounts1000("UMA.PersistentHistograms.TmpRemovals", - delete_count); } // How much time after startup to run the above function. Two minutes is
diff --git a/components/module_installer/android/BUILD.gn b/components/module_installer/android/BUILD.gn index e781862b..41d2ab4c 100644 --- a/components/module_installer/android/BUILD.gn +++ b/components/module_installer/android/BUILD.gn
@@ -10,11 +10,12 @@ # build. android_library("module_installer_java") { java_files = [ - "java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java", + "java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java", + "java/src-common/org/chromium/components/module_installer/ModuleInstaller.java", "java/src-common/org/chromium/components/module_installer/OnModuleInstallFinishedListener.java", "java/src-common/org/chromium/components/module_installer/Module.java", ] - jar_excluded_patterns = [ "*/ModuleInstaller.class" ] + jar_excluded_patterns = [ "*/ModuleInstallerImpl.class" ] deps = [ "//base:base_java", ] @@ -24,7 +25,7 @@ # Contains stub implementation to be used for builds not supporting modules # (e.g. APKs). android_library("module_installer_stub_java") { - java_files = [ "java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java" ] + java_files = [ "java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java" ] deps = [ ":module_installer_java", "//base:base_java", @@ -36,7 +37,7 @@ # bundles). android_library("module_installer_impl_java") { java_files = [ - "java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java", + "java/src-impl/org/chromium/components/module_installer/ModuleInstallerImpl.java", "java/src-impl/org/chromium/components/module_installer/ModuleInstallerBackend.java", "java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java", "java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java", @@ -50,10 +51,12 @@ } android_library("module_installer_test_java") { - java_files = [ "java/src-test/org/chromium/components/module_installer/ModuleInstaller.java" ] + testonly = true + java_files = [ "javatests/src/org/chromium/components/module_installer/ModuleInstallerRule.java" ] deps = [ ":module_installer_java", "//base:base_java", + "//third_party/junit", ] jacoco_never_instrument = true }
diff --git a/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java b/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java index 9e19273..ccd6e5ab 100644 --- a/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java +++ b/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java
@@ -56,7 +56,7 @@ // Accessing classes in the module may cause its DEX file to be loaded. And on some devices // that causes a read mode violation. try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) { - ModuleInstaller.init(); + ModuleInstaller.getInstance().init(); Class.forName(mImplClassName); return true; } catch (ClassNotFoundException e) { @@ -64,18 +64,18 @@ } } - /** Requests install of the module. See {@link ModuleInstaller#install} for more details. */ + /** Requests install of the module. See {@link ModuleInstallerImpl#install} for more details. */ public void install(OnModuleInstallFinishedListener onFinishedListener) { assert !isInstalled(); - ModuleInstaller.install(mName, onFinishedListener); + ModuleInstaller.getInstance().install(mName, onFinishedListener); } /** - * Requests deferred install of the module. See {@link ModuleInstaller#installDeferred} for + * Requests deferred install of the module. See {@link ModuleInstallerImpl#installDeferred} for * more details. */ public void installDeferred() { - ModuleInstaller.installDeferred(mName); + ModuleInstaller.getInstance().installDeferred(mName); } /** @@ -85,7 +85,7 @@ public T getImpl() { assert isInstalled(); if (mImpl == null) { - ModuleInstaller.init(); + ModuleInstaller.getInstance().init(); // Accessing classes in the module may cause its DEX file to be loaded. And on some // devices that causes a read mode violation. try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
diff --git a/components/module_installer/android/java/src-common/org/chromium/components/module_installer/ModuleInstaller.java b/components/module_installer/android/java/src-common/org/chromium/components/module_installer/ModuleInstaller.java new file mode 100644 index 0000000..b5083a5 --- /dev/null +++ b/components/module_installer/android/java/src-common/org/chromium/components/module_installer/ModuleInstaller.java
@@ -0,0 +1,63 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.module_installer; + +import android.content.Context; + +import org.chromium.base.VisibleForTesting; + +/** + * This interface contains all the necessary methods to orchestrate the installation of dynamic + * feature modules (DFMs). + */ +public interface ModuleInstaller { + /** Returns the singleton instance from the correct implementation. */ + static ModuleInstaller getInstance() { + return ModuleInstallerImpl.getInstance(); + } + + @VisibleForTesting + static void setInstanceForTesting(ModuleInstaller moduleInstaller) { + ModuleInstallerImpl.setInstanceForTesting(moduleInstaller); + } + + /** Needs to be called before trying to access a module. */ + default void init() {} + + /** + * Needs to be called in attachBaseContext of the activities that want to have access to + * splits prior to application restart. + * + * For details, see: + * https://developer.android.com/reference/com/google/android/play/core/splitcompat/SplitCompat.html#install(android.content.Context) + */ + default void initActivity(Context context) {} + + /** + * Records via UMA all modules that have been requested and are currently installed. The intent + * is to measure the install penetration of each module. + */ + default void recordModuleAvailability() {} + + /** Writes fully installed and emulated modules to crash keys. */ + default void updateCrashKeys() {} + + /** + * Requests the install of a module. The install will be performed asynchronously. + * + * @param moduleName Name of the module as defined in GN. + * @param onFinishedListener Listener to be called once installation is finished. + */ + default void install(String moduleName, OnModuleInstallFinishedListener onFinishedListener) {} + + /** + * Asynchronously installs module in the background when on unmetered connection and charging. + * Install is best effort and may fail silently. Upon success, the module will only be available + * after Chrome restarts. + * + * @param moduleName Name of the module. + */ + default void installDeferred(String moduleName) {} +}
diff --git a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstallerImpl.java similarity index 64% rename from components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java rename to components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstallerImpl.java index 5b73565..1fbc3c5 100644 --- a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java +++ b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstallerImpl.java
@@ -30,53 +30,54 @@ import java.util.TreeSet; /** Installs dynamic feature modules (DFMs). */ -public class ModuleInstaller { +public class ModuleInstallerImpl implements ModuleInstaller { /** Command line switch for activating the fake backend. */ private static final String FAKE_FEATURE_MODULE_INSTALL = "fake-feature-module-install"; - private static final Map<String, List<OnModuleInstallFinishedListener>> sModuleNameListenerMap = + private static ModuleInstaller sInstance = new ModuleInstallerImpl(); + private static boolean sAppContextSplitCompatted; + private final Map<String, List<OnModuleInstallFinishedListener>> mModuleNameListenerMap = new HashMap<>(); - private static ModuleInstallerBackend sBackend; - private static boolean sSplitCompatted; + private ModuleInstallerBackend mBackend; - /** Needs to be called before trying to access a module. */ - public static void init() { - if (sSplitCompatted) return; + /** Returns the singleton instance. */ + public static ModuleInstaller getInstance() { + return sInstance; + } + + public static void setInstanceForTesting(ModuleInstaller moduleInstaller) { + sInstance = moduleInstaller; + } + + @Override + public void init() { + if (sAppContextSplitCompatted) return; // SplitCompat.install may copy modules into Chrome's internal folder or clean them up. try (StrictModeContext ignored = StrictModeContext.allowDiskWrites()) { SplitCompat.install(ContextUtils.getApplicationContext()); - sSplitCompatted = true; + sAppContextSplitCompatted = true; } // SplitCompat.install may add emulated modules. Thus, update crash keys. updateCrashKeys(); } - /** - * Needs to be called in attachBaseContext of the activities that want to have access to - * splits prior to application restart. - * - * For details, see: - * https://developer.android.com/reference/com/google/android/play/core/splitcompat/SplitCompat.html#install(android.content.Context) - */ - public static void initActivity(Context context) { + @Override + public void initActivity(Context context) { SplitCompat.install(context); } - /** - * Records via UMA all modules that have been requested and are currently installed. The intent - * is to measure the install penetration of each module. - */ - public static void recordModuleAvailability() { + @Override + public void recordModuleAvailability() { if (!CommandLine.getInstance().hasSwitch(FAKE_FEATURE_MODULE_INSTALL)) { PlayCoreModuleInstallerBackend.recordModuleAvailability(); } } - /** Writes fully installed and emulated modules to crash keys. */ - public static void updateCrashKeys() { + @Override + public void updateCrashKeys() { Context context = ContextUtils.getApplicationContext(); // Get modules that are fully installed as split APKs (excluding base which is always - // intalled). Tree set to have ordered and, thus, deterministic results. + // installed). Tree set to have ordered and, thus, deterministic results. Set<String> fullyInstalledModules = new TreeSet<>(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Split APKs are only supported on Android L+. @@ -97,7 +98,7 @@ // emulation of later modules won't work. If splitcompat has not been called no modules are // emulated. Therefore, use an empty set in that case. Set<String> emulatedModules = new TreeSet<>(); - if (sSplitCompatted) { + if (sAppContextSplitCompatted) { emulatedModules.addAll( SplitInstallManagerFactory.create(context).getInstalledModules()); emulatedModules.removeAll(fullyInstalledModules); @@ -109,21 +110,15 @@ CrashKeyIndex.EMULATED_MODULES, encodeCrashKeyValue(emulatedModules)); } - /** - * Requests the install of a module. The install will be performed asynchronously. - * - * @param moduleName Name of the module as defined in GN. - * @param onFinishedListener Listener to be called once installation is finished. - */ - public static void install( - String moduleName, OnModuleInstallFinishedListener onFinishedListener) { + @Override + public void install(String moduleName, OnModuleInstallFinishedListener onFinishedListener) { ThreadUtils.assertOnUiThread(); - if (!sModuleNameListenerMap.containsKey(moduleName)) { - sModuleNameListenerMap.put(moduleName, new LinkedList<>()); + if (!mModuleNameListenerMap.containsKey(moduleName)) { + mModuleNameListenerMap.put(moduleName, new LinkedList<>()); } List<OnModuleInstallFinishedListener> onFinishedListeners = - sModuleNameListenerMap.get(moduleName); + mModuleNameListenerMap.get(moduleName); onFinishedListeners.add(onFinishedListener); if (onFinishedListeners.size() > 1) { // Request is already running. @@ -132,56 +127,50 @@ getBackend().install(moduleName); } - /** - * Asynchronously installs module in the background when on unmetered connection and charging. - * Install is best effort and may fail silently. Upon success, the module will only be available - * after Chrome restarts. - * - * @param moduleName Name of the module. - */ - public static void installDeferred(String moduleName) { + @Override + public void installDeferred(String moduleName) { ThreadUtils.assertOnUiThread(); getBackend().installDeferred(moduleName); } - private static void onFinished(boolean success, List<String> moduleNames) { + private void onFinished(boolean success, List<String> moduleNames) { ThreadUtils.assertOnUiThread(); for (String moduleName : moduleNames) { List<OnModuleInstallFinishedListener> onFinishedListeners = - sModuleNameListenerMap.get(moduleName); + mModuleNameListenerMap.get(moduleName); if (onFinishedListeners == null) continue; for (OnModuleInstallFinishedListener listener : onFinishedListeners) { listener.onFinished(success); } - sModuleNameListenerMap.remove(moduleName); + mModuleNameListenerMap.remove(moduleName); } - if (sModuleNameListenerMap.isEmpty()) { - sBackend.close(); - sBackend = null; + if (mModuleNameListenerMap.isEmpty()) { + mBackend.close(); + mBackend = null; } updateCrashKeys(); } - private static ModuleInstallerBackend getBackend() { - if (sBackend == null) { - ModuleInstallerBackend.OnFinishedListener listener = ModuleInstaller::onFinished; - sBackend = CommandLine.getInstance().hasSwitch(FAKE_FEATURE_MODULE_INSTALL) + private ModuleInstallerBackend getBackend() { + if (mBackend == null) { + ModuleInstallerBackend.OnFinishedListener listener = this::onFinished; + mBackend = CommandLine.getInstance().hasSwitch(FAKE_FEATURE_MODULE_INSTALL) ? new FakeModuleInstallerBackend(listener) : new PlayCoreModuleInstallerBackend(listener); } - return sBackend; + return mBackend; } - private static String encodeCrashKeyValue(Set<String> moduleNames) { + private String encodeCrashKeyValue(Set<String> moduleNames) { if (moduleNames.isEmpty()) return "<none>"; // Values with dots are interpreted as URLs. Some module names have dots in them. Make sure // they don't get sanitized. return TextUtils.join(",", moduleNames).replace('.', '$'); } - private ModuleInstaller() {} + private ModuleInstallerImpl() {} }
diff --git a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java index 00b1712..b64387c 100644 --- a/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java +++ b/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java
@@ -20,7 +20,6 @@ import org.chromium.base.Log; import org.chromium.base.metrics.CachedMetrics.EnumeratedHistogramSample; import org.chromium.base.metrics.RecordHistogram; -import org.chromium.components.module_installer.ModuleInstallerBackend.OnFinishedListener; import java.util.Collections; import java.util.HashMap; @@ -93,7 +92,7 @@ /** Records via UMA all modules that have been requested and are currently installed. */ public static void recordModuleAvailability() { // MUST call init before creating a SplitInstallManager. - ModuleInstaller.init(); + ModuleInstaller.getInstance().init(); SharedPreferences prefs = ContextUtils.getAppSharedPreferences(); Set<String> requestedModules = new HashSet<>(); requestedModules.addAll( @@ -128,7 +127,7 @@ public PlayCoreModuleInstallerBackend(OnFinishedListener listener) { super(listener); // MUST call init before creating a SplitInstallManager. - ModuleInstaller.init(); + ModuleInstaller.getInstance().init(); mManager = SplitInstallManagerFactory.create(ContextUtils.getApplicationContext()); mManager.registerListener(this); }
diff --git a/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java b/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java deleted file mode 100644 index f88b9ca..0000000 --- a/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java +++ /dev/null
@@ -1,36 +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. - -package org.chromium.components.module_installer; - -import android.content.Context; - -import org.chromium.base.VisibleForTesting; - -/** Dummy fallback of ModuleInstaller for APK builds. */ -public class ModuleInstaller { - public static void init() {} - - public static void initActivity(Context context) {} - - public static void recordModuleAvailability() {} - - public static void updateCrashKeys(){}; - - public static void install( - String moduleName, OnModuleInstallFinishedListener onFinishedListener) { - throw new UnsupportedOperationException("Cannot install module if APK"); - } - - public static void installDeferred(String moduleName) { - throw new UnsupportedOperationException("Cannot deferred install module if APK"); - } - - @VisibleForTesting - public static boolean didRequestDeferred(String moduleName) { - throw new UnsupportedOperationException(); - } - - private ModuleInstaller() {} -}
diff --git a/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java b/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java new file mode 100644 index 0000000..f4bca10 --- /dev/null +++ b/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java
@@ -0,0 +1,32 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.module_installer; + +/** Dummy fallback of ModuleInstaller for APK builds. */ +public class ModuleInstallerImpl implements ModuleInstaller { + /** A valid singleton instance is necessary for tests to swap it out. */ + private static ModuleInstaller sInstance = new ModuleInstallerImpl(); + + /** Returns the singleton instance. */ + public static ModuleInstaller getInstance() { + return sInstance; + } + + public static void setInstanceForTesting(ModuleInstaller moduleInstaller) { + sInstance = moduleInstaller; + } + + @Override + public void install(String moduleName, OnModuleInstallFinishedListener onFinishedListener) { + throw new UnsupportedOperationException("Cannot install module if APK"); + } + + @Override + public void installDeferred(String moduleName) { + throw new UnsupportedOperationException("Cannot deferred install module if APK"); + } + + private ModuleInstallerImpl() {} +}
diff --git a/components/module_installer/android/java/src-test/org/chromium/components/module_installer/ModuleInstaller.java b/components/module_installer/android/java/src-test/org/chromium/components/module_installer/ModuleInstaller.java deleted file mode 100644 index 02b8519..0000000 --- a/components/module_installer/android/java/src-test/org/chromium/components/module_installer/ModuleInstaller.java +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.module_installer; - -import android.content.Context; - -import org.chromium.base.VisibleForTesting; - -import java.util.HashSet; -import java.util.Set; - -/** Mock ModuleInstaller for use in tests. */ -public class ModuleInstaller { - private static Set<String> sModulesRequestedDeffered = new HashSet<>(); - - public static void init() {} - - public static void initActivity(Context context) {} - - public static void recordModuleAvailability() {} - - public static void updateCrashKeys(){}; - - public static void install( - String moduleName, OnModuleInstallFinishedListener onFinishedListener) {} - - public static void installDeferred(String moduleName) { - sModulesRequestedDeffered.add(moduleName); - } - - @VisibleForTesting - public static boolean didRequestDeferred(String moduleName) { - return sModulesRequestedDeffered.contains(moduleName); - } - - private ModuleInstaller() {} -}
diff --git a/components/module_installer/android/javatests/src/org/chromium/components/module_installer/ModuleInstallerRule.java b/components/module_installer/android/javatests/src/org/chromium/components/module_installer/ModuleInstallerRule.java new file mode 100644 index 0000000..f9a9418 --- /dev/null +++ b/components/module_installer/android/javatests/src/org/chromium/components/module_installer/ModuleInstallerRule.java
@@ -0,0 +1,33 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.module_installer; + +import org.junit.rules.ExternalResource; + +/** + * This rule allows the caller to specify their own {@link ModuleInstaller} for the duration of the + * test and resets it back to what it was before. + * + * TODO(wnwen): This should eventually become ModuleConfigRule. + */ +public class ModuleInstallerRule extends ExternalResource { + private ModuleInstaller mOldModuleInstaller; + private final ModuleInstaller mMockModuleInstaller; + + public ModuleInstallerRule(ModuleInstaller mockModuleInstaller) { + mMockModuleInstaller = mockModuleInstaller; + } + + @Override + protected void before() { + mOldModuleInstaller = ModuleInstaller.getInstance(); + ModuleInstaller.setInstanceForTesting(mMockModuleInstaller); + } + + @Override + protected void after() { + ModuleInstaller.setInstanceForTesting(mOldModuleInstaller); + } +}
diff --git a/components/omnibox/browser/omnibox_popup_model_unittest.cc b/components/omnibox/browser/omnibox_popup_model_unittest.cc index 2a65f52c..1273add 100644 --- a/components/omnibox/browser/omnibox_popup_model_unittest.cc +++ b/components/omnibox/browser/omnibox_popup_model_unittest.cc
@@ -96,6 +96,9 @@ } TEST_F(OmniboxPopupModelTest, PopupPositionChanging) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(omnibox::kOmniboxWrapPopupPosition); + ACMatches matches; for (size_t i = 0; i < 3; ++i) { AutocompleteMatch match(nullptr, 1000, false, @@ -125,7 +128,7 @@ model()->OnUpOrDownKeyPressed(-3); EXPECT_EQ(0u, model()->popup_model()->selected_line()); - base::test::ScopedFeatureList feature_list; + feature_list.Reset(); feature_list.InitAndEnableFeature(omnibox::kOmniboxWrapPopupPosition); // Test wrapping. model()->OnUpOrDownKeyPressed(-1);
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc index 8ac55bf8..8dda09e9d 100644 --- a/components/omnibox/common/omnibox_features.cc +++ b/components/omnibox/common/omnibox_features.cc
@@ -118,10 +118,10 @@ #endif }; -// Feature that enables wrapping the Omnibox position between top and -// bottom. -const base::Feature kOmniboxWrapPopupPosition{ - "OmniboxWrapPopupPosition", base::FEATURE_DISABLED_BY_DEFAULT}; +// Feature that enables wrapping the Omnibox position between top and bottom. +// The feature is enabled by default, but remains as a kill-switch. +const base::Feature kOmniboxWrapPopupPosition{"OmniboxWrapPopupPosition", + base::FEATURE_ENABLED_BY_DEFAULT}; // Feature used to reverse the sense of the tab switch button. Selecting the // suggestion will switch to the tab, while the button will navigate @@ -282,6 +282,11 @@ const base::Feature kOmniboxDisableInstantExtendedLimit{ "OmniboxDisableInstantExtendedLimit", base::FEATURE_DISABLED_BY_DEFAULT}; +// Show the search engine logo in the omnibox on Android (desktop already does +// this). +const base::Feature kOmniboxSearchEngineLogo{"OmniboxSearchEngineLogo", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Feature to configure on-focus suggestions provided by ZeroSuggestProvider. // This feature's main job is to contain some field trial parameters such as: // - "ZeroSuggestVariant" configures the per-page-classification mode of
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h index d95912c..a7c23ff 100644 --- a/components/omnibox/common/omnibox_features.h +++ b/components/omnibox/common/omnibox_features.h
@@ -51,6 +51,7 @@ extern const base::Feature kOmniboxPopupShortcutIconsInZeroState; extern const base::Feature kOmniboxMaterialDesignWeatherIcons; extern const base::Feature kOmniboxDisableInstantExtendedLimit; +extern const base::Feature kOmniboxSearchEngineLogo; // On-Focus Suggestions a.k.a. ZeroSuggest. extern const base::Feature kOnFocusSuggestions;
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc index 14d42c2..e498e9f 100644 --- a/components/password_manager/core/browser/new_password_form_manager.cc +++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -143,6 +143,7 @@ observed_form_ = observed_form; metrics_recorder_->RecordFormSignature(CalculateFormSignature(observed_form)); form_fetcher_->AddConsumer(this); + votes_uploader_.StoreInitialFieldValues(observed_form); } NewPasswordFormManager::NewPasswordFormManager(
diff --git a/components/password_manager/core/browser/votes_uploader.cc b/components/password_manager/core/browser/votes_uploader.cc index bdd4ee5..97b30d3 100644 --- a/components/password_manager/core/browser/votes_uploader.cc +++ b/components/password_manager/core/browser/votes_uploader.cc
@@ -7,14 +7,18 @@ #include <ctype.h> #include <algorithm> - +#include <utility> +#include "base/hash/hash.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" +#include "base/strings/utf_string_conversions.h" #include "components/autofill/core/browser/autofill_download_manager.h" +#include "components/autofill/core/browser/autofill_field.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/randomized_encoder.h" #include "components/autofill/core/common/form_data.h" +#include "components/autofill/core/common/form_field_data.h" #include "components/password_manager/core/browser/browser_save_password_progress_logger.h" #include "components/password_manager/core/browser/password_manager_client.h" #include "components/password_manager/core/browser/password_manager_util.h" @@ -23,6 +27,7 @@ using autofill::AutofillField; using autofill::AutofillUploadContents; using autofill::FormData; +using autofill::FormFieldData; using autofill::FormStructure; using autofill::PasswordForm; using autofill::RandomizedEncoder; @@ -35,6 +40,8 @@ namespace password_manager { namespace { +// Number of distinct low-entropy hash values. +constexpr uint32_t kNumberOfLowEntropyHashValues = 64; // Contains all special symbols considered for password-generation. constexpr char kSpecialSymbols[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; @@ -100,14 +107,13 @@ field->vote_type() != AutofillUploadContents::Field::NO_INFORMATION); } - ServerFieldTypeSet types; types.insert(type); field->set_possible_types(types); } } -// Returns true iff |credentials| has the same password as an entry in |matches| +// Returns true if |credentials| has the same password as an entry in |matches| // which doesn't have a username. bool IsAddingUsernameToExistingMatch( const PasswordForm& credentials, @@ -154,6 +160,11 @@ return symbols[base::RandGenerator(symbols.size())]; } +size_t GetLowEntropyHashValue(const base::string16& value) { + return base::PersistentHash(base::UTF16ToUTF8(value)) % + kNumberOfLowEntropyHashValues; +} + } // namespace VotesUploader::VotesUploader(PasswordManagerClient* client, @@ -398,11 +409,33 @@ form_structure.set_randomized_encoder( RandomizedEncoder::Create(client_->GetPrefs())); + SetInitialHashValueOfUsernameField( + form_to_upload.username_element_renderer_id, &form_structure); + download_manager->StartUploadRequest( form_structure, false /* was_autofilled */, available_field_types, std::string(), true /* observed_submission */, nullptr /* prefs */); } +void VotesUploader::SetInitialHashValueOfUsernameField( + uint32_t username_element_renderer_id, + FormStructure* form_structure) { + auto it = initial_values_.find(username_element_renderer_id); + + if (it == initial_values_.end() || it->second.empty()) + return; + + for (const auto& field : *form_structure) { + if (field && field->unique_renderer_id == username_element_renderer_id) { + const base::string16 form_signature = + base::UTF8ToUTF16(form_structure->FormSignatureAsStr()); + const base::string16 seeded_input = it->second.append(form_signature); + field->set_initial_value_hash(GetLowEntropyHashValue(seeded_input)); + break; + } + } +} + void VotesUploader::AddGeneratedVote(FormStructure* form_structure) { DCHECK(form_structure); DCHECK(generation_popup_was_shown_); @@ -571,4 +604,13 @@ form_structure->set_password_length_vote(randomized_length); } +void VotesUploader::StoreInitialFieldValues( + const autofill::FormData& observed_form) { + for (const auto& field : observed_form.fields) { + if (!field.value.empty()) + initial_values_.insert( + std::make_pair(field.unique_renderer_id, field.value)); + } +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/votes_uploader.h b/components/password_manager/core/browser/votes_uploader.h index 2eb9565..abe6879 100644 --- a/components/password_manager/core/browser/votes_uploader.h +++ b/components/password_manager/core/browser/votes_uploader.h
@@ -87,6 +87,17 @@ void GeneratePasswordAttributesVote(const base::string16& password_value, autofill::FormStructure* form_structure); + // Stores the |unique_renderer_id| and |values| of the fields in + // |observed_form| to |initial_field_values_|. + void StoreInitialFieldValues(const autofill::FormData& observed_form); + + // Sets the low-entropy hash value of the values stored in |initial_values_| + // for the detected |username| field to the corresponding field in + // |form_structure|. + void SetInitialHashValueOfUsernameField( + uint32_t username_element_renderer_id, + autofill::FormStructure* form_structure); + bool get_generation_popup_was_shown() const { return generation_popup_was_shown_; } @@ -197,6 +208,10 @@ // Whether this form has a generated password changed by user. bool generated_password_changed_ = false; + + // Maps an |unique_renderer_id| to the initial value of the fields of an + // observed form. + std::map<uint32_t, base::string16> initial_values_; }; } // namespace password_manager
diff --git a/components/password_manager/core/browser/votes_uploader_unittest.cc b/components/password_manager/core/browser/votes_uploader_unittest.cc index e272850..a72bbf42 100644 --- a/components/password_manager/core/browser/votes_uploader_unittest.cc +++ b/components/password_manager/core/browser/votes_uploader_unittest.cc
@@ -7,6 +7,7 @@ #include <string> #include <utility> +#include "base/hash/hash.h" #include "base/optional.h" #include "base/rand_util.h" #include "base/strings/string16.h" @@ -15,6 +16,7 @@ #include "base/test/scoped_task_environment.h" #include "components/autofill/core/browser/autofill_download_manager.h" #include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/common/form_data.h" #include "components/password_manager/core/browser/stub_password_manager_client.h" #include "components/password_manager/core/browser/vote_uploads_test_matchers.h" #include "components/prefs/pref_registry_simple.h" @@ -22,12 +24,16 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using autofill::AutofillDownloadManager; using autofill::CONFIRMATION_PASSWORD; +using autofill::FormData; using autofill::FormFieldData; using autofill::FormStructure; using autofill::NEW_PASSWORD; using autofill::PASSWORD; +using autofill::PasswordAttribute; using autofill::PasswordForm; +using autofill::ServerFieldType; using autofill::ServerFieldTypeSet; using autofill::mojom::SubmissionIndicatorEvent; using base::ASCIIToUTF16; @@ -41,9 +47,9 @@ namespace { constexpr int kNumberOfPasswordAttributes = - static_cast<int>(autofill::PasswordAttribute::kPasswordAttributesCount); + static_cast<int>(PasswordAttribute::kPasswordAttributesCount); -class MockAutofillDownloadManager : public autofill::AutofillDownloadManager { +class MockAutofillDownloadManager : public AutofillDownloadManager { public: MockAutofillDownloadManager() : AutofillDownloadManager(nullptr, &fake_observer) {} @@ -51,7 +57,7 @@ MOCK_METHOD6(StartUploadRequest, bool(const FormStructure&, bool, - const autofill::ServerFieldTypeSet&, + const ServerFieldTypeSet&, const std::string&, bool, PrefService*)); @@ -69,8 +75,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient { public: - MOCK_METHOD0(GetAutofillDownloadManager, - autofill::AutofillDownloadManager*()); + MOCK_METHOD0(GetAutofillDownloadManager, AutofillDownloadManager*()); }; } // namespace @@ -166,6 +171,52 @@ form_to_upload_, submitted_form_, PASSWORD, login_form_signature_)); } +TEST_F(VotesUploaderTest, InitialValueDetection) { + // Tests if the initial value of the (predicted to be the) username field + // in |form_data| is persistently stored and if it's low-entropy hash is + // correctly written to the corresponding field in the |form_structure|. + // Note that the value of the username field is deliberately altered before + // the |form_structure| is generated from |form_data| to test the persistence. + base::string16 prefilled_username = ASCIIToUTF16("prefilled_username"); + uint32_t username_field_renderer_id = 123456; + const uint32_t kNumberOfHashValues = 64; + FormData form_data; + + FormFieldData username_field; + username_field.value = prefilled_username; + username_field.unique_renderer_id = username_field_renderer_id; + + FormFieldData other_field; + other_field.value = ASCIIToUTF16("some_field"); + other_field.unique_renderer_id = 3234; + + form_data.fields = {other_field, username_field}; + + VotesUploader votes_uploader(&client_, true); + votes_uploader.StoreInitialFieldValues(form_data); + + form_data.fields.at(1).value = ASCIIToUTF16("user entered value"); + FormStructure form_structure(form_data); + + PasswordForm password_form; + password_form.username_element_renderer_id = username_field_renderer_id; + + votes_uploader.SetInitialHashValueOfUsernameField(username_field_renderer_id, + &form_structure); + + const uint32_t expected_hash = 1377800651 % kNumberOfHashValues; + + int found_fields = 0; + for (auto& f : form_structure) { + if (f->unique_renderer_id == username_field_renderer_id) { + found_fields++; + ASSERT_TRUE(f->initial_value_hash()); + EXPECT_EQ(f->initial_value_hash().value(), expected_hash); + } + } + EXPECT_EQ(found_fields, 1); +} + TEST_F(VotesUploaderTest, GeneratePasswordAttributesVote) { VotesUploader votes_uploader(&client_, true); // Checks that randomization distorts information about present and missed @@ -183,8 +234,8 @@ if (password_value.empty()) continue; - autofill::FormData form; - autofill::FormStructure form_structure(form); + FormData form; + FormStructure form_structure(form); int reported_false[kNumberOfPasswordAttributes] = {0, 0, 0, 0}; int reported_true[kNumberOfPasswordAttributes] = {0, 0, 0, 0}; @@ -196,7 +247,7 @@ for (int i = 0; i < kNumberOfRuns; ++i) { votes_uploader.GeneratePasswordAttributesVote(password_value, &form_structure); - base::Optional<std::pair<autofill::PasswordAttribute, bool>> vote = + base::Optional<std::pair<PasswordAttribute, bool>> vote = form_structure.get_password_attributes_vote_for_testing(); int attribute_index = static_cast<int>(vote->first); if (vote->second) @@ -242,18 +293,18 @@ const int kNumberOfRuns = 2000; const int kSpecialSymbolsAttribute = 3; - autofill::FormData form; + FormData form; int correct_symbol_reported = 0; int wrong_symbol_reported = 0; int number_of_symbol_votes = 0; for (int i = 0; i < kNumberOfRuns; ++i) { - autofill::FormStructure form_structure(form); + FormStructure form_structure(form); votes_uploader.GeneratePasswordAttributesVote(password_value, &form_structure); - base::Optional<std::pair<autofill::PasswordAttribute, bool>> vote = + base::Optional<std::pair<PasswordAttribute, bool>> vote = form_structure.get_password_attributes_vote_for_testing(); // Continue if the vote is not about special symbols or implies that no @@ -279,12 +330,12 @@ TEST_F(VotesUploaderTest, GeneratePasswordAttributesVote_OneCharacterPassword) { // |VotesUploader::GeneratePasswordAttributesVote| shouldn't crash if a // password has only one character. - autofill::FormData form; - autofill::FormStructure form_structure(form); + FormData form; + FormStructure form_structure(form); VotesUploader votes_uploader(&client_, true); votes_uploader.GeneratePasswordAttributesVote(ASCIIToUTF16("1"), &form_structure); - base::Optional<std::pair<autofill::PasswordAttribute, bool>> vote = + base::Optional<std::pair<PasswordAttribute, bool>> vote = form_structure.get_password_attributes_vote_for_testing(); EXPECT_TRUE(vote.has_value()); size_t reported_length = @@ -293,14 +344,14 @@ } TEST_F(VotesUploaderTest, GeneratePasswordAttributesVote_AllAsciiCharacters) { - autofill::FormData form; - autofill::FormStructure form_structure(form); + FormData form; + FormStructure form_structure(form); VotesUploader votes_uploader(&client_, true); votes_uploader.GeneratePasswordAttributesVote( base::UTF8ToUTF16("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr" "stuvwxyz!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"), &form_structure); - base::Optional<std::pair<autofill::PasswordAttribute, bool>> vote = + base::Optional<std::pair<PasswordAttribute, bool>> vote = form_structure.get_password_attributes_vote_for_testing(); EXPECT_TRUE(vote.has_value()); } @@ -312,12 +363,12 @@ {"пароль1", "パスワード", "münchen", "סיסמה-A", "Σ-12345", "գաղտնաբառըTTT", "Slaptažodis", "密碼", "كلمهالسر", "mậtkhẩu!", "ລະຫັດຜ່ານ-l", "စကားဝှက်ကို3", "პაროლი", "पारण शब्द"}) { - autofill::FormData form; - autofill::FormStructure form_structure(form); + FormData form; + FormStructure form_structure(form); VotesUploader votes_uploader(&client_, true); votes_uploader.GeneratePasswordAttributesVote(base::UTF8ToUTF16(password), &form_structure); - base::Optional<std::pair<autofill::PasswordAttribute, bool>> vote = + base::Optional<std::pair<PasswordAttribute, bool>> vote = form_structure.get_password_attributes_vote_for_testing(); EXPECT_FALSE(vote.has_value()) << password;
diff --git a/components/payments/content/BUILD.gn b/components/payments/content/BUILD.gn index a38cd36..1c92e1b 100644 --- a/components/payments/content/BUILD.gn +++ b/components/payments/content/BUILD.gn
@@ -96,6 +96,7 @@ "//components/payments/content/icon", "//components/payments/content/utility", "//components/payments/core", + "//components/payments/core:error_strings", "//components/strings", "//components/webdata/common", "//content/public/browser",
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestDownloader.java b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestDownloader.java index 6d8dbfb..897167f 100644 --- a/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestDownloader.java +++ b/components/payments/content/android/java/src/org/chromium/components/payments/PaymentManifestDownloader.java
@@ -35,9 +35,13 @@ @CalledByNative("ManifestDownloadCallback") void onWebAppManifestDownloadSuccess(String content); - /** Called on failed download. */ + /** + * Called on failed download. + * + * @param errorMessage The error message, which could be empty or null. + */ @CalledByNative("ManifestDownloadCallback") - void onManifestDownloadFailure(); + void onManifestDownloadFailure(String errorMessage); } private long mNativeObject;
diff --git a/components/payments/content/android/payment_manifest_downloader_android.cc b/components/payments/content/android/payment_manifest_downloader_android.cc index 9aa99568..bc4a9ef 100644 --- a/components/payments/content/android/payment_manifest_downloader_android.cc +++ b/components/payments/content/android/payment_manifest_downloader_android.cc
@@ -29,11 +29,14 @@ ~DownloadCallback() {} void OnPaymentMethodManifestDownload(const GURL& url_after_redirects, - const std::string& content) { + const std::string& content, + const std::string& error_message) { JNIEnv* env = base::android::AttachCurrentThread(); if (content.empty()) { - Java_ManifestDownloadCallback_onManifestDownloadFailure(env, jcallback_); + Java_ManifestDownloadCallback_onManifestDownloadFailure( + env, jcallback_, + base::android::ConvertUTF8ToJavaString(env, error_message)); } else { Java_ManifestDownloadCallback_onPaymentMethodManifestDownloadSuccess( env, jcallback_, @@ -42,11 +45,14 @@ } void OnWebAppManifestDownload(const GURL& url_after_redirects, - const std::string& content) { + const std::string& content, + const std::string& error_message) { JNIEnv* env = base::android::AttachCurrentThread(); if (content.empty()) { - Java_ManifestDownloadCallback_onManifestDownloadFailure(env, jcallback_); + Java_ManifestDownloadCallback_onManifestDownloadFailure( + env, jcallback_, + base::android::ConvertUTF8ToJavaString(env, error_message)); } else { Java_ManifestDownloadCallback_onWebAppManifestDownloadSuccess( env, jcallback_,
diff --git a/components/payments/content/installable_payment_app_crawler.cc b/components/payments/content/installable_payment_app_crawler.cc index 2dc98edc..c1bff8503 100644 --- a/components/payments/content/installable_payment_app_crawler.cc +++ b/components/payments/content/installable_payment_app_crawler.cc
@@ -7,9 +7,11 @@ #include <utility> #include "base/bind.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/task/post_task.h" #include "components/payments/content/icon/icon_size.h" +#include "components/payments/core/native_error_strings.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -103,7 +105,8 @@ void InstallablePaymentAppCrawler::OnPaymentMethodManifestDownloaded( const GURL& method_manifest_url, const GURL& method_manifest_url_after_redirects, - const std::string& content) { + const std::string& content, + const std::string& error_message) { // Enforced in PaymentManifestDownloader. DCHECK(net::registry_controlled_domains::SameDomainOrHost( method_manifest_url, method_manifest_url_after_redirects, @@ -111,6 +114,7 @@ number_of_payment_method_manifest_to_download_--; if (content.empty()) { + SetFirstError(error_message); FinishCrawlingPaymentAppsIfReady(); return; } @@ -148,11 +152,12 @@ if (!IsSameOriginWith(method_manifest_url_after_redirects, web_app_manifest_url)) { - log_.Error("Installable payment handler from \"" + - web_app_manifest_url.spec() + - "\" is not allowed for the method \"" + - method_manifest_url_after_redirects.spec() + - "\" because of different origin."); + std::string error_message = base::ReplaceStringPlaceholders( + errors::kCrossOriginWebAppManifestNotAllowed, + {web_app_manifest_url.spec(), + method_manifest_url_after_redirects.spec()}, + nullptr); + SetFirstError(error_message); continue; } @@ -182,7 +187,8 @@ const GURL& method_manifest_url, const GURL& web_app_manifest_url, const GURL& web_app_manifest_url_after_redirects, - const std::string& content) { + const std::string& content, + const std::string& error_message) { #if DCHECK_IS_ON() GURL::Replacements replacements; if (ignore_port_in_origin_comparison_for_testing_) @@ -196,6 +202,7 @@ number_of_web_app_manifest_to_download_--; if (content.empty()) { + SetFirstError(error_message); FinishCrawlingPaymentAppsIfReady(); return; } @@ -233,13 +240,8 @@ if (app_info == nullptr) return false; - std::string log_prefix = "Web app manifest \"" + web_app_manifest_url.spec() + - "\" for payment method manifest \"" + - method_manifest_url.spec() + "\": "; if (app_info->sw_js_url.empty() || !base::IsStringUTF8(app_info->sw_js_url)) { - log_.Error(log_prefix + - "The installable payment handler's service worker JavaScript " - "file URL is not a non-empty UTF8 string."); + SetFirstError(errors::kInvalidServiceWorkerUrl); return false; } @@ -247,29 +249,23 @@ if (!GURL(app_info->sw_js_url).is_valid()) { GURL absolute_url = web_app_manifest_url.Resolve(app_info->sw_js_url); if (!absolute_url.is_valid()) { - log_.Error(log_prefix + - "Failed to resolve the installable payment handler's service " - "worker JavaScript file URL \"" + - app_info->sw_js_url + "\"."); + SetFirstError(base::ReplaceStringPlaceholders( + errors::kCannotResolveServiceWorkerUrl, + {app_info->sw_js_url, web_app_manifest_url.spec()}, nullptr)); return false; } app_info->sw_js_url = absolute_url.spec(); } if (!IsSameOriginWith(web_app_manifest_url, GURL(app_info->sw_js_url))) { - log_.Error(log_prefix + - "Installable payment handler's service worker JavaScript file " - "URL \"" + - app_info->sw_js_url + - "\" is not allowed for the web app manifest file \"" + - web_app_manifest_url.spec() + "\" because of different origin."); + SetFirstError(base::ReplaceStringPlaceholders( + errors::kCrossOriginServiceWorkerUrlNotAllowed, + {app_info->sw_js_url, web_app_manifest_url.spec()}, nullptr)); return false; } if (!app_info->sw_scope.empty() && !base::IsStringUTF8(app_info->sw_scope)) { - log_.Error(log_prefix + - "The installable payment handler's service worker scope is not " - "a UTF8 string."); + SetFirstError(errors::kInvalidServiceWorkerScope); return false; } @@ -277,21 +273,18 @@ GURL absolute_scope = web_app_manifest_url.GetWithoutFilename().Resolve(app_info->sw_scope); if (!absolute_scope.is_valid()) { - log_.Error(log_prefix + - "Failed to resolve the installable payment handler's " - "registration scope \"" + - app_info->sw_scope + "\"."); + SetFirstError(base::ReplaceStringPlaceholders( + errors::kCannotResolveServiceWorkerScope, + {app_info->sw_scope, web_app_manifest_url.spec()}, nullptr)); return false; } app_info->sw_scope = absolute_scope.spec(); } if (!IsSameOriginWith(web_app_manifest_url, GURL(app_info->sw_scope))) { - log_.Error(log_prefix + - "Installable payment handler's registration scope \"" + - app_info->sw_scope + - "\" is not allowed for the web app manifest file \"" + - web_app_manifest_url.spec() + "\" because of different origin."); + SetFirstError(base::ReplaceStringPlaceholders( + errors::kCrossOriginServiceWorkerScopeNotAllowed, + {app_info->sw_scope, web_app_manifest_url.spec()}, nullptr)); return false; } @@ -299,16 +292,14 @@ if (!content::PaymentAppProvider::GetInstance()->IsValidInstallablePaymentApp( web_app_manifest_url, GURL(app_info->sw_js_url), GURL(app_info->sw_scope), &error_message)) { - log_.Error(log_prefix + error_message); + SetFirstError(error_message); return false; } // TODO(crbug.com/782270): Support multiple installable payment apps for a // payment method. if (installable_apps_.find(method_manifest_url) != installable_apps_.end()) { - log_.Error(log_prefix + - "Multiple installable payment handlers from for a single " - "payment method are not yet supported."); + SetFirstError(errors::kInstallingMultipleDefaultAppsNotSupported); return false; } @@ -333,7 +324,7 @@ const GURL& web_app_manifest_url, std::unique_ptr<std::vector<PaymentManifestParser::WebAppIcon>> icons) { if (icons == nullptr || icons->empty()) { - log_.Error( + log_.Warn( "No valid icon information for installable payment handler found in " "web app manifest \"" + web_app_manifest_url.spec() + "\" for payment handler manifest \"" + @@ -377,16 +368,16 @@ } if (manifest_icons.empty()) { - log_.Error("No valid icons found in web app manifest \"" + - web_app_manifest_url.spec() + - "\" for payment handler manifest \"" + - method_manifest_url.spec() + "\"."); + log_.Warn("No valid icons found in web app manifest \"" + + web_app_manifest_url.spec() + + "\" for payment handler manifest \"" + + method_manifest_url.spec() + "\"."); return; } // Stop if the web_contents is gone. if (web_contents() == nullptr) { - log_.Error( + log_.Warn( "Cannot download icons after the webpage has been closed (web app " "manifest \"" + web_app_manifest_url.spec() + "\" for payment handler manifest \"" + @@ -401,10 +392,10 @@ content::ManifestIconDownloader::kMaxWidthToHeightRatio, blink::Manifest::ImageResource::Purpose::ANY); if (!best_icon_url.is_valid()) { - log_.Error("No suitable icon found in web app manifest \"" + - web_app_manifest_url.spec() + - "\" for payment handler manifest \"" + - method_manifest_url.spec() + "\"."); + log_.Warn("No suitable icon found in web app manifest \"" + + web_app_manifest_url.spec() + + "\" for payment handler manifest \"" + + method_manifest_url.spec() + "\"."); return; } @@ -451,8 +442,15 @@ return; } - std::move(callback_).Run(std::move(installable_apps_)); + std::move(callback_).Run(std::move(installable_apps_), first_error_message_); std::move(finished_using_resources_).Run(); } +void InstallablePaymentAppCrawler::SetFirstError( + const std::string& error_message) { + log_.Error(error_message); + if (first_error_message_.empty()) + first_error_message_ = error_message; +} + } // namespace payments.
diff --git a/components/payments/content/installable_payment_app_crawler.h b/components/payments/content/installable_payment_app_crawler.h index 601667c9..78372308 100644 --- a/components/payments/content/installable_payment_app_crawler.h +++ b/components/payments/content/installable_payment_app_crawler.h
@@ -36,7 +36,8 @@ class InstallablePaymentAppCrawler : public content::WebContentsObserver { public: using FinishedCrawlingCallback = base::OnceCallback<void( - std::map<GURL, std::unique_ptr<WebAppInstallationInfo>>)>; + std::map<GURL, std::unique_ptr<WebAppInstallationInfo>>, + const std::string& error_message)>; // The owner of InstallablePaymentAppCrawler owns |downloader|, |parser| and // |cache|. They should live until |finished_using_resources| parameter to @@ -65,7 +66,8 @@ void OnPaymentMethodManifestDownloaded( const GURL& method_manifest_url, const GURL& method_manifest_url_after_redirects, - const std::string& content); + const std::string& content, + const std::string& error_message); void OnPaymentMethodManifestParsed( const GURL& method_manifest_url, const GURL& method_manifest_url_after_redirects, @@ -76,7 +78,8 @@ const GURL& method_manifest_url, const GURL& web_app_manifest_url, const GURL& web_app_manifest_url_after_redirects, - const std::string& content); + const std::string& content, + const std::string& error_message); void OnPaymentWebAppInstallationInfo( const GURL& method_manifest_url, const GURL& web_app_manifest_url, @@ -94,6 +97,7 @@ const GURL& web_app_manifest_url, const SkBitmap& icon); void FinishCrawlingPaymentAppsIfReady(); + void SetFirstError(const std::string& error_message); DeveloperConsoleLogger log_; PaymentManifestDownloader* downloader_; @@ -109,6 +113,10 @@ std::set<GURL> downloaded_web_app_manifests_; std::map<GURL, std::unique_ptr<WebAppInstallationInfo>> installable_apps_; + // The first error message (if any) to be forwarded to the merchant when + // rejecting the promise returned from PaymentRequest.show(). + std::string first_error_message_; + bool ignore_port_in_origin_comparison_for_testing_ = false; base::WeakPtrFactory<InstallablePaymentAppCrawler> weak_ptr_factory_;
diff --git a/components/payments/content/manifest_verifier.cc b/components/payments/content/manifest_verifier.cc index 550f9024..1600aa9 100644 --- a/components/payments/content/manifest_verifier.cc +++ b/components/payments/content/manifest_verifier.cc
@@ -144,7 +144,8 @@ manifests_to_download.size(); if (number_of_manifests_to_verify_ == 0) { RemoveInvalidPaymentApps(); - std::move(finished_verification_callback_).Run(std::move(apps_)); + std::move(finished_verification_callback_) + .Run(std::move(apps_), first_error_message_); std::move(finished_using_resources_callback_).Run(); return; } @@ -199,7 +200,8 @@ cached_manifest_urls_.insert(method_manifest_url); if (--number_of_manifests_to_verify_ == 0) { RemoveInvalidPaymentApps(); - std::move(finished_verification_callback_).Run(std::move(apps_)); + std::move(finished_verification_callback_) + .Run(std::move(apps_), first_error_message_); } } @@ -212,15 +214,19 @@ void ManifestVerifier::OnPaymentMethodManifestDownloaded( const GURL& method_manifest_url, const GURL& unused_method_manifest_url_after_redirects, - const std::string& content) { + const std::string& content, + const std::string& error_message) { DCHECK_LT(0U, number_of_manifests_to_download_); if (content.empty()) { + if (first_error_message_.empty()) + first_error_message_ = error_message; if (cached_manifest_urls_.find(method_manifest_url) == cached_manifest_urls_.end() && --number_of_manifests_to_verify_ == 0) { RemoveInvalidPaymentApps(); - std::move(finished_verification_callback_).Run(std::move(apps_)); + std::move(finished_verification_callback_) + .Run(std::move(apps_), first_error_message_); } if (--number_of_manifests_to_download_ == 0) @@ -256,7 +262,8 @@ if (--number_of_manifests_to_verify_ == 0) { RemoveInvalidPaymentApps(); - std::move(finished_verification_callback_).Run(std::move(apps_)); + std::move(finished_verification_callback_) + .Run(std::move(apps_), first_error_message_); } }
diff --git a/components/payments/content/manifest_verifier.h b/components/payments/content/manifest_verifier.h index 8292e0d..4a6ad23 100644 --- a/components/payments/content/manifest_verifier.h +++ b/components/payments/content/manifest_verifier.h
@@ -58,7 +58,8 @@ // remaining. If a payment handler does not have any valid payment method // names, then it's not included in the returned set of handlers. using VerifyCallback = - base::OnceCallback<void(content::PaymentAppProvider::PaymentApps)>; + base::OnceCallback<void(content::PaymentAppProvider::PaymentApps, + const std::string& error_message)>; // Creates the verifier and starts up the parser utility process. // The owner of ManifestVerifier owns |downloader|, |parser| and @@ -88,7 +89,8 @@ void OnPaymentMethodManifestDownloaded( const GURL& method_manifest_url, const GURL& unused_method_manifest_url_after_redirects, - const std::string& content); + const std::string& content, + const std::string& error_message); // Called when a manifest is parsed. void OnPaymentMethodManifestParsed( @@ -153,6 +155,10 @@ // Once this number reaches 0, the resource usage callback is invoked. size_t number_of_manifests_to_download_; + // The first error message (if any) to be forwarded to the merchant when + // rejecting the promise returned from PaymentRequest.show(). + std::string first_error_message_; + base::WeakPtrFactory<ManifestVerifier> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ManifestVerifier);
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc index 1771e48..40ee346 100644 --- a/components/payments/content/payment_request.cc +++ b/components/payments/content/payment_request.cc
@@ -240,7 +240,7 @@ if (!state_) { // SSL is not valid. Reject show with NotSupportedError, disconnect the // mojo pipe, and destroy this object. - AreRequestedMethodsSupportedCallback(false); + AreRequestedMethodsSupportedCallback(false, reject_show_error_message_); return; } @@ -480,7 +480,8 @@ } void PaymentRequest::AreRequestedMethodsSupportedCallback( - bool methods_supported) { + bool methods_supported, + const std::string& error_message) { if (methods_supported) { if (SatisfiesSkipUIConstraints()) Pay(); @@ -490,9 +491,8 @@ journey_logger_.SetNotShown( JourneyLogger::NOT_SHOWN_REASON_NO_SUPPORTED_PAYMENT_METHOD); client_->OnError(mojom::PaymentErrorReason::NOT_SUPPORTED, - !reject_show_error_message_.empty() - ? reject_show_error_message_ - : GetNotSupportedErrorMessage(spec_.get())); + GetNotSupportedErrorMessage(spec_.get()) + + (error_message.empty() ? "" : " " + error_message)); if (observer_for_testing_) observer_for_testing_->OnNotSupportedError(); OnConnectionTerminated();
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h index 33eb60e1..55f410e7 100644 --- a/components/payments/content/payment_request.h +++ b/components/payments/content/payment_request.h
@@ -156,7 +156,8 @@ bool has_enrolled_instrument); // The callback for PaymentRequestState::AreRequestedMethodsSupported. - void AreRequestedMethodsSupportedCallback(bool methods_supported); + void AreRequestedMethodsSupportedCallback(bool methods_supported, + const std::string& error_message); // Sends either HAS_ENROLLED_INSTRUMENT or HAS_NO_ENROLLED_INSTRUMENT to the // renderer, depending on |has_enrolled_instrument| value. Does not check
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc index 361769d..dc75de75 100644 --- a/components/payments/content/payment_request_state.cc +++ b/components/payments/content/payment_request_state.cc
@@ -94,9 +94,11 @@ const GURL& top_level_origin, const GURL& frame_origin, content::PaymentAppProvider::PaymentApps apps, - ServiceWorkerPaymentAppFactory::InstallablePaymentApps installable_apps) { + ServiceWorkerPaymentAppFactory::InstallablePaymentApps installable_apps, + const std::string& error_message) { number_of_pending_sw_payment_instruments_ = apps.size() + installable_apps.size(); + get_all_payment_apps_error_ = error_message; if (number_of_pending_sw_payment_instruments_ == 0U) { FinishedGetAllSWPaymentInstruments(); return; @@ -273,7 +275,7 @@ } void PaymentRequestState::AreRequestedMethodsSupported( - StatusCallback callback) { + MethodsSupportedCallback callback) { if (!get_all_instruments_finished_) { are_requested_methods_supported_callback_ = std::move(callback); return; @@ -286,10 +288,11 @@ } void PaymentRequestState::CheckRequestedMethodsSupported( - StatusCallback callback) { + MethodsSupportedCallback callback) { DCHECK(get_all_instruments_finished_); - std::move(callback).Run(are_requested_methods_supported_); + std::move(callback).Run(are_requested_methods_supported_, + get_all_payment_apps_error_); } std::string PaymentRequestState::GetAuthenticatedEmail() const {
diff --git a/components/payments/content/payment_request_state.h b/components/payments/content/payment_request_state.h index c0fc680..7cabf2db 100644 --- a/components/payments/content/payment_request_state.h +++ b/components/payments/content/payment_request_state.h
@@ -102,6 +102,9 @@ }; using StatusCallback = base::OnceCallback<void(bool)>; + using MethodsSupportedCallback = + base::OnceCallback<void(bool methods_supported, + const std::string& error_message)>; PaymentRequestState(content::WebContents* web_contents, const GURL& top_level_origin, @@ -136,7 +139,7 @@ // Checks if the payment methods that the merchant website have // requested are supported asynchronously. For example, may return true for // "basic-card", but false for "https://bobpay.com". - void AreRequestedMethodsSupported(StatusCallback callback); + void AreRequestedMethodsSupported(MethodsSupportedCallback callback); // Returns authenticated user email, or empty string. std::string GetAuthenticatedEmail() const; @@ -293,7 +296,8 @@ const GURL& top_level_origin, const GURL& frame_origin, content::PaymentAppProvider::PaymentApps apps, - ServiceWorkerPaymentAppFactory::InstallablePaymentApps installable_apps); + ServiceWorkerPaymentAppFactory::InstallablePaymentApps installable_apps, + const std::string& error_message); // The ServiceWorkerPaymentInstrument::ValidateCanMakePaymentCallback. void OnSWPaymentInstrumentValidated( @@ -312,7 +316,7 @@ // Checks if the payment methods that the merchant website have // requested are supported and call the |callback| to return the result. - void CheckRequestedMethodsSupported(StatusCallback callback); + void CheckRequestedMethodsSupported(MethodsSupportedCallback callback); void OnAddressNormalized(bool success, const autofill::AutofillProfile& normalized_profile); @@ -341,8 +345,9 @@ StatusCallback can_make_payment_callback_; StatusCallback has_enrolled_instrument_callback_; - StatusCallback are_requested_methods_supported_callback_; + MethodsSupportedCallback are_requested_methods_supported_callback_; bool are_requested_methods_supported_; + std::string get_all_payment_apps_error_; autofill::AutofillProfile* selected_shipping_profile_; autofill::AutofillProfile* selected_shipping_option_error_profile_;
diff --git a/components/payments/content/service_worker_payment_app_factory.cc b/components/payments/content/service_worker_payment_app_factory.cc index eefbab9..0e582e8 100644 --- a/components/payments/content/service_worker_payment_app_factory.cc +++ b/components/payments/content/service_worker_payment_app_factory.cc
@@ -153,7 +153,7 @@ ServiceWorkerPaymentAppFactory::RemoveAppsWithoutMatchingMethodData( requested_method_data_, &apps); if (apps.empty()) { - OnPaymentAppsVerified(std::move(apps)); + OnPaymentAppsVerified(std::move(apps), first_error_message_); OnPaymentAppsVerifierFinishedUsingResources(); return; } @@ -172,7 +172,10 @@ base::Unretained(this))); } - void OnPaymentAppsVerified(content::PaymentAppProvider::PaymentApps apps) { + void OnPaymentAppsVerified(content::PaymentAppProvider::PaymentApps apps, + const std::string& error_message) { + if (first_error_message_.empty()) + first_error_message_ = error_message; if (apps.empty() && crawler_ != nullptr) { // Crawls installable web payment apps if no web payment apps have been // installed. @@ -193,13 +196,17 @@ std::move(callback_).Run( std::move(apps), - ServiceWorkerPaymentAppFactory::InstallablePaymentApps()); + ServiceWorkerPaymentAppFactory::InstallablePaymentApps(), + first_error_message_); } void OnPaymentAppsCrawled( - std::map<GURL, std::unique_ptr<WebAppInstallationInfo>> apps_info) { + std::map<GURL, std::unique_ptr<WebAppInstallationInfo>> apps_info, + const std::string& error_message) { + if (first_error_message_.empty()) + first_error_message_ = error_message; std::move(callback_).Run(content::PaymentAppProvider::PaymentApps(), - std::move(apps_info)); + std::move(apps_info), first_error_message_); } void OnPaymentAppsCrawlerFinishedUsingResources() { @@ -234,6 +241,7 @@ std::vector<mojom::PaymentMethodDataPtr> requested_method_data_; ServiceWorkerPaymentAppFactory::GetAllPaymentAppsCallback callback_; base::OnceClosure finished_using_resources_callback_; + std::string first_error_message_; std::unique_ptr<ManifestVerifier> verifier_; bool is_payment_verifier_finished_using_resources_ = true;
diff --git a/components/payments/content/service_worker_payment_app_factory.h b/components/payments/content/service_worker_payment_app_factory.h index 496ca9e9..036e5e48 100644 --- a/components/payments/content/service_worker_payment_app_factory.h +++ b/components/payments/content/service_worker_payment_app_factory.h
@@ -42,7 +42,8 @@ std::map<GURL, std::unique_ptr<WebAppInstallationInfo>>; using GetAllPaymentAppsCallback = base::OnceCallback<void(content::PaymentAppProvider::PaymentApps, - InstallablePaymentApps)>; + InstallablePaymentApps, + const std::string& error_message)>; static ServiceWorkerPaymentAppFactory* GetInstance();
diff --git a/components/payments/core/BUILD.gn b/components/payments/core/BUILD.gn index 9688cb5..bdd65fd 100644 --- a/components/payments/core/BUILD.gn +++ b/components/payments/core/BUILD.gn
@@ -71,6 +71,7 @@ } deps = [ + ":error_strings", "//base", "//components/autofill/core/browser", "//components/keyed_service/core",
diff --git a/components/payments/core/native_error_strings.cc b/components/payments/core/native_error_strings.cc index d7c8221..fcc1cd41 100644 --- a/components/payments/core/native_error_strings.cc +++ b/components/payments/core/native_error_strings.cc
@@ -23,14 +23,57 @@ const char kCannotCompleteWithoutShow[] = "Attempted complete without show."; +const char kCannotResolveServiceWorkerScope[] = + "Cannot resolve the \"serviceworker\".\"scope\" $1 in web app manifest $2."; + +const char kCannotResolveServiceWorkerUrl[] = + "Cannot resolve the \"serviceworker\".\"src\" $1 in web app manifest $2."; + const char kCannotRetryWithoutInit[] = "Attempted retry without initialization."; const char kCannotRetryWithoutShow[] = "Attempted retry without show."; +const char kCrossOriginPaymentMethodManifestNotAllowed[] = + "Cross-origin payment method manifest \"$1\" not allowed for the payment " + "method \"$2\"."; + +const char kCrossOriginServiceWorkerScopeNotAllowed[] = + "Cross-origin \"serviceworker\".\"scope\" $1 not allowed in web app " + "manifest $2."; + +const char kCrossOriginServiceWorkerUrlNotAllowed[] = + "Cross-origin \"serviceworker\".\"src\" $1 not allowed in web app manifest " + "$2."; + +const char kCrossOriginWebAppManifestNotAllowed[] = + "Cross-origin default application $1 not allowed in payment method " + "manifest $2."; + const char kDetailedInvalidSslCertificateMessageFormat[] = "SSL certificate is not valid. Security level: $."; +const char kHttpHeadRequestFailed[] = + "Unable to make a HEAD request to \"$1\" for payment method manifest."; + +const char kHttpStatusCodeNotAllowed[] = + "HTTP status code $1 \"$2\" not allowed for payment method manifest " + "\"$3\"."; + +const char kInstallingMultipleDefaultAppsNotSupported[] = + "Installing multiple payment handlers from a single payment method " + "manifest is not supported."; + +const char kInvalidManifestUrl[] = + "\"$1\" is not a valid payment manifest URL with HTTPS scheme (or HTTP " + "scheme for localhost)."; + +const char kInvalidServiceWorkerScope[] = + "\"serviceworker\".\"scope\" must be a non-empty UTF8 string."; + +const char kInvalidServiceWorkerUrl[] = + "\"serviceworker\".\"src\" must be a non-empty UTF8 string."; + const char kInvalidSslCertificate[] = "SSL certificate is not valid."; const char kMethodDataRequired[] = "Method data required."; @@ -46,6 +89,9 @@ const char kMultiplePaymentMethodsNotSupportedFormat[] = "The payment methods $ are not supported."; +const char kNoLinkRelPaymentMethodManifestHttpHeader[] = + "No \"Link: rel=payment-method-manifest\" HTTP header found at \"$1\"."; + const char kNoResponseToPaymentEvent[] = "Payment handler did not respond to \"paymentrequest\" event."; @@ -53,6 +99,13 @@ const char kNotShown[] = "Not shown."; +const char kPaymentManifestCrossSiteRedirectNotAllowed[] = + "Cross-site redirect from \"$1\" to \"$2\" not allowed for payment " + "manifests."; + +const char kPaymentManifestDownloadFailed[] = + "Unable to download payment manifest \"$1\"."; + const char kPaymentDetailsNotObject[] = "Payment app returned invalid response. \"details\" field is not a " "dictionary."; @@ -74,6 +127,10 @@ "PaymentRequestEvent.respondWith(). This is how payment handlers close " "their own window programmatically."; +const char kReachedMaximumNumberOfRedirects[] = + "Unable to download the payment manifest because reached the maximum " + "number of redirects."; + const char kPaymentEventServiceWorkerError[] = "Payment handler failed to provide a response because either the " "\"paymentrequest\" event took too long or the service worker stopped for "
diff --git a/components/payments/core/native_error_strings.h b/components/payments/core/native_error_strings.h index 927d146..fa10b3a5 100644 --- a/components/payments/core/native_error_strings.h +++ b/components/payments/core/native_error_strings.h
@@ -30,20 +30,71 @@ // Mojo call PaymentRequest::Show() must precede PaymentRequest::Complete(). extern const char kCannotCompleteWithoutShow[]; +// Used when "serviceworker"."scope" string A in web app manifest B is not a +// valid URL and cannot be resolved as a relative URL either. This format should +// be used with base::ReplaceStringPlaceholders(fmt, {A, B}, nullptr). +extern const char kCannotResolveServiceWorkerScope[]; + +// Used when "serviceworker"."src" string A in web app manifest B is not a valid +// URL and cannot be resolved as a relative URL either. This format should be +// used with base::ReplaceStringPlaceholders(fmt, {A, B}, nullptr). +extern const char kCannotResolveServiceWorkerUrl[]; + // Mojo call PaymentRequest::Init() must precede PaymentRequest::Retry(). extern const char kCannotRetryWithoutInit[]; // Mojo call PaymentRequest::Show() must precede PaymentRequest::Retry(). extern const char kCannotRetryWithoutShow[]; -// Mojo call PaymentRequest::Show() must precede PaymentRequest::UpdateWith(). -extern const char kCannotUpdateWithoutShow[]; +// Used when a payment method A has a cross-origin "Link: +// rel=payment-method-manifest" to the manifest B. This format should be used +// with base::ReplaceStringPlaceholders(fmt, {B, A}, nullptr). +extern const char kCrossOriginPaymentMethodManifestNotAllowed[]; + +// The URL A in web app manifest B's "serviceworker"."scope" must be of the same +// origin as the web app manifest itself. This format should be used with +// base::ReplaceStringPlaceholders(fmt, {A, B}, nullptr). +extern const char kCrossOriginServiceWorkerScopeNotAllowed[]; + +// The URL A in web app manifest B's "serviceworker"."src" must be of the same +// origin as the web app manifest itself. This format should be used with +// base::ReplaceStringPlaceholders(fmt, {A, B}, nullptr). +extern const char kCrossOriginServiceWorkerUrlNotAllowed[]; + +// The "default_applications" list on origin A is not allowed to contain a URL +// from origin B. This format should be used with +// base::ReplaceStringPlaceholders(format, {B, A}, nullptr). +extern const char kCrossOriginWebAppManifestNotAllowed[]; // The format for a detailed message about invalid SSL certificate. This format // should be used with base::ReplaceChars() function, where "$" is the character // to replace. extern const char kDetailedInvalidSslCertificateMessageFormat[]; +// Used when a HEAD request for URL A fails. This format should be used with +// base::ReplaceStringPlaceholders(fmt, {A}, nullptr). +extern const char kHttpHeadRequestFailed[]; + +// Used for HTTP redirects that are prohibited for payment method manifests. +// This format should be used with base::ReplaceStringPlaceholders(fmt, +// {http_code, http_code_phrase, original_url}, nullptr). +extern const char kHttpStatusCodeNotAllowed[]; + +// The "default_applications" list should contain exactly one URL for JIT +// install feature to work. +extern const char kInstallingMultipleDefaultAppsNotSupported[]; + +// Used to let the web developer know about an invalid payment manifest URL A. +// This format should be used with base::ReplaceStringPlaceholders(fmt, {A}, +// nullptr). +extern const char kInvalidManifestUrl[]; + +// Web app manifest contains an empty or non-UTF8 service worker scope. +extern const char kInvalidServiceWorkerScope[]; + +// Web app manifest contains an empty or non-UTF8 service worker URL. +extern const char kInvalidServiceWorkerUrl[]; + // Chrome refuses to provide any payment information to a website with an // invalid SSL certificate. extern const char kInvalidSslCertificate[]; @@ -66,6 +117,11 @@ // where "$" is the character to replace. extern const char kMultiplePaymentMethodsNotSupportedFormat[]; +// Used when the payment method URL A does not have a "Link: +// rel=payment-method-manifest" HTTP header. This format should be used with +// base::ReplaceStringPlaceholders(fmt, {A}, nullptr). +extern const char kNoLinkRelPaymentMethodManifestHttpHeader[]; + // Payment handler did not respond to the "paymentrequest" event. extern const char kNoResponseToPaymentEvent[]; @@ -75,6 +131,14 @@ // Used when PaymentRequest::Show() has not been called, but should have been. extern const char kNotShown[]; +// Used for errors about cross-site redirects from A to B. This format should be +// used with base::ReplaceStringPlaceholders(fmt, {A, B}, nullptr). +extern const char kPaymentManifestCrossSiteRedirectNotAllowed[]; + +// Used when downloading payment manifest URL A has failed. This format should +// be used with base::ReplaceStringPlaceholders(fmt, {A}, nullptr). +extern const char kPaymentManifestDownloadFailed[]; + // Payment handler passed a non-object field "details" in response to the // "paymentrequest" event. extern const char kPaymentDetailsNotObject[]; @@ -106,6 +170,9 @@ // PaymentRequestEvent.respondWith() method. extern const char kPaymentEventRejected[]; +// Used when maximum number of redirects has been reached. +extern const char kReachedMaximumNumberOfRedirects[]; + // The format for the message about a single payment method that is not // supported. This format should be used with base::ReplaceChars() function, // where "$" is the character to replace.
diff --git a/components/payments/core/payment_manifest_downloader.cc b/components/payments/core/payment_manifest_downloader.cc index 814db83..5da3730 100644 --- a/components/payments/core/payment_manifest_downloader.cc +++ b/components/payments/core/payment_manifest_downloader.cc
@@ -11,10 +11,12 @@ #include "base/logging.h" #include "base/optional.h" #include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" -#include "base/strings/stringprintf.h" +#include "base/strings/string_util.h" #include "components/link_header_util/link_header_util.h" #include "components/payments/core/error_logger.h" +#include "components/payments/core/native_error_strings.h" #include "components/payments/core/url_util.h" #include "net/base/load_flags.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" @@ -32,28 +34,31 @@ GURL ParseResponseHeader(const GURL& url, scoped_refptr<net::HttpResponseHeaders> headers, - const ErrorLogger& log) { + const ErrorLogger& log, + std::string* out_error_message) { if (!headers) { - log.Error(base::StringPrintf( - "No HTTP headers found on \"%s\" for payment method manifest.", - url.spec().c_str())); + *out_error_message = base::ReplaceStringPlaceholders( + errors::kNoLinkRelPaymentMethodManifestHttpHeader, {url.spec()}, + nullptr); + log.Error(*out_error_message); return GURL(); } int response_code = headers->response_code(); if (response_code != net::HTTP_OK && response_code != net::HTTP_NO_CONTENT) { - log.Error(base::StringPrintf( - "Unable to make a HEAD request to \"%s\" for payment method manifest.", - url.spec().c_str())); + *out_error_message = base::ReplaceStringPlaceholders( + errors::kHttpHeadRequestFailed, {url.spec()}, nullptr), + log.Error(*out_error_message); return GURL(); } std::string link_header; headers->GetNormalizedHeader("link", &link_header); if (link_header.empty()) { - log.Error(base::StringPrintf( - "No HTTP Link headers found on \"%s\" for payment method manifest.", - url.spec().c_str())); + *out_error_message = base::ReplaceStringPlaceholders( + errors::kNoLinkRelPaymentMethodManifestHttpHeader, {url.spec()}, + nullptr); + log.Error(*out_error_message); return GURL(); } @@ -76,40 +81,45 @@ return url.Resolve(payment_method_manifest_url); } - log.Error( - base::StringPrintf("No rel=\"payment-method-manifest\" HTTP Link headers " - "found on \"%s\" for payment method manifest.", - url.spec().c_str())); + *out_error_message = base::ReplaceStringPlaceholders( + errors::kNoLinkRelPaymentMethodManifestHttpHeader, {url.spec()}, nullptr); + log.Error(*out_error_message); return GURL(); } -bool IsValidManifestUrl(const GURL& url, const ErrorLogger& log) { +bool IsValidManifestUrl(const GURL& url, + const ErrorLogger& log, + std::string* out_error_message) { bool is_valid = UrlUtil::IsValidManifestUrl(url); if (!is_valid) { - log.Error( - base::StringPrintf("\"%s\" is not a valid payment manifest URL with " - "HTTPS scheme (or HTTP scheme for localhost).", - url.spec().c_str())); + *out_error_message = base::ReplaceStringPlaceholders( + errors::kInvalidManifestUrl, {url.spec()}, nullptr); + log.Error(*out_error_message); } return is_valid; } GURL ParseRedirectUrl(const net::RedirectInfo& redirect_info, - const ErrorLogger& log) { - // Do not follow net::HTTP_MULTIPLE_CHOICES, net::HTTP_NOT_MODIFIED and - // net::HTTP_USE_PROXY redirects. (306 is no longer used.) + const GURL& original_url, + const ErrorLogger& log, + std::string* out_error_message) { if (redirect_info.status_code != net::HTTP_MOVED_PERMANENTLY && // 301 redirect_info.status_code != net::HTTP_FOUND && // 302 redirect_info.status_code != net::HTTP_SEE_OTHER && // 303 redirect_info.status_code != net::HTTP_TEMPORARY_REDIRECT && // 307 redirect_info.status_code != net::HTTP_PERMANENT_REDIRECT) { // 308 - log.Error( - "Cannot follow HTTP_MULTIPLE_CHOICES (300), HTTP_NOT_MODIFIED (304), " - "and HTTP_USE_PROXY (305) redirects for payment manifests."); + *out_error_message = base::ReplaceStringPlaceholders( + errors::kHttpStatusCodeNotAllowed, + {base::NumberToString(redirect_info.status_code), + net::GetHttpReasonPhrase( + static_cast<net::HttpStatusCode>(redirect_info.status_code)), + original_url.spec()}, + nullptr); + log.Error(*out_error_message); return GURL(); } - if (!IsValidManifestUrl(redirect_info.new_url, log)) + if (!IsValidManifestUrl(redirect_info.new_url, log, out_error_message)) return GURL(); return redirect_info.new_url; @@ -119,10 +129,12 @@ const GURL& final_url, const std::string& response_body, scoped_refptr<net::HttpResponseHeaders> headers, - const ErrorLogger& log) { + const ErrorLogger& log, + std::string* out_error_message) { if (!headers || headers->response_code() != net::HTTP_OK) { - log.Error(base::StringPrintf("Unable to download payment manifest \"%s\".", - final_url.spec().c_str())); + *out_error_message = base::ReplaceStringPlaceholders( + errors::kPaymentManifestDownloadFailed, {final_url.spec()}, nullptr); + log.Error(*out_error_message); return std::string(); } @@ -144,7 +156,7 @@ void PaymentManifestDownloader::DownloadPaymentMethodManifest( const GURL& url, PaymentManifestDownloadCallback callback) { - DCHECK(IsValidManifestUrl(url, *log_)); + DCHECK(UrlUtil::IsValidManifestUrl(url)); // Restrict number of redirects for efficiency and breaking circle. InitiateDownload(url, "HEAD", /*allowed_number_of_redirects=*/3, std::move(callback)); @@ -153,7 +165,7 @@ void PaymentManifestDownloader::DownloadWebAppManifest( const GURL& url, PaymentManifestDownloadCallback callback) { - DCHECK(IsValidManifestUrl(url, *log_)); + DCHECK(UrlUtil::IsValidManifestUrl(url)); InitiateDownload(url, "GET", /*allowed_number_of_redirects=*/0, std::move(callback)); } @@ -178,9 +190,11 @@ downloads_.erase(download_it); // Manually follow some type of redirects. + std::string error_message; if (download->allowed_number_of_redirects > 0) { DCHECK(download->method == "HEAD"); - GURL redirect_url = ParseRedirectUrl(redirect_info, *log_); + GURL redirect_url = ParseRedirectUrl(redirect_info, download->original_url, + *log_, &error_message); if (!redirect_url.is_empty()) { // Do not allow cross site redirects. if (net::registry_controlled_domains::SameDomainOrHost( @@ -191,18 +205,16 @@ std::move(download->callback)); return; } - log_->Error(base::StringPrintf( - "Cross-site redirect from \"%s\" to \"%s\" not allowed for payment " - "manifests.", - download->original_url.spec().c_str(), redirect_url.spec().c_str())); + error_message = base::ReplaceStringPlaceholders( + errors::kPaymentManifestCrossSiteRedirectNotAllowed, + {download->original_url.spec(), redirect_url.spec()}, nullptr); } } else { - log_->Error( - "Unable to download the payment manifest because reached the maximum " - "number of redirects."); + error_message = errors::kReachedMaximumNumberOfRedirects; } - - std::move(download->callback).Run(download->original_url, std::string()); + log_->Error(error_message); + std::move(download->callback) + .Run(download->original_url, std::string(), error_message); } void PaymentManifestDownloader::OnURLLoaderComplete( @@ -233,29 +245,33 @@ std::unique_ptr<Download> download = std::move(download_it->second); downloads_.erase(download_it); + std::string error_message; if (download->method == "GET") { - std::move(download->callback) - .Run(final_url, - ParseResponseContent(final_url, response_body, headers, *log_)); + std::string content = ParseResponseContent(final_url, response_body, + headers, *log_, &error_message); + std::move(download->callback).Run(final_url, content, error_message); return; } DCHECK_EQ("HEAD", download->method); GURL payment_method_manifest_url = - ParseResponseHeader(final_url, headers, *log_); + ParseResponseHeader(final_url, headers, *log_, &error_message); + if (!payment_method_manifest_url.is_valid()) { + std::move(download->callback).Run(final_url, std::string(), error_message); + return; + } - if (!payment_method_manifest_url.is_valid() || - !IsValidManifestUrl(payment_method_manifest_url, *log_)) { - std::move(download->callback).Run(final_url, std::string()); + if (!IsValidManifestUrl(payment_method_manifest_url, *log_, &error_message)) { + std::move(download->callback).Run(final_url, std::string(), error_message); return; } if (!url::IsSameOriginWith(final_url, payment_method_manifest_url)) { - log_->Error(base::StringPrintf( - "Payment method manifest \"%s\" is not allowed for the method \"%s\" " - "because of different origin.", - payment_method_manifest_url.spec().c_str(), final_url.spec().c_str())); - std::move(download->callback).Run(final_url, std::string()); + error_message = base::ReplaceStringPlaceholders( + errors::kCrossOriginPaymentMethodManifestNotAllowed, + {payment_method_manifest_url.spec(), final_url.spec()}, nullptr); + log_->Error(error_message); + std::move(download->callback).Run(final_url, std::string(), error_message); return; } @@ -279,7 +295,7 @@ const std::string& method, int allowed_number_of_redirects, PaymentManifestDownloadCallback callback) { - DCHECK(IsValidManifestUrl(url, *log_)); + DCHECK(UrlUtil::IsValidManifestUrl(url)); net::NetworkTrafficAnnotationTag traffic_annotation = net::DefineNetworkTrafficAnnotation("payment_manifest_downloader", R"(
diff --git a/components/payments/core/payment_manifest_downloader.h b/components/payments/core/payment_manifest_downloader.h index de5a4605..753e186 100644 --- a/components/payments/core/payment_manifest_downloader.h +++ b/components/payments/core/payment_manifest_downloader.h
@@ -49,7 +49,9 @@ // In the case of a web app manifest download, can also also fail when: // - There's a redirect. using PaymentManifestDownloadCallback = - base::OnceCallback<void(const GURL& url, const std::string& contents)>; + base::OnceCallback<void(const GURL& url, + const std::string& contents, + const std::string& error_message)>; // Downloader of the payment method manifest and web-app manifest based on the // payment method name that is a URL with HTTPS scheme, e.g.,
diff --git a/components/payments/core/payment_manifest_downloader_unittest.cc b/components/payments/core/payment_manifest_downloader_unittest.cc index 421c5e4..b460cb7 100644 --- a/components/payments/core/payment_manifest_downloader_unittest.cc +++ b/components/payments/core/payment_manifest_downloader_unittest.cc
@@ -22,6 +22,8 @@ using testing::_; +static const char kNoError[] = ""; + } // namespace class PaymentMethodManifestDownloaderTest : public testing::Test { @@ -41,9 +43,10 @@ ~PaymentMethodManifestDownloaderTest() override {} - MOCK_METHOD2(OnManifestDownload, + MOCK_METHOD3(OnManifestDownload, void(const GURL& unused_url_after_redirects, - const std::string& content)); + const std::string& content, + const std::string& error_message)); void CallComplete(int response_code = 200, const std::string& link_header = std::string(), @@ -52,7 +55,10 @@ scoped_refptr<net::HttpResponseHeaders> headers; if (send_headers) { headers = base::MakeRefCounted<net::HttpResponseHeaders>(std::string()); - headers->ReplaceStatusLine(base::StringPrintf("%d", response_code)); + headers->ReplaceStatusLine(base::StringPrintf( + "HTTP/1.1 %d %s", response_code, + net::GetHttpReasonPhrase( + static_cast<net::HttpStatusCode>(response_code)))); } if (!link_header.empty()) @@ -87,19 +93,29 @@ }; TEST_F(PaymentMethodManifestDownloaderTest, HttpHeadResponse404IsFailure) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL(*this, + OnManifestDownload( + _, std::string(), + "Unable to make a HEAD request to \"https://bobpay.com/\" " + "for payment method manifest.")); CallComplete(404); } TEST_F(PaymentMethodManifestDownloaderTest, NoHttpHeadersIsFailure) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL( + *this, OnManifestDownload(_, std::string(), + "No \"Link: rel=payment-method-manifest\" HTTP " + "header found at \"https://bobpay.com/\".")); CallComplete(200, std::string(), std::string(), false); } TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpHeaderIsFailure) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL( + *this, OnManifestDownload(_, std::string(), + "No \"Link: rel=payment-method-manifest\" HTTP " + "header found at \"https://bobpay.com/\".")); CallComplete(200); } @@ -107,26 +123,38 @@ TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpLinkHeaderIsFailure) { scoped_refptr<net::HttpResponseHeaders> headers( new net::HttpResponseHeaders(std::string())); - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL( + *this, OnManifestDownload(_, std::string(), + "No \"Link: rel=payment-method-manifest\" HTTP " + "header found at \"https://bobpay.com/\".")); CallComplete(200, "Link:"); } TEST_F(PaymentMethodManifestDownloaderTest, NoRelInHttpLinkHeaderIsFailure) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL( + *this, OnManifestDownload(_, std::string(), + "No \"Link: rel=payment-method-manifest\" HTTP " + "header found at \"https://bobpay.com/\".")); CallComplete(200, "Link: <manifest.json>"); } TEST_F(PaymentMethodManifestDownloaderTest, NoUrlInHttpLinkHeaderIsFailure) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL( + *this, OnManifestDownload(_, std::string(), + "No \"Link: rel=payment-method-manifest\" HTTP " + "header found at \"https://bobpay.com/\".")); CallComplete(200, "Link: rel=payment-method-manifest"); } TEST_F(PaymentMethodManifestDownloaderTest, NoManifestRellInHttpLinkHeaderIsFailure) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL( + *this, OnManifestDownload(_, std::string(), + "No \"Link: rel=payment-method-manifest\" HTTP " + "header found at \"https://bobpay.com/\".")); CallComplete(200, "Link: <manifest.json>; rel=web-app-manifest"); } @@ -136,7 +164,10 @@ new net::HttpResponseHeaders(std::string())); CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL(*this, + OnManifestDownload(_, std::string(), + "Unable to download payment manifest " + "\"https://bobpay.com/manifest.json\".")); CallComplete(404); } @@ -144,7 +175,10 @@ TEST_F(PaymentMethodManifestDownloaderTest, EmptyHttpGetResponseIsFailure) { CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL(*this, + OnManifestDownload(_, std::string(), + "Unable to download payment manifest " + "\"https://bobpay.com/manifest.json\".")); CallComplete(200, std::string(), std::string(), false); } @@ -152,7 +186,7 @@ TEST_F(PaymentMethodManifestDownloaderTest, NonEmptyHttpGetResponseIsSuccess) { CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); - EXPECT_CALL(*this, OnManifestDownload(_, "manifest content")); + EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); CallComplete(200, std::string(), "manifest content"); } @@ -160,7 +194,7 @@ TEST_F(PaymentMethodManifestDownloaderTest, HeaderResponseCode204IsSuccess) { CallComplete(204, "Link: <manifest.json>; rel=payment-method-manifest"); - EXPECT_CALL(*this, OnManifestDownload(_, "manifest content")); + EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); CallComplete(200, std::string(), "manifest content"); } @@ -180,7 +214,12 @@ } TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpHeaderLinkUrl) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL( + *this, + OnManifestDownload( + _, std::string(), + "\"http://bobpay.com/manifest.json\" is not a valid payment manifest " + "URL with HTTPS scheme (or HTTP scheme for localhost).")); CallComplete(200, "Link: <http://bobpay.com/manifest.json>; " @@ -188,7 +227,11 @@ } TEST_F(PaymentMethodManifestDownloaderTest, 300IsUnsupportedRedirect) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL(*this, + OnManifestDownload( + _, std::string(), + "HTTP status code 300 \"Multiple Choices\" not allowed for " + "payment method manifest \"https://bobpay.com/\".")); CallRedirect(300, GURL("https://pay.bobpay.com")); } @@ -204,7 +247,7 @@ CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); - EXPECT_CALL(*this, OnManifestDownload(_, "manifest content")); + EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); CallComplete(200, std::string(), "manifest content"); } @@ -220,19 +263,26 @@ CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); - EXPECT_CALL(*this, OnManifestDownload(_, "manifest content")); + EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); CallComplete(200, std::string(), "manifest content"); } TEST_F(PaymentMethodManifestDownloaderTest, 304IsUnsupportedRedirect) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL(*this, + OnManifestDownload( + _, std::string(), + "HTTP status code 304 \"Not Modified\" not allowed for " + "payment method manifest \"https://bobpay.com/\".")); CallRedirect(304, GURL("https://pay.bobpay.com")); } TEST_F(PaymentMethodManifestDownloaderTest, 305IsUnsupportedRedirect) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL(*this, OnManifestDownload( + _, std::string(), + "HTTP status code 305 \"Use Proxy\" not allowed for " + "payment method manifest \"https://bobpay.com/\".")); CallRedirect(305, GURL("https://pay.bobpay.com")); } @@ -248,7 +298,7 @@ CallComplete(200, "Link: <manifest.json>; rel=payment-method-manifest"); - EXPECT_CALL(*this, OnManifestDownload(_, "manifest content")); + EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); CallComplete(200, std::string(), "manifest content"); } @@ -266,19 +316,30 @@ EXPECT_EQ(GetOriginalURL(), GURL("https://newpay.bobpay.com")); - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL(*this, OnManifestDownload( + _, std::string(), + "Unable to download the payment manifest because " + "reached the maximum number of redirects.")); CallRedirect(308, GURL("https://newpay.bobpay.com")); } TEST_F(PaymentMethodManifestDownloaderTest, InvalidRedirectUrlIsFailure) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL(*this, OnManifestDownload( + _, std::string(), + "\"\" is not a valid payment manifest URL with HTTPS " + "scheme (or HTTP scheme for localhost).")); CallRedirect(308, GURL("pay.bobpay.com")); } TEST_F(PaymentMethodManifestDownloaderTest, NotAllowCrossSiteRedirects) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL( + *this, + OnManifestDownload( + _, std::string(), + "Cross-site redirect from \"https://bobpay.com/\" to " + "\"https://alicepay.com/\" not allowed for payment manifests.")); CallRedirect(301, GURL("https://alicepay.com")); } @@ -300,14 +361,19 @@ ~WebAppManifestDownloaderTest() override {} - MOCK_METHOD2(OnManifestDownload, - void(const GURL& url, const std::string& content)); + MOCK_METHOD3(OnManifestDownload, + void(const GURL& url, + const std::string& content, + const std::string& error_message)); void CallComplete(int response_code, const std::string& response_body = std::string()) { scoped_refptr<net::HttpResponseHeaders> headers = base::MakeRefCounted<net::HttpResponseHeaders>(std::string()); - headers->ReplaceStatusLine(base::StringPrintf("%d", response_code)); + headers->ReplaceStatusLine(base::StringPrintf( + "HTTP/1.1 %d %s", response_code, + net::GetHttpReasonPhrase( + static_cast<net::HttpStatusCode>(response_code)))); downloader_.OnURLLoaderCompleteInternal(downloader_.GetLoaderForTesting(), test_url_, response_body, headers, net::OK); @@ -324,19 +390,23 @@ }; TEST_F(WebAppManifestDownloaderTest, HttpGetResponse404IsFailure) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL( + *this, + OnManifestDownload( + _, std::string(), + "Unable to download payment manifest \"https://bobpay.com/\".")); CallComplete(404); } TEST_F(WebAppManifestDownloaderTest, EmptyHttpGetResponseIsFailure) { - EXPECT_CALL(*this, OnManifestDownload(_, std::string())); + EXPECT_CALL(*this, OnManifestDownload(_, std::string(), kNoError)); CallComplete(200); } TEST_F(WebAppManifestDownloaderTest, NonEmptyHttpGetResponseIsSuccess) { - EXPECT_CALL(*this, OnManifestDownload(_, "manifest content")); + EXPECT_CALL(*this, OnManifestDownload(_, "manifest content", kNoError)); CallComplete(200, "manifest content"); }
diff --git a/components/resources/terms/terms_am.html b/components/resources/terms/terms_am.html index ccd72ff..fcf55438 100644 --- a/components/resources/terms/terms_am.html +++ b/components/resources/terms/terms_am.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>የGoogle Chrome የአግልግሎት ስምምነት ውሎች </title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_ar.html b/components/resources/terms/terms_ar.html index 8354244..6e5920a 100644 --- a/components/resources/terms/terms_ar.html +++ b/components/resources/terms/terms_ar.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>بنود خدمة Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_bg.html b/components/resources/terms/terms_bg.html index bec309d..9aaeaf6 100644 --- a/components/resources/terms/terms_bg.html +++ b/components/resources/terms/terms_bg.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Общи условия на Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_bn.html b/components/resources/terms/terms_bn.html index 22082df4..09f7d6b 100644 --- a/components/resources/terms/terms_bn.html +++ b/components/resources/terms/terms_bn.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome পরিষেবার চুক্তি</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_ca.html b/components/resources/terms/terms_ca.html index fdebae5..d673e888 100644 --- a/components/resources/terms/terms_ca.html +++ b/components/resources/terms/terms_ca.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Condicions d'ús de Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_chromium.html b/components/resources/terms/terms_chromium.html index 7b39fb5..87690e9 100644 --- a/components/resources/terms/terms_chromium.html +++ b/components/resources/terms/terms_chromium.html
@@ -1,6 +1,9 @@ <html> <head> - <title></title> +<title></title> +<style> +:root { color-scheme: light dark; } +</style> </head> <body> <h2>This Space Intentionally Blank</h2>
diff --git a/components/resources/terms/terms_cs.html b/components/resources/terms/terms_cs.html index 8d5a1299..1248e063 100644 --- a/components/resources/terms/terms_cs.html +++ b/components/resources/terms/terms_cs.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Smluvní podmínky aplikace Google Chrome </title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_da.html b/components/resources/terms/terms_da.html index f4e9bc624..e1e80fc 100644 --- a/components/resources/terms/terms_da.html +++ b/components/resources/terms/terms_da.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome Servicevilkår</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_de.html b/components/resources/terms/terms_de.html index 6a90a917..b71895d0 100644 --- a/components/resources/terms/terms_de.html +++ b/components/resources/terms/terms_de.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome – Nutzungsbedingungen</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_el.html b/components/resources/terms/terms_el.html index 74145f8..f402c5ba 100644 --- a/components/resources/terms/terms_el.html +++ b/components/resources/terms/terms_el.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Όροι Παροχής Υπηρεσιών του Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_en-GB.html b/components/resources/terms/terms_en-GB.html index a709979..c91430d7 100644 --- a/components/resources/terms/terms_en-GB.html +++ b/components/resources/terms/terms_en-GB.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome Terms of Service</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_en.html b/components/resources/terms/terms_en.html index fe96cc092..ca6a0d9 100644 --- a/components/resources/terms/terms_en.html +++ b/components/resources/terms/terms_en.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome Terms of Service</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_es-419.html b/components/resources/terms/terms_es-419.html index 4b0b516..0e30e33f 100644 --- a/components/resources/terms/terms_es-419.html +++ b/components/resources/terms/terms_es-419.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Condiciones del servicio de Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_es.html b/components/resources/terms/terms_es.html index 970e41d..cfa57df9 100644 --- a/components/resources/terms/terms_es.html +++ b/components/resources/terms/terms_es.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Condiciones del servicio de Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_et.html b/components/resources/terms/terms_et.html index a541169f..5d5a9bd 100644 --- a/components/resources/terms/terms_et.html +++ b/components/resources/terms/terms_et.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome'i teenusetingimused</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_fa.html b/components/resources/terms/terms_fa.html index 9337b1f..140d846e 100644 --- a/components/resources/terms/terms_fa.html +++ b/components/resources/terms/terms_fa.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>شرایط سرویس Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_fi.html b/components/resources/terms/terms_fi.html index 279218c..c945a98 100644 --- a/components/resources/terms/terms_fi.html +++ b/components/resources/terms/terms_fi.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chromen käyttöehdot</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_fil.html b/components/resources/terms/terms_fil.html index 4954c0f..847ce1a3 100644 --- a/components/resources/terms/terms_fil.html +++ b/components/resources/terms/terms_fil.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Mga Tuntunin ng Serbisyo ng Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_fr.html b/components/resources/terms/terms_fr.html index ac305761..8b67f318 100644 --- a/components/resources/terms/terms_fr.html +++ b/components/resources/terms/terms_fr.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Conditions d'utilisation de Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_gu.html b/components/resources/terms/terms_gu.html index c2647d73..097ac76 100644 --- a/components/resources/terms/terms_gu.html +++ b/components/resources/terms/terms_gu.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome સેવાની શરતો</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_he.html b/components/resources/terms/terms_he.html index 3caedd2..486983f 100644 --- a/components/resources/terms/terms_he.html +++ b/components/resources/terms/terms_he.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>התנאים וההגבלות של Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_hi.html b/components/resources/terms/terms_hi.html index 56ea72b8..631a576c 100644 --- a/components/resources/terms/terms_hi.html +++ b/components/resources/terms/terms_hi.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome सेवा की शर्तें</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_hr.html b/components/resources/terms/terms_hr.html index a38ad02..f5edf10 100644 --- a/components/resources/terms/terms_hr.html +++ b/components/resources/terms/terms_hr.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome uvjeti pružanja usluge</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_hu.html b/components/resources/terms/terms_hu.html index 1f53f0a..6223c93 100644 --- a/components/resources/terms/terms_hu.html +++ b/components/resources/terms/terms_hu.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome - Általános Szerződési Feltételek</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_id.html b/components/resources/terms/terms_id.html index 98021e02..6122b160 100644 --- a/components/resources/terms/terms_id.html +++ b/components/resources/terms/terms_id.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Persyaratan Layanan Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_it.html b/components/resources/terms/terms_it.html index f9c76f98..d78debd 100644 --- a/components/resources/terms/terms_it.html +++ b/components/resources/terms/terms_it.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Termini di servizio di Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_ja.html b/components/resources/terms/terms_ja.html index f617373..99dffbe 100644 --- a/components/resources/terms/terms_ja.html +++ b/components/resources/terms/terms_ja.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome 利用規約</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_kn.html b/components/resources/terms/terms_kn.html index 740a7e9..19436f3f 100644 --- a/components/resources/terms/terms_kn.html +++ b/components/resources/terms/terms_kn.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome ಸೇವಾ ನಿಯಮಗಳು</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_ko.html b/components/resources/terms/terms_ko.html index 61ee4d14..35cbd34 100644 --- a/components/resources/terms/terms_ko.html +++ b/components/resources/terms/terms_ko.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google 크롬 서비스 약관</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_lt.html b/components/resources/terms/terms_lt.html index 79d890d..fd7dc36 100644 --- a/components/resources/terms/terms_lt.html +++ b/components/resources/terms/terms_lt.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>„Google Chrome“ paslaugų teikimo sąlygos</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_lv.html b/components/resources/terms/terms_lv.html index e34eed73..e315109 100644 --- a/components/resources/terms/terms_lv.html +++ b/components/resources/terms/terms_lv.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome pakalpojumu sniegšanas noteikumi</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_ml.html b/components/resources/terms/terms_ml.html index 7a1501a..103041f3 100644 --- a/components/resources/terms/terms_ml.html +++ b/components/resources/terms/terms_ml.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome സേവനനിബന്ധനകള്</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_mr.html b/components/resources/terms/terms_mr.html index 3b05d5c0..3fc4eb0 100644 --- a/components/resources/terms/terms_mr.html +++ b/components/resources/terms/terms_mr.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome सेवा अटी</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_nb.html b/components/resources/terms/terms_nb.html index fb8b09d..5981a39 100644 --- a/components/resources/terms/terms_nb.html +++ b/components/resources/terms/terms_nb.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Vilkår for bruk av Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_nl.html b/components/resources/terms/terms_nl.html index 3054a67..2ed125b 100644 --- a/components/resources/terms/terms_nl.html +++ b/components/resources/terms/terms_nl.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome - Servicevoorwaarden</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_pl.html b/components/resources/terms/terms_pl.html index 756fd29a..f2f719c 100644 --- a/components/resources/terms/terms_pl.html +++ b/components/resources/terms/terms_pl.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome – Warunki korzystania z usługi</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_pt-BR.html b/components/resources/terms/terms_pt-BR.html index f823b88..4a8bf3b 100644 --- a/components/resources/terms/terms_pt-BR.html +++ b/components/resources/terms/terms_pt-BR.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Termos de Serviço do Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_pt-PT.html b/components/resources/terms/terms_pt-PT.html index feda817..bdde37c0 100644 --- a/components/resources/terms/terms_pt-PT.html +++ b/components/resources/terms/terms_pt-PT.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Termos de utilização do Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_ro.html b/components/resources/terms/terms_ro.html index d27a1cf0..79df577e 100644 --- a/components/resources/terms/terms_ro.html +++ b/components/resources/terms/terms_ro.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Termeni şi condiţii Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_ru.html b/components/resources/terms/terms_ru.html index 46bd51e..a4e1b89 100644 --- a/components/resources/terms/terms_ru.html +++ b/components/resources/terms/terms_ru.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Условия предоставления услуг Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_sk.html b/components/resources/terms/terms_sk.html index 31cfe62..70f76af8 100644 --- a/components/resources/terms/terms_sk.html +++ b/components/resources/terms/terms_sk.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome – Zmluvné podmienky</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_sl.html b/components/resources/terms/terms_sl.html index 09ba674..1c2ef68f 100644 --- a/components/resources/terms/terms_sl.html +++ b/components/resources/terms/terms_sl.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Pogoji storitve Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_sr.html b/components/resources/terms/terms_sr.html index b48a5da..a7db88e97 100644 --- a/components/resources/terms/terms_sr.html +++ b/components/resources/terms/terms_sr.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome услови коришћења услуге</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_sv.html b/components/resources/terms/terms_sv.html index 588b668..0922201 100644 --- a/components/resources/terms/terms_sv.html +++ b/components/resources/terms/terms_sv.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Användarvillkor för Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_sw.html b/components/resources/terms/terms_sw.html index 8b95b79..99e33ee 100644 --- a/components/resources/terms/terms_sw.html +++ b/components/resources/terms/terms_sw.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Sheria na Masharti ya Google Chrome</title> <style> +:root { color-scheme: light dark; } body { font-family:Arial; font-size:13px; } </style> </head>
diff --git a/components/resources/terms/terms_ta.html b/components/resources/terms/terms_ta.html index d691a51..94aceeab 100644 --- a/components/resources/terms/terms_ta.html +++ b/components/resources/terms/terms_ta.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome சேவை விதிமுறைகள்</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_te.html b/components/resources/terms/terms_te.html index 08fed586..bd54510 100644 --- a/components/resources/terms/terms_te.html +++ b/components/resources/terms/terms_te.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome సేవా నిబంధనలు</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_th.html b/components/resources/terms/terms_th.html index 16234202..14fc430 100644 --- a/components/resources/terms/terms_th.html +++ b/components/resources/terms/terms_th.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>ข้อกำหนดในการให้บริการของ Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_tr.html b/components/resources/terms/terms_tr.html index 6670f3f..c4361bd 100644 --- a/components/resources/terms/terms_tr.html +++ b/components/resources/terms/terms_tr.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google Chrome Hizmet Şartları</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_uk.html b/components/resources/terms/terms_uk.html index 871deafe..a042d27 100644 --- a/components/resources/terms/terms_uk.html +++ b/components/resources/terms/terms_uk.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Загальні положення та умови Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_vi.html b/components/resources/terms/terms_vi.html index 632e66d..20d70be 100644 --- a/components/resources/terms/terms_vi.html +++ b/components/resources/terms/terms_vi.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Ðiều khoản Dịch vụ của Google Chrome</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_zh-CN.html b/components/resources/terms/terms_zh-CN.html index 15fa16f..b527cb59 100644 --- a/components/resources/terms/terms_zh-CN.html +++ b/components/resources/terms/terms_zh-CN.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>谷歌浏览器服务条款</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/resources/terms/terms_zh-TW.html b/components/resources/terms/terms_zh-TW.html index ac039ce..4c633438 100644 --- a/components/resources/terms/terms_zh-TW.html +++ b/components/resources/terms/terms_zh-TW.html
@@ -6,6 +6,7 @@ <meta name="viewport" content="initial-scale=1.0"> <title>Google 瀏覽器服務條款</title> <style> +:root { color-scheme: light dark } body { font-family:Arial; font-size:13px; } h2 { font-size:1em; margin-top:0 } </style>
diff --git a/components/safe_browsing/android/remote_database_manager.cc b/components/safe_browsing/android/remote_database_manager.cc index 7b004773..9976bfa 100644 --- a/components/safe_browsing/android/remote_database_manager.cc +++ b/components/safe_browsing/android/remote_database_manager.cc
@@ -120,7 +120,7 @@ if (ints_str.empty()) { // By default, we check all types except a few. static_assert(content::ResourceType::kMaxValue == - content::ResourceType::kNavigationPreload, + content::ResourceType::kNavigationPreloadSubFrame, "Decide if new resource type should be skipped on mobile."); for (int t_int = 0; t_int <= static_cast<int>(content::ResourceType::kMaxValue); t_int++) {
diff --git a/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h b/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h index c6f0487..cfdfcaf 100644 --- a/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h +++ b/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h
@@ -15,7 +15,6 @@ #include "base/time/time.h" #include "components/safe_browsing/common/safe_browsing.mojom.h" #include "mojo/public/cpp/bindings/binding.h" -#include "third_party/blink/public/platform/web_callbacks.h" #include "third_party/blink/public/platform/websocket_handshake_throttle.h" #include "url/gurl.h"
diff --git a/components/search_engines/template_url_fetcher.cc b/components/search_engines/template_url_fetcher.cc index d136273..40b4abb7 100644 --- a/components/search_engines/template_url_fetcher.cc +++ b/components/search_engines/template_url_fetcher.cc
@@ -19,6 +19,18 @@ namespace { +// In some network environments, silent failure can be avoided by retrying +// request on network change. This helps OpenSearch get through in such cases. +// See https://crbug.com/956689 for context. +constexpr int kOpenSearchRetryCount = 3; + +// Timeout for OpenSearch description document (OSDD) fetch request. +// Requests for a particular resource are limited to one. +// Requests may not receive a response, and in that case no +// further requests would be allowed. The timeout cleans up failed requests +// so that later attempts to fetch the OSDD can be made. +constexpr int kOpenSearchTimeoutSeconds = 30; + // Traffic annotation for RequestDelegate. const net::NetworkTrafficAnnotationTag kTrafficAnnotation = net::DefineNetworkTrafficAnnotation("open_search", R"( @@ -116,6 +128,10 @@ simple_url_loader_ = network::SimpleURLLoader::Create( std::move(resource_request), kTrafficAnnotation); simple_url_loader_->SetAllowHttpErrorResults(true); + simple_url_loader_->SetTimeoutDuration( + base::TimeDelta::FromSeconds(kOpenSearchTimeoutSeconds)); + simple_url_loader_->SetRetryOptions( + kOpenSearchRetryCount, network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE); simple_url_loader_->DownloadToString( url_loader_factory, base::BindOnce(
diff --git a/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.cc b/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.cc index 4e234eaf..87e00c3 100644 --- a/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.cc +++ b/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.cc
@@ -18,13 +18,12 @@ DeviceAccountsSynchronizerImpl::~DeviceAccountsSynchronizerImpl() = default; void DeviceAccountsSynchronizerImpl::ReloadAllAccountsFromSystem() { - token_service_delegate_->ReloadAccountsFromSystem( - /*primary_account_id=*/CoreAccountId()); + token_service_delegate_->ReloadAllAccountsFromSystem(); } void DeviceAccountsSynchronizerImpl::ReloadAccountFromSystem( const CoreAccountId& account_id) { - token_service_delegate_->AddAccountFromSystem(account_id); + token_service_delegate_->ReloadAccountFromSystem(account_id); } } // namespace identity
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h index f5cdef5d0..5780184c 100644 --- a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h +++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
@@ -49,10 +49,9 @@ // Subsequent calls to |RefreshTokenIsAvailable| will return |false|. void RevokeAllCredentials() override; - void AddAccountFromSystem(const CoreAccountId& account_id) override; + void ReloadAllAccountsFromSystem() override; - void ReloadAccountsFromSystem( - const CoreAccountId& primary_account_id) override; + void ReloadAccountFromSystem(const CoreAccountId& account_id) override; // Adds |account_id| to |accounts_| if it does not exist or udpates // the auth error state of |account_id| if it exists. Fires
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm index 8e2cb1f..dca7adf 100644 --- a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm +++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
@@ -266,14 +266,13 @@ ClearExcludedSecondaryAccounts(); } -void ProfileOAuth2TokenServiceIOSDelegate::AddAccountFromSystem( - const CoreAccountId& account_id) { - AddOrUpdateAccount(account_id); +void ProfileOAuth2TokenServiceIOSDelegate::ReloadAllAccountsFromSystem() { + ReloadCredentials(); } -void ProfileOAuth2TokenServiceIOSDelegate::ReloadAccountsFromSystem( - const CoreAccountId& /* ignored */) { - ReloadCredentials(); +void ProfileOAuth2TokenServiceIOSDelegate::ReloadAccountFromSystem( + const CoreAccountId& account_id) { + AddOrUpdateAccount(account_id); } std::unique_ptr<OAuth2AccessTokenFetcher>
diff --git a/components/tracing/common/trace_startup_config.cc b/components/tracing/common/trace_startup_config.cc index cdb0a32..babe9cc1 100644 --- a/components/tracing/common/trace_startup_config.cc +++ b/components/tracing/common/trace_startup_config.cc
@@ -31,9 +31,6 @@ const size_t kTraceConfigFileSizeLimit = 64 * 1024; const int kDefaultStartupDuration = 5; -// 95th percentile size of current startup traces size uploaded. -const size_t kMaxStartupTraceSizeInKb = 300; - // Trace config file path: // - Android: /data/local/chrome-trace-config.json // - Others: specified by --trace-config-file flag. @@ -42,7 +39,8 @@ FILE_PATH_LITERAL("/data/local/chrome-trace-config.json"); const char kDefaultStartupCategories[] = - "startup,browser,toplevel,EarlyJava,cc,Java,navigation,loading,gpu," + "startup,browser,toplevel,disabled-by-default-toplevel.flow,ipc,disabled-" + "by-default-ipc.flow,EarlyJava,cc,Java,navigation,loading,gpu," "disabled-by-default-cpu_profiler,download_service,-*"; #else const char kDefaultStartupCategories[] = @@ -74,7 +72,6 @@ {base::GetCurrentProcId()}); // First 10k events at start are sufficient to debug startup traces. trace_config.SetTraceBufferSizeInEvents(10000); - trace_config.SetTraceBufferSizeInKb(kMaxStartupTraceSizeInKb); trace_config.SetProcessFilterConfig(process_config); // Enable argument filter since we could be background tracing. trace_config.EnableArgumentFilter();
diff --git a/components/translate/core/browser/translate_manager.cc b/components/translate/core/browser/translate_manager.cc index 8a83711..d3e8a48 100644 --- a/components/translate/core/browser/translate_manager.cc +++ b/components/translate/core/browser/translate_manager.cc
@@ -283,12 +283,13 @@ TranslateErrors::IDENTICAL_LANGUAGES, triggered_from_menu); NotifyTranslateError(TranslateErrors::IDENTICAL_LANGUAGES); return; + } else { + // Trigger the "translating now" UI. + translate_client_->ShowTranslateUI( + translate::TRANSLATE_STEP_TRANSLATING, source_lang, target_lang, + TranslateErrors::NONE, triggered_from_menu); } - translate_client_->ShowTranslateUI( - translate::TRANSLATE_STEP_TRANSLATING, source_lang, target_lang, - TranslateErrors::NONE, triggered_from_menu); - TranslateScript* script = TranslateDownloadManager::GetInstance()->script(); DCHECK(script != nullptr);
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc index edd414b..42858fc 100644 --- a/components/translate/core/browser/translate_prefs.cc +++ b/components/translate/core/browser/translate_prefs.cc
@@ -83,13 +83,7 @@ base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kTranslateMobileManualTrigger{ - "TranslateAndroidManualTrigger", -#if defined(OS_IOS) - base::FEATURE_DISABLED_BY_DEFAULT -#else - base::FEATURE_ENABLED_BY_DEFAULT -#endif -}; + "TranslateAndroidManualTrigger", base::FEATURE_ENABLED_BY_DEFAULT}; DenialTimeUpdate::DenialTimeUpdate(PrefService* prefs, const std::string& language,
diff --git a/components/ui_devtools/css_agent.cc b/components/ui_devtools/css_agent.cc index 10b88b2c..37e9a10 100644 --- a/components/ui_devtools/css_agent.cc +++ b/components/ui_devtools/css_agent.cc
@@ -32,6 +32,15 @@ .build(); } +std::unique_ptr<protocol::Array<int>> BuildDefaultMatchingSelectors() { + auto matching_selectors = std::make_unique<protocol::Array<int>>(); + + // Add index 0 to matching delectors array, so frontend uses the class mame + // from the selectors array as the header for the properties section + matching_selectors->emplace_back(0); + return matching_selectors; +} + std::unique_ptr<CSS::CSSProperty> BuildCSSProperty(const std::string& name, int value) { return CSS::CSSProperty::create() @@ -60,6 +69,16 @@ return cssProperties; } +std::unique_ptr<Array<CSS::CSSProperty>> BuildCSSProperties( + const std::vector<UIElement::UIProperty>& properties_vector) { + auto css_properties = std::make_unique<Array<protocol::CSS::CSSProperty>>(); + for (const auto& property : properties_vector) { + css_properties->emplace_back( + BuildCSSProperty(property.name_, property.value_)); + } + return css_properties; +} + std::unique_ptr<CSS::CSSStyle> BuildCSSStyle(UIElement* ui_element) { gfx::Rect bounds; ui_element->GetBounds(&bounds); @@ -86,6 +105,77 @@ .build(); } +std::unique_ptr<CSS::CSSStyle> BuildCSSStyle( + std::string stylesheet_uid, + const std::vector<UIElement::UIProperty>& properties) { + return protocol::CSS::CSSStyle::create() + .setRange(BuildDefaultSourceRange()) + .setCssProperties(BuildCSSProperties(properties)) + .setShorthandEntries( + std::make_unique<Array<protocol::CSS::ShorthandEntry>>()) + .setStyleSheetId(stylesheet_uid) + .build(); +} + +std::unique_ptr<protocol::Array<protocol::CSS::Value>> BuildSelectors( + const std::string& name) { + auto selectors = std::make_unique<protocol::Array<protocol::CSS::Value>>(); + selectors->emplace_back(protocol::CSS::Value::create().setText(name).build()); + return selectors; +} + +std::unique_ptr<protocol::CSS::SelectorList> BuildSelectorList( + const std::string& name) { + return protocol::CSS::SelectorList::create() + .setSelectors(BuildSelectors(name)) + .build(); +} + +std::unique_ptr<protocol::CSS::CSSRule> BuildCSSRule( + std::string stylesheet_uid, + const UIElement::ClassProperties& class_properties) { + return protocol::CSS::CSSRule::create() + .setSelectorList(BuildSelectorList(class_properties.class_name_)) + .setStyle(BuildCSSStyle(stylesheet_uid, class_properties.properties_)) + .build(); +} + +std::vector<UIElement::ClassProperties> GetClassPropertiesWithBounds( + UIElement* ui_element) { + std::vector<UIElement::ClassProperties> properties_vector = + ui_element->GetCustomPropertiesForMatchedStyle(); + + // If GetCustomPropertiesForMatchedStyle not overridden to return custom + // properties, populate vector with bounds properties. + if (properties_vector.empty()) { + gfx::Rect bounds; + ui_element->GetBounds(&bounds); + std::vector<UIElement::UIProperty> bound_properties; + bound_properties.emplace_back(kX, base::NumberToString(bounds.x())); + bound_properties.emplace_back(kY, base::NumberToString(bounds.y())); + bound_properties.emplace_back(kWidth, base::NumberToString(bounds.width())); + bound_properties.emplace_back(kHeight, + base::NumberToString(bounds.height())); + if (ui_element->type() != VIEW) { + bool visible; + ui_element->GetVisible(&visible); + bound_properties.emplace_back(kVisibility, visible ? "true" : "false"); + } + properties_vector.emplace_back(ui_element->GetTypeName(), bound_properties); + } + + // Set base stylesheet ID to the last index in the vector, so when bounds + // properties are modified, CSSAgent can update and return the right + // properties section + ui_element->SetBaseStylesheetId(properties_vector.size() - 1); + return properties_vector; +} + +std::string BuildStylesheetUId(int node_id, int stylesheet_id) { + return base::NumberToString(node_id) + "_" + + base::NumberToString(stylesheet_id); +} + Response NodeNotFoundError(int node_id) { return Response::Error("Node with id=" + std::to_string(node_id) + " not found"); @@ -138,12 +228,14 @@ return Response::OK(); } -Response CSSAgent::getMatchedStylesForNode(int node_id, - Maybe<CSS::CSSStyle>* inline_style) { +Response CSSAgent::getMatchedStylesForNode( + int node_id, + protocol::Maybe<protocol::Array<protocol::CSS::RuleMatch>>* + matched_css_rules) { UIElement* ui_element = dom_agent_->GetElementFromNodeId(node_id); - *inline_style = GetStylesForUIElement(ui_element); - if (!inline_style) + if (!ui_element) return NodeNotFoundError(node_id); + *matched_css_rules = BuildMatchedStyles(ui_element); return Response::OK(); } @@ -153,10 +245,19 @@ auto updated_styles = std::make_unique<Array<CSS::CSSStyle>>(); for (const auto& edit : *edits) { int node_id; - if (!base::StringToInt(edit->getStyleSheetId(), &node_id)) - return Response::Error("Invalid node id"); + int stylesheet_id; + + std::vector<std::string> ids = + base::SplitString(edit->getStyleSheetId(), "_", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + if (ids.size() < 2 || !base::StringToInt(ids[0], &node_id) || + !base::StringToInt(ids[1], &stylesheet_id)) + return Response::Error("Invalid stylesheet id"); UIElement* ui_element = dom_agent_->GetElementFromNodeId(node_id); + + if (!ui_element) + return Response::Error("Node id not found"); // Handle setting properties from metadata for View. if (ui_element->type() == VIEW) ui_element->SetPropertiesFromString(edit->getText()); @@ -174,7 +275,10 @@ if (!SetPropertiesForUIElement(ui_element, updated_bounds, visible)) return NodeNotFoundError(node_id); - updated_styles->emplace_back(BuildCSSStyle(ui_element)); + updated_styles->emplace_back(BuildCSSStyle( + edit->getStyleSheetId(), GetClassPropertiesWithBounds(ui_element) + .at(stylesheet_id) + .properties_)); } *result = std::move(updated_styles); return Response::OK(); @@ -194,8 +298,10 @@ } void CSSAgent::InvalidateStyleSheet(UIElement* ui_element) { - // The stylesheetId for each node is equivalent to its node_id (as a string). - frontend()->styleSheetChanged(base::NumberToString(ui_element->node_id())); + // The stylesheetId for each node is equivalent to a string of its + // node_id + "_" + index of CSS::RuleMatch in vector. + frontend()->styleSheetChanged(BuildStylesheetUId( + ui_element->node_id(), ui_element->GetBaseStylesheetId())); } bool CSSAgent::GetPropertiesForUIElement(UIElement* ui_element, @@ -221,4 +327,22 @@ return false; } +std::unique_ptr<protocol::Array<protocol::CSS::RuleMatch>> +CSSAgent::BuildMatchedStyles(UIElement* ui_element) { + auto result = std::make_unique<protocol::Array<protocol::CSS::RuleMatch>>(); + std::vector<UIElement::ClassProperties> properties_vector = + GetClassPropertiesWithBounds(ui_element); + + for (size_t i = 0; i < properties_vector.size(); i++) { + result->emplace_back( + protocol::CSS::RuleMatch::create() + .setRule(BuildCSSRule(BuildStylesheetUId(ui_element->node_id(), i), + properties_vector[i])) + .setMatchingSelectors(BuildDefaultMatchingSelectors()) + .build()); + } + + return result; +} + } // namespace ui_devtools
diff --git a/components/ui_devtools/css_agent.h b/components/ui_devtools/css_agent.h index 1b651d2..b4b4ac9 100644 --- a/components/ui_devtools/css_agent.h +++ b/components/ui_devtools/css_agent.h
@@ -29,7 +29,8 @@ protocol::Response disable() override; protocol::Response getMatchedStylesForNode( int node_id, - protocol::Maybe<protocol::CSS::CSSStyle>* inline_style) override; + protocol::Maybe<protocol::Array<protocol::CSS::RuleMatch>>* + matched_css_rules) override; protocol::Response setStyleTexts( std::unique_ptr<protocol::Array<protocol::CSS::StyleDeclarationEdit>> edits, @@ -49,6 +50,9 @@ bool SetPropertiesForUIElement(UIElement* ui_element, const gfx::Rect& bounds, bool visible); + std::unique_ptr<protocol::Array<protocol::CSS::RuleMatch>> BuildMatchedStyles( + UIElement* ui_element); + DOMAgent* const dom_agent_; DISALLOW_COPY_AND_ASSIGN(CSSAgent);
diff --git a/components/ui_devtools/protocol.json b/components/ui_devtools/protocol.json index df34c0ef..b030b48 100644 --- a/components/ui_devtools/protocol.json +++ b/components/ui_devtools/protocol.json
@@ -261,10 +261,13 @@ ], "returns": [ { - "name": "inlineStyle", - "$ref": "CSSStyle", + "name": "matchedCSSRules", + "type": "array", + "items": { + "$ref": "RuleMatch" + }, "optional": true, - "description": "Inline style for the specified DOM node." + "description": "CSS rules matching this node, from all applicable stylesheets." } ] }, @@ -718,4 +721,4 @@ "major": "1", "minor": "3" } -} +} \ No newline at end of file
diff --git a/components/ui_devtools/ui_element.cc b/components/ui_devtools/ui_element.cc index 2802951..4b964d9 100644 --- a/components/ui_devtools/ui_element.cc +++ b/components/ui_devtools/ui_element.cc
@@ -16,6 +16,16 @@ } // namespace +UIElement::ClassProperties::ClassProperties( + std::string class_name, + std::vector<UIElement::UIProperty> properties) + : class_name_(class_name), properties_(properties) {} + +UIElement::ClassProperties::ClassProperties( + const UIElement::ClassProperties& other) = default; + +UIElement::ClassProperties::~ClassProperties() = default; + // static void UIElement::ResetNodeId() { node_ids = 0; @@ -107,6 +117,11 @@ return 0; } +std::vector<UIElement::ClassProperties> +UIElement::GetCustomPropertiesForMatchedStyle() const { + return {}; +} + UIElement::UIElement(const UIElementType type, UIElementDelegate* delegate, UIElement* parent)
diff --git a/components/ui_devtools/ui_element.h b/components/ui_devtools/ui_element.h index ecc8a4cd..214c967 100644 --- a/components/ui_devtools/ui_element.h +++ b/components/ui_devtools/ui_element.h
@@ -24,6 +24,22 @@ class UI_DEVTOOLS_EXPORT UIElement { public: + struct UI_DEVTOOLS_EXPORT UIProperty { + UIProperty(std::string name, std::string value) + : name_(name), value_(value) {} + + std::string name_; + std::string value_; + }; + struct UI_DEVTOOLS_EXPORT ClassProperties { + ClassProperties(std::string name, std::vector<UIProperty> properties); + ClassProperties(const ClassProperties& copy); + ~ClassProperties(); + + std::string class_name_; + std::vector<UIProperty> properties_; + }; + using UIElements = std::vector<UIElement*>; // resets node ids to 0 so that they are reusable @@ -40,6 +56,8 @@ bool is_updating() const { return is_updating_; } void set_is_updating(bool is_updating) { is_updating_ = is_updating; } void set_owns_children(bool owns_children) { owns_children_ = owns_children; } + int GetBaseStylesheetId() const { return base_stylesheet_id_; } + void SetBaseStylesheetId(int id) { base_stylesheet_id_ = id; } using ElementCompare = bool (*)(const UIElement*, const UIElement*); @@ -73,6 +91,10 @@ virtual std::vector<std::pair<std::string, std::string>> GetCustomProperties() const = 0; + // Returns properties grouped by the class they are from. + virtual std::vector<ClassProperties> GetCustomPropertiesForMatchedStyle() + const; + virtual void GetBounds(gfx::Rect* bounds) const = 0; virtual void SetBounds(const gfx::Rect& bounds) = 0; virtual void GetVisible(bool* visible) const = 0; @@ -113,6 +135,7 @@ UIElementDelegate* delegate_; bool is_updating_ = false; bool owns_children_ = true; + int base_stylesheet_id_; DISALLOW_COPY_AND_ASSIGN(UIElement); };
diff --git a/components/ui_devtools/views/element_utility.cc b/components/ui_devtools/views/element_utility.cc index ddc9a4cf..f315b4cf 100644 --- a/components/ui_devtools/views/element_utility.cc +++ b/components/ui_devtools/views/element_utility.cc
@@ -9,6 +9,7 @@ namespace ui_devtools { +// TODO(khamasaki): Remove AppendLayerProperties. void AppendLayerProperties( const ui::Layer* layer, std::vector<std::pair<std::string, std::string>>* ret) { @@ -49,4 +50,45 @@ } } +void AppendLayerPropertiesMatchedStyle( + const ui::Layer* layer, + std::vector<UIElement::UIProperty>* ret) { + ret->emplace_back("layer-type", + std::string(LayerTypeToString(layer->type()))); + ret->emplace_back("has-layer-mask", + layer->layer_mask_layer() ? "true" : "false"); + ret->emplace_back("layer-opacity", base::NumberToString((layer->opacity()))); + ret->emplace_back("layer-combined-opacity", + base::NumberToString(layer->GetCombinedOpacity())); + ret->emplace_back("background-blur", + base::NumberToString(layer->background_blur())); + ret->emplace_back("layer-blur", base::NumberToString(layer->layer_blur())); + ret->emplace_back("layer-saturation", + base::NumberToString(layer->layer_saturation())); + ret->emplace_back("layer-brightness", + base::NumberToString(layer->layer_brightness())); + ret->emplace_back("layer-grayscale", + base::NumberToString(layer->layer_grayscale())); + const ui::Layer::ShapeRects* alpha_shape_bounds = layer->alpha_shape(); + if (alpha_shape_bounds && alpha_shape_bounds->size()) { + gfx::Rect bounding_box; + for (auto& shape_bound : *alpha_shape_bounds) + bounding_box.Union(shape_bound); + ret->emplace_back("alpha-shape-bounding-box", bounding_box.ToString()); + } + const cc::Layer* cc_layer = layer->cc_layer_for_testing(); + if (cc_layer) { + // Property trees must be updated in order to get valid render surface + // reasons. + if (!cc_layer->layer_tree_host() || + cc_layer->layer_tree_host()->property_trees()->needs_rebuild) + return; + cc::RenderSurfaceReason render_surface = cc_layer->GetRenderSurfaceReason(); + if (render_surface != cc::RenderSurfaceReason::kNone) { + ret->emplace_back("render-surface-reason", + cc::RenderSurfaceReasonToString(render_surface)); + } + } +} + } // namespace ui_devtools
diff --git a/components/ui_devtools/views/element_utility.h b/components/ui_devtools/views/element_utility.h index d6697d4..b80a628 100644 --- a/components/ui_devtools/views/element_utility.h +++ b/components/ui_devtools/views/element_utility.h
@@ -8,6 +8,8 @@ #include <string> #include <vector> +#include "components/ui_devtools/ui_element.h" + namespace ui { class Layer; } @@ -23,6 +25,9 @@ const ui::Layer* layer, std::vector<std::pair<std::string, std::string>>* ret); +void AppendLayerPropertiesMatchedStyle(const ui::Layer* layer, + std::vector<UIElement::UIProperty>* ret); + } // namespace ui_devtools #endif // COMPONENTS_UI_DEVTOOLS_VIEWS_ELEMENT_UTILITY_H_
diff --git a/components/ui_devtools/views/view_element.cc b/components/ui_devtools/views/view_element.cc index 2fc9ae2..fbad7fc 100644 --- a/components/ui_devtools/views/view_element.cc +++ b/components/ui_devtools/views/view_element.cc
@@ -83,6 +83,49 @@ return ret; } +std::vector<UIElement::ClassProperties> +ViewElement::GetCustomPropertiesForMatchedStyle() const { + std::vector<UIElement::ClassProperties> ret; + + ui::Layer* layer = view_->layer(); + if (layer) { + std::vector<UIElement::UIProperty> layer_properties; + AppendLayerPropertiesMatchedStyle(layer, &layer_properties); + ret.emplace_back("Layer", layer_properties); + } + + std::vector<UIElement::UIProperty> class_properties; + views::metadata::ClassMetaData* metadata = view_->GetClassMetaData(); + for (auto member = metadata->begin(); member != metadata->end(); member++) { + if (member.GetCurrentCollectionName() == "View" && + class_properties.empty()) { + gfx::Rect bounds = view_->bounds(); + class_properties.emplace_back("x", base::NumberToString(bounds.x())); + class_properties.emplace_back("y", base::NumberToString(bounds.y())); + class_properties.emplace_back("width", + base::NumberToString(bounds.width())); + class_properties.emplace_back("height", + base::NumberToString(bounds.height())); + class_properties.emplace_back("is-drawn", + view_->IsDrawn() ? "true" : "false"); + base::string16 description = view_->GetTooltipText(gfx::Point()); + if (!description.empty()) + class_properties.emplace_back("tooltip", + base::UTF16ToUTF8(description)); + } + + class_properties.emplace_back( + (*member)->member_name(), + base::UTF16ToUTF8((*member)->GetValueAsString(view_))); + + if (member.IsLastMember()) { + ret.emplace_back(member.GetCurrentCollectionName(), class_properties); + class_properties.clear(); + } + } + return ret; +} + void ViewElement::GetBounds(gfx::Rect* bounds) const { *bounds = view_->bounds(); }
diff --git a/components/ui_devtools/views/view_element.h b/components/ui_devtools/views/view_element.h index afe1b4f..acc3313 100644 --- a/components/ui_devtools/views/view_element.h +++ b/components/ui_devtools/views/view_element.h
@@ -33,6 +33,8 @@ // UIElement: std::vector<std::pair<std::string, std::string>> GetCustomProperties() const override; + std::vector<UIElement::ClassProperties> GetCustomPropertiesForMatchedStyle() + const override; void GetBounds(gfx::Rect* bounds) const override; void SetBounds(const gfx::Rect& bounds) override; void GetVisible(bool* visible) const override;
diff --git a/components/ui_devtools/views/window_element.cc b/components/ui_devtools/views/window_element.cc index 649a5a0..d6cd15d 100644 --- a/components/ui_devtools/views/window_element.cc +++ b/components/ui_devtools/views/window_element.cc
@@ -87,6 +87,43 @@ return ret; } +std::vector<UIElement::ClassProperties> +WindowElement::GetCustomPropertiesForMatchedStyle() const { + std::vector<UIElement::ClassProperties> ret; + std::vector<UIElement::UIProperty> cur_properties; + + ui::Layer* layer = window_->layer(); + if (layer) { + AppendLayerPropertiesMatchedStyle(layer, &cur_properties); + ret.emplace_back("Layer", cur_properties); + cur_properties.clear(); + } + + gfx::Rect bounds; + GetBounds(&bounds); + cur_properties.emplace_back("x", base::NumberToString(bounds.x())); + cur_properties.emplace_back("y", base::NumberToString(bounds.y())); + cur_properties.emplace_back("width", base::NumberToString(bounds.width())); + cur_properties.emplace_back("height", base::NumberToString(bounds.height())); + + std::string state_str = + aura::Window::OcclusionStateToString(window_->occlusion_state()); + // change OcclusionState::UNKNOWN to UNKNOWN + state_str = state_str.substr(state_str.find("::") + 2); + cur_properties.emplace_back("occlusion-state", state_str); + cur_properties.emplace_back("surface", + window_->GetSurfaceId().is_valid() + ? window_->GetSurfaceId().ToString() + : "none"); + cur_properties.emplace_back("capture", + window_->HasCapture() ? "true" : "false"); + cur_properties.emplace_back( + "is-activatable", wm::CanActivateWindow(window_) ? "true" : "false"); + + ret.emplace_back("Window", cur_properties); + return ret; +} + void WindowElement::GetBounds(gfx::Rect* bounds) const { *bounds = window_->bounds(); }
diff --git a/components/ui_devtools/views/window_element.h b/components/ui_devtools/views/window_element.h index 20b375c..9b063624 100644 --- a/components/ui_devtools/views/window_element.h +++ b/components/ui_devtools/views/window_element.h
@@ -36,6 +36,8 @@ // UIElement: std::vector<std::pair<std::string, std::string>> GetCustomProperties() const override; + std::vector<UIElement::ClassProperties> GetCustomPropertiesForMatchedStyle() + const override; void GetBounds(gfx::Rect* bounds) const override; void SetBounds(const gfx::Rect& bounds) override; void GetVisible(bool* visible) const override;
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn index 3f6def06..e8981817 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn
@@ -314,8 +314,6 @@ "display_embedder/skia_output_surface_dependency_impl.h", "display_embedder/skia_output_surface_impl.cc", "display_embedder/skia_output_surface_impl.h", - "display_embedder/skia_output_surface_impl_non_ddl.cc", - "display_embedder/skia_output_surface_impl_non_ddl.h", "display_embedder/skia_output_surface_impl_on_gpu.cc", "display_embedder/skia_output_surface_impl_on_gpu.h", "gl/gpu_service_impl.cc",
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc index fd4dbff3..2ca528a 100644 --- a/components/viz/service/display/direct_renderer.cc +++ b/components/viz/service/display/direct_renderer.cc
@@ -789,10 +789,12 @@ gfx::Rect DirectRenderer::ComputeScissorRectForRenderPass( const RenderPass* render_pass) const { const RenderPass* root_render_pass = current_frame()->root_render_pass; - const gfx::Rect root_damage_rect = current_frame()->root_damage_rect; + gfx::Rect root_damage_rect = current_frame()->root_damage_rect; - if (render_pass == root_render_pass) + if (render_pass == root_render_pass) { + root_damage_rect.Union(output_surface_->GetCurrentFramebufferDamage()); return root_damage_rect; + } // If the root damage rect has been expanded due to overlays, all the other // damage rect calculations are incorrect.
diff --git a/components/viz/service/display/output_surface.cc b/components/viz/service/display/output_surface.cc index 81f92a2..097fdcac 100644 --- a/components/viz/service/display/output_surface.cc +++ b/components/viz/service/display/output_surface.cc
@@ -16,6 +16,7 @@ #include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/gles2_interface.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/swap_result.h" namespace viz { @@ -35,6 +36,10 @@ OutputSurface::~OutputSurface() = default; +gfx::Rect OutputSurface::GetCurrentFramebufferDamage() const { + return gfx::Rect(); +} + SkiaOutputSurface* OutputSurface::AsSkiaOutputSurface() { return nullptr; }
diff --git a/components/viz/service/display/output_surface.h b/components/viz/service/display/output_surface.h index 343e490b..564c4d2 100644 --- a/components/viz/service/display/output_surface.h +++ b/components/viz/service/display/output_surface.h
@@ -26,6 +26,7 @@ namespace gfx { class ColorSpace; +class Rect; class Size; struct SwapResponse; } // namespace gfx @@ -136,6 +137,12 @@ // after returning from this method in order to unblock the next frame. virtual void SwapBuffers(OutputSurfaceFrame frame) = 0; + // Returns a rectangle whose contents may have changed since the current + // buffer was last submitted and they need to be redrawn. For partial swap, + // the contents outside this rectangle can be considered valid and do not need + // to be redrawn. + virtual gfx::Rect GetCurrentFramebufferDamage() const; + // Updates the GpuFence associated with this surface. The id of a newly // created GpuFence is returned, or if an error occurs, or fences are not // supported, the special id of 0 (meaning "no fence") is returned. In all
diff --git a/components/viz/service/display_embedder/buffer_queue.cc b/components/viz/service/display_embedder/buffer_queue.cc index e874cd7..7003bbb 100644 --- a/components/viz/service/display_embedder/buffer_queue.cc +++ b/components/viz/service/display_embedder/buffer_queue.cc
@@ -12,11 +12,8 @@ #include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" #include "gpu/command_buffer/common/gpu_memory_buffer_support.h" -#include "third_party/skia/include/core/SkRect.h" -#include "third_party/skia/include/core/SkRegion.h" #include "ui/display/types/display_snapshot.h" #include "ui/gfx/gpu_memory_buffer.h" -#include "ui/gfx/skia_util.h" namespace viz { @@ -52,21 +49,6 @@ return 0u; } -void BufferQueue::CopyBufferDamage(unsigned texture, - unsigned source_texture, - const gfx::Rect& new_damage, - const gfx::Rect& old_damage) { - SkRegion region(gfx::RectToSkIRect(old_damage)); - if (!region.op(gfx::RectToSkIRect(new_damage), SkRegion::kDifference_Op)) - return; - for (SkRegion::Iterator it(region); !it.done(); it.next()) { - const SkIRect& rect = it.rect(); - gl_->CopySubTextureCHROMIUM( - source_texture, 0, texture_target_, texture, 0, rect.x(), rect.y(), - rect.x(), rect.y(), rect.width(), rect.height(), false, false, false); - } -} - void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) { if (displayed_surface_) displayed_surface_->damage.Union(damage); @@ -78,40 +60,15 @@ } } -void BufferQueue::CopyDamageForCurrentSurface(const gfx::Rect& damage) { - if (!current_surface_) - return; - - if (damage != gfx::Rect(size_)) { - // Copy damage from the most recently swapped buffer. In the event that - // the buffer was destroyed and failed to recreate, pick from the most - // recently available buffer. - unsigned texture_id = 0; - for (auto& surface : base::Reversed(in_flight_surfaces_)) { - if (surface) { - texture_id = surface->texture; - break; - } - } - if (!texture_id && displayed_surface_) - texture_id = displayed_surface_->texture; - - if (texture_id) { - CopyBufferDamage(current_surface_->texture, texture_id, damage, - current_surface_->damage); - } - } - current_surface_->damage = gfx::Rect(); +gfx::Rect BufferQueue::CurrentBufferDamage() const { + DCHECK(current_surface_); + return current_surface_->damage; } void BufferQueue::SwapBuffers(const gfx::Rect& damage) { - if (damage.IsEmpty()) { - in_flight_surfaces_.push_back(std::move(current_surface_)); - return; - } - - DCHECK(!current_surface_ || current_surface_->damage.IsEmpty()); UpdateBufferDamage(damage); + if (current_surface_) + current_surface_->damage = gfx::Rect(); in_flight_surfaces_.push_back(std::move(current_surface_)); }
diff --git a/components/viz/service/display_embedder/buffer_queue.h b/components/viz/service/display_embedder/buffer_queue.h index 4baa6acb..41d28e72 100644 --- a/components/viz/service/display_embedder/buffer_queue.h +++ b/components/viz/service/display_embedder/buffer_queue.h
@@ -53,10 +53,16 @@ // current buffer and one could not be created. unsigned GetCurrentBuffer(unsigned* stencil); + // Returns a rectangle whose contents may have changed since the current + // buffer was last submitted and they need to be redrawn. For partial swap, + // only the contents outside this rectangle can be considered valid and do not + // need to be redrawn. + gfx::Rect CurrentBufferDamage() const; + // Called by the user of this object to indicate that the buffer currently - // marked for drawing should be moved to the list of in-flight buffers. If - // |damage| is not empty, the damage rectangle for all buffers except the - // one currently marked for drawing is unioned with |damage|. + // marked for drawing should be moved to the list of in-flight buffers. + // |damage| represents the rectangle containing the damaged area since the + // last SwapBuffers. void SwapBuffers(const gfx::Rect& damage); // Called by the user of this object to indicate that a previous request to @@ -78,10 +84,6 @@ const gfx::ColorSpace& color_space, bool use_stencil); - // Copies the damage from the most recently swapped available buffer into the - // current buffer. - void CopyDamageForCurrentSurface(const gfx::Rect& damage); - uint32_t internal_format() const { return internal_format_; } gfx::BufferFormat buffer_format() const { return format_; } uint32_t texture_target() const { return texture_target_; } @@ -108,13 +110,6 @@ void FreeSurfaceResources(AllocatedSurface* surface); - // Copy everything that is in |copy_rect|, except for what is in - // |exclude_rect| from |source_texture| to |texture|. - virtual void CopyBufferDamage(unsigned texture, - unsigned source_texture, - const gfx::Rect& new_damage, - const gfx::Rect& old_damage); - void UpdateBufferDamage(const gfx::Rect& damage); // Return a surface, available to be drawn into.
diff --git a/components/viz/service/display_embedder/buffer_queue_unittest.cc b/components/viz/service/display_embedder/buffer_queue_unittest.cc index a6ecd16..47a709c 100644 --- a/components/viz/service/display_embedder/buffer_queue_unittest.cc +++ b/components/viz/service/display_embedder/buffer_queue_unittest.cc
@@ -104,20 +104,6 @@ const unsigned int kBufferQueueInternalformat = GL_RGBA; const gfx::BufferFormat kBufferQueueFormat = gfx::BufferFormat::RGBA_8888; -class MockBufferQueue : public BufferQueue { - public: - MockBufferQueue(gpu::gles2::GLES2Interface* gl, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - const gpu::Capabilities& capabilities) - : BufferQueue(gl, - kBufferQueueFormat, - gpu_memory_buffer_manager, - kFakeSurfaceHandle, - capabilities) {} - MOCK_METHOD4(CopyBufferDamage, - void(unsigned, unsigned, const gfx::Rect&, const gfx::Rect&)); -}; - class BufferQueueTest : public ::testing::Test { public: BufferQueueTest() {} @@ -130,9 +116,10 @@ context_provider_ = TestContextProvider::Create(std::move(context)); context_provider_->BindToCurrentThread(); gpu_memory_buffer_manager_.reset(new StubGpuMemoryBufferManager); - mock_output_surface_ = new MockBufferQueue( - context_provider_->ContextGL(), gpu_memory_buffer_manager_.get(), - context_provider_->ContextCapabilities()); + mock_output_surface_ = + new BufferQueue(context_provider_->ContextGL(), kBufferQueueFormat, + gpu_memory_buffer_manager_.get(), kFakeSurfaceHandle, + context_provider_->ContextCapabilities()); output_surface_.reset(mock_output_surface_); } @@ -184,7 +171,6 @@ } void SwapBuffers(const gfx::Rect& damage) { - output_surface_->CopyDamageForCurrentSurface(damage); output_surface_->SwapBuffers(damage); } @@ -214,7 +200,7 @@ scoped_refptr<TestContextProvider> context_provider_; std::unique_ptr<StubGpuMemoryBufferManager> gpu_memory_buffer_manager_; std::unique_ptr<BufferQueue> output_surface_; - MockBufferQueue* mock_output_surface_; + BufferQueue* mock_output_surface_; }; namespace { @@ -300,43 +286,9 @@ EXPECT_GT(output_surface->GetCurrentBuffer(&stencil), 0u); } -TEST(BufferQueueStandaloneTest, CopyBufferDamage) { - scoped_refptr<TestContextProvider> context_provider = - TestContextProvider::Create(); - context_provider->BindToCurrentThread(); - std::unique_ptr<StubGpuMemoryBufferManager> gpu_memory_buffer_manager; - std::unique_ptr<BufferQueue> output_surface; - gpu_memory_buffer_manager.reset(new StubGpuMemoryBufferManager); - - output_surface.reset( - new BufferQueue(context_provider->ContextGL(), kBufferQueueFormat, - gpu_memory_buffer_manager.get(), kFakeSurfaceHandle, - context_provider->ContextCapabilities())); - EXPECT_TRUE( - output_surface->Reshape(screen_size, 1.0f, gfx::ColorSpace(), false)); - // Trigger a sub-buffer copy to exercise all paths. - unsigned stencil; - EXPECT_GT(output_surface->GetCurrentBuffer(&stencil), 0u); - output_surface->CopyDamageForCurrentSurface(screen_rect); - output_surface->SwapBuffers(screen_rect); - output_surface->PageFlipComplete(); - EXPECT_GT(output_surface->GetCurrentBuffer(&stencil), 0u); - output_surface->CopyDamageForCurrentSurface(small_damage); - output_surface->SwapBuffers(small_damage); -} - TEST_F(BufferQueueTest, PartialSwapReuse) { EXPECT_TRUE( output_surface_->Reshape(screen_size, 1.0f, gfx::ColorSpace(), false)); - EXPECT_CALL(*mock_output_surface_, - CopyBufferDamage(_, _, small_damage, screen_rect)) - .Times(1); - EXPECT_CALL(*mock_output_surface_, - CopyBufferDamage(_, _, small_damage, small_damage)) - .Times(1); - EXPECT_CALL(*mock_output_surface_, - CopyBufferDamage(_, _, large_damage, small_damage)) - .Times(1); SendFullFrame(); SendDamagedFrame(small_damage); SendDamagedFrame(small_damage); @@ -348,9 +300,6 @@ TEST_F(BufferQueueTest, PartialSwapFullFrame) { EXPECT_TRUE( output_surface_->Reshape(screen_size, 1.0f, gfx::ColorSpace(), false)); - EXPECT_CALL(*mock_output_surface_, - CopyBufferDamage(_, _, small_damage, screen_rect)) - .Times(1); SendFullFrame(); SendDamagedFrame(small_damage); SendFullFrame(); @@ -358,15 +307,37 @@ EXPECT_EQ(next_frame()->damage, screen_rect); } +// Make sure that each time we swap buffers, the damage gets propagated to the +// previously swapped buffers. +TEST_F(BufferQueueTest, PartialSwapWithTripleBuffering) { + unsigned stencil = 0; + EXPECT_TRUE( + output_surface_->Reshape(screen_size, 1.0f, gfx::ColorSpace(), false)); + SendFullFrame(); + SendFullFrame(); + // Let's triple buffer. + EXPECT_GT(output_surface_->GetCurrentBuffer(&stencil), 0u); + SwapBuffers(small_damage); + EXPECT_GT(output_surface_->GetCurrentBuffer(&stencil), 0u); + EXPECT_EQ(3, CountBuffers()); + // The whole buffer needs to be redrawn since it's a newly allocated buffer + EXPECT_EQ(output_surface_->CurrentBufferDamage(), screen_rect); + + SendDamagedFrame(overlapping_damage); + // The next buffer should include damage from |overlapping_damage| and + // |small_damage|. + EXPECT_GT(output_surface_->GetCurrentBuffer(&stencil), 0u); + const auto current_buffer_damage = output_surface_->CurrentBufferDamage(); + EXPECT_TRUE(current_buffer_damage.Contains(overlapping_damage)); + EXPECT_TRUE(current_buffer_damage.Contains(small_damage)); + + // Let's make sure the damage is not trivially the whole screen. + EXPECT_NE(current_buffer_damage, screen_rect); +} + TEST_F(BufferQueueTest, PartialSwapOverlapping) { EXPECT_TRUE( output_surface_->Reshape(screen_size, 1.0f, gfx::ColorSpace(), false)); - EXPECT_CALL(*mock_output_surface_, - CopyBufferDamage(_, _, small_damage, screen_rect)) - .Times(1); - EXPECT_CALL(*mock_output_surface_, - CopyBufferDamage(_, _, overlapping_damage, small_damage)) - .Times(1); SendFullFrame(); SendDamagedFrame(small_damage); @@ -596,38 +567,20 @@ SwapBuffers(screen_rect); EXPECT_FALSE(current_frame()); - // Try another swap. It should copy the buffer damage from the back - // surface. gpu_memory_buffer_manager_->set_allocate_succeeds(true); EXPECT_GT(output_surface_->GetCurrentBuffer(&stencil), 0u); - unsigned int source_texture = in_flight_surfaces().front()->texture; - unsigned int target_texture = current_frame()->texture; - testing::Mock::VerifyAndClearExpectations(mock_output_surface_); - EXPECT_CALL(*mock_output_surface_, - CopyBufferDamage(target_texture, source_texture, small_damage, _)) - .Times(1); SwapBuffers(small_damage); - testing::Mock::VerifyAndClearExpectations(mock_output_surface_); - // Destroy the just-created buffer, and try another swap. The copy should - // come from the displayed surface (because both in-flight surfaces are - // gone now). + // Destroy the just-created buffer, and try another swap. output_surface_->PageFlipComplete(); in_flight_surfaces().back().reset(); EXPECT_EQ(2u, in_flight_surfaces().size()); for (auto& surface : in_flight_surfaces()) EXPECT_FALSE(surface); EXPECT_GT(output_surface_->GetCurrentBuffer(&stencil), 0u); - source_texture = displayed_frame()->texture; EXPECT_TRUE(current_frame()); EXPECT_TRUE(displayed_frame()); - target_texture = current_frame()->texture; - testing::Mock::VerifyAndClearExpectations(mock_output_surface_); - EXPECT_CALL(*mock_output_surface_, - CopyBufferDamage(target_texture, source_texture, small_damage, _)) - .Times(1); SwapBuffers(small_damage); - testing::Mock::VerifyAndClearExpectations(mock_output_surface_); } } // namespace
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc b/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc index 01db6191..8c125590 100644 --- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc +++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
@@ -100,11 +100,6 @@ } } -void GLOutputSurfaceBufferQueue::SetDrawRectangle(const gfx::Rect& damage) { - GLOutputSurface::SetDrawRectangle(damage); - buffer_queue_->CopyDamageForCurrentSurface(damage); -} - void GLOutputSurfaceBufferQueue::SwapBuffers(OutputSurfaceFrame frame) { DCHECK(buffer_queue_);
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h b/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h index 594b38b..0642ecd0 100644 --- a/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h +++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h
@@ -61,7 +61,6 @@ bool IsDisplayedAsOverlayPlane() const override; unsigned GetOverlayTextureId() const override; gfx::BufferFormat GetOverlayBufferFormat() const override; - void SetDrawRectangle(const gfx::Rect& damage) override; // GLOutputSurface: void DidReceiveSwapBuffersAck(const gfx::SwapResponse& response) override;
diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.cc b/components/viz/service/display_embedder/output_surface_provider_impl.cc index abc5488..15e1edf3 100644 --- a/components/viz/service/display_embedder/output_surface_provider_impl.cc +++ b/components/viz/service/display_embedder/output_surface_provider_impl.cc
@@ -20,7 +20,6 @@ #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h" #include "components/viz/service/display_embedder/skia_output_surface_impl.h" -#include "components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.h" #include "components/viz/service/display_embedder/software_output_surface.h" #include "components/viz/service/display_embedder/viz_process_context_provider.h" #include "components/viz/service/gl/gpu_service_impl.h" @@ -111,33 +110,7 @@ return nullptr; #else if (renderer_settings.use_skia_renderer_non_ddl) { - bool is_gles2 = - (gl::GetGLImplementation() == gl::kGLImplementationEGLGLES2) || - (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE); - DCHECK(is_gles2) << "SkiaRendererNonDDL is only supported with GLES2."; - auto gl_surface = gpu::ImageTransportSurface::CreateNativeSurface( - nullptr, surface_handle, gl::GLSurfaceFormat()); - if (!shared_context_state_) { - auto gl_share_group = base::MakeRefCounted<gl::GLShareGroup>(); - auto gl_context = gl::init::CreateGLContext( - gl_share_group.get(), gl_surface.get(), gl::GLContextAttribs()); - gl_context->MakeCurrent(gl_surface.get()); - shared_context_state_ = base::MakeRefCounted<gpu::SharedContextState>( - std::move(gl_share_group), gl_surface, std::move(gl_context), - false /* use_virtualized_gl_contexts */, base::DoNothing::Once(), - nullptr /* vulkan_context_provider */); - shared_context_state_->InitializeGrContext( - gpu::GpuDriverBugWorkarounds(), nullptr /* gr_shader_cache */); - mailbox_manager_ = gpu::gles2::CreateMailboxManager( - gpu_service_impl_->gpu_preferences()); - DCHECK(mailbox_manager_->UsesSync()); - } - output_surface = std::make_unique<SkiaOutputSurfaceImplNonDDL>( - std::move(gl_surface), shared_context_state_, mailbox_manager_.get(), - gpu_service_impl_->shared_image_manager(), - gpu_service_impl_->sync_point_manager(), - true /* need_swapbuffers_ack */); - + NOTIMPLEMENTED(); } else { output_surface = std::make_unique<SkiaOutputSurfaceImpl>( std::make_unique<SkiaOutputSurfaceDependencyImpl>(gpu_service_impl_,
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc b/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc deleted file mode 100644 index 770ba596..0000000 --- a/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.cc +++ /dev/null
@@ -1,534 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.h" - -#include <utility> - -#include "base/atomic_sequence_num.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback_helpers.h" -#include "base/synchronization/waitable_event.h" -#include "components/viz/common/frame_sinks/begin_frame_source.h" -#include "components/viz/common/frame_sinks/copy_output_request.h" -#include "components/viz/common/gpu/vulkan_context_provider.h" -#include "components/viz/common/resources/resource_format_utils.h" -#include "components/viz/service/display/output_surface_client.h" -#include "components/viz/service/display/output_surface_frame.h" -#include "components/viz/service/display/resource_metadata.h" -#include "components/viz/service/display_embedder/image_context.h" -#include "gpu/command_buffer/common/shared_image_usage.h" -#include "gpu/command_buffer/common/swap_buffers_complete_params.h" -#include "gpu/command_buffer/service/mailbox_manager.h" -#include "gpu/command_buffer/service/shared_image_factory.h" -#include "gpu/command_buffer/service/shared_image_representation.h" -#include "gpu/command_buffer/service/skia_utils.h" -#include "gpu/command_buffer/service/sync_point_manager.h" -#include "gpu/command_buffer/service/texture_base.h" -#include "gpu/vulkan/buildflags.h" -#include "third_party/skia/include/core/SkPromiseImageTexture.h" -#include "third_party/skia/include/gpu/GrBackendSemaphore.h" -#include "ui/gfx/skia_util.h" -#include "ui/gl/color_space_utils.h" -#include "ui/gl/gl_bindings.h" -#include "ui/gl/gl_context.h" -#include "ui/gl/gl_gl_api_implementation.h" -#include "ui/gl/gl_surface.h" -#include "ui/gl/gl_version_info.h" - -#if BUILDFLAG(ENABLE_VULKAN) -#include "third_party/skia/src/gpu/vk/GrVkSecondaryCBDrawContext.h" -#endif - -namespace viz { - -namespace { - -scoped_refptr<gpu::SyncPointClientState> CreateSyncPointClientState( - gpu::SyncPointManager* sync_point_manager, - gpu::SequenceId sequence_id) { - static uint64_t next_command_buffer_id = 0u; - auto command_buffer_id = - gpu::CommandBufferId::FromUnsafeValue(++next_command_buffer_id); - return sync_point_manager->CreateSyncPointClientState( - gpu::CommandBufferNamespace::VIZ_SKIA_OUTPUT_SURFACE_NON_DDL, - command_buffer_id, sequence_id); -} - -std::unique_ptr<gpu::SharedImageRepresentationFactory> -CreateSharedImageRepresentationFactory(gpu::SharedImageManager* manager) { - if (!manager) - return nullptr; - // TODO(https://crbug.com/899905): Use a real MemoryTracker, not nullptr. - return std::make_unique<gpu::SharedImageRepresentationFactory>( - manager, nullptr /* tracker */); -} - -} // namespace - -SkiaOutputSurfaceImplNonDDL::SkiaOutputSurfaceImplNonDDL( - scoped_refptr<gl::GLSurface> gl_surface, - scoped_refptr<gpu::SharedContextState> shared_context_state, - gpu::MailboxManager* mailbox_manager, - gpu::SharedImageManager* shared_image_manager, - gpu::SyncPointManager* sync_point_manager, - bool need_swapbuffers_ack) - : gl_surface_(std::move(gl_surface)), - shared_context_state_(std::move(shared_context_state)), - mailbox_manager_(mailbox_manager), - sir_factory_( - CreateSharedImageRepresentationFactory(shared_image_manager)), - sync_point_order_data_(sync_point_manager->CreateSyncPointOrderData()), - sync_point_client_state_( - CreateSyncPointClientState(sync_point_manager, - sync_point_order_data_->sequence_id())), - need_swapbuffers_ack_(need_swapbuffers_ack), - weak_ptr_factory_(this) {} - -SkiaOutputSurfaceImplNonDDL::~SkiaOutputSurfaceImplNonDDL() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void SkiaOutputSurfaceImplNonDDL::EnsureBackbuffer() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - NOTIMPLEMENTED(); -} - -void SkiaOutputSurfaceImplNonDDL::DiscardBackbuffer() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - NOTIMPLEMENTED(); -} - -void SkiaOutputSurfaceImplNonDDL::Reshape(const gfx::Size& size, - float device_scale_factor, - const gfx::ColorSpace& color_space, - bool has_alpha, - bool use_stencil) { - reshape_surface_size_ = size; - reshape_device_scale_factor_ = device_scale_factor; - reshape_color_space_ = color_space; - reshape_has_alpha_ = has_alpha; - reshape_use_stencil_ = use_stencil; - - if (shared_context_state_->GrContextIsVulkan()) { - auto* context_provider = shared_context_state_->vk_context_provider(); - DCHECK(context_provider->GetGrSecondaryCBDrawContext()); - } else if (shared_context_state_->GrContextIsGL()) { - gl::GLSurface::ColorSpace surface_color_space = - gl::ColorSpaceUtils::GetGLSurfaceColorSpace(color_space); - gl_surface_->Resize(size, device_scale_factor, surface_color_space, - has_alpha); - - backing_framebuffer_object_ = gl_surface_->GetBackingFramebufferObject(); - - SkSurfaceProps surface_props = - SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType); - - GrGLFramebufferInfo framebuffer_info; - framebuffer_info.fFBOID = backing_framebuffer_object_; - framebuffer_info.fFormat = GL_RGBA8; - - GrBackendRenderTarget render_target(size.width(), size.height(), 0, 8, - framebuffer_info); - - sk_surface_ = SkSurface::MakeFromBackendRenderTarget( - gr_context(), render_target, kBottomLeft_GrSurfaceOrigin, - kRGBA_8888_SkColorType, color_space.ToSkColorSpace(), &surface_props); - DCHECK(sk_surface_); - } else { - NOTIMPLEMENTED(); - } -} - -SkCanvas* SkiaOutputSurfaceImplNonDDL::BeginPaintCurrentFrame() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK_EQ(current_render_pass_id_, 0u); - DCHECK(!scoped_gpu_task_); - scoped_gpu_task_.emplace(sync_point_order_data_.get()); - - if (shared_context_state_->GrContextIsVulkan()) { -#if BUILDFLAG(ENABLE_VULKAN) - DCHECK(!draw_context_); - draw_context_ = shared_context_state_->vk_context_provider() - ->GetGrSecondaryCBDrawContext(); - DCHECK(draw_context_); - return draw_context_->getCanvas(); -#else - NOTREACHED(); - return nullptr; -#endif - } else { - DCHECK(sk_surface_); - // If FBO is changed, we need call Reshape() to recreate |sk_surface_|. - if (backing_framebuffer_object_ != - gl_surface_->GetBackingFramebufferObject()) { - Reshape(reshape_surface_size_, reshape_device_scale_factor_, - reshape_color_space_, reshape_has_alpha_, reshape_use_stencil_); - } - sk_current_surface_ = sk_surface_.get(); - return sk_current_surface_->getCanvas(); - } -} - -sk_sp<SkImage> SkiaOutputSurfaceImplNonDDL::MakePromiseSkImage( - const ResourceMetadata& metadata) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (metadata.mailbox_holder.mailbox.IsSharedImage() && sir_factory_) { - auto& image_context = promise_image_cache_[metadata.resource_id]; - if (!image_context) - image_context = MakeSkImageFromSharedImage(metadata); - if (image_context) { - if (!image_context->representation_is_being_accessed) { - std::vector<GrBackendSemaphore> begin_semaphores; - auto promise_image_texture = - image_context->representation->BeginReadAccess( - &begin_semaphores, &pending_semaphores_); - // The image has been created and cached. It is too late to tell skia - // the backing of the cached image is not accessible right now, so crash - // for now. - // TODO(penghuang): find a way to notify skia. - CHECK(promise_image_texture); - image_context->representation_is_being_accessed = true; - WaitSemaphores(std::move(begin_semaphores)); - } - images_in_current_paint_.push_back(image_context.get()); - } - return image_context ? image_context->image : nullptr; - } - - GrBackendTexture backend_texture; - if (!GetGrBackendTexture(metadata, &backend_texture)) { - DLOG(ERROR) << "Failed to GetGrBackendTexture from mailbox."; - return nullptr; - } - - auto sk_color_type = ResourceFormatToClosestSkColorType( - true /* gpu_compositing */, metadata.resource_format); - return SkImage::MakeFromTexture( - gr_context(), backend_texture, kTopLeft_GrSurfaceOrigin, sk_color_type, - metadata.alpha_type, metadata.color_space.ToSkColorSpace()); -} - -sk_sp<SkImage> SkiaOutputSurfaceImplNonDDL::MakePromiseSkImageFromYUV( - const std::vector<ResourceMetadata>& metadatas, - SkYUVColorSpace yuv_color_space, - sk_sp<SkColorSpace> dst_color_space, - bool has_alpha) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK((has_alpha && (metadatas.size() == 3 || metadatas.size() == 4)) || - (!has_alpha && (metadatas.size() == 2 || metadatas.size() == 3))); - - SkYUVAIndex indices[4] = {}; - PrepareYUVATextureIndices(metadatas, has_alpha, indices); - - GrBackendTexture yuva_textures[4] = {}; - for (size_t i = 0; i < metadatas.size(); ++i) { - const auto& metadata = metadatas[i]; - if (!GetGrBackendTexture(metadata, &yuva_textures[i])) - DLOG(ERROR) << "Failed to GetGrBackendTexture from a mailbox."; - } - - return SkImage::MakeFromYUVATextures( - gr_context(), yuv_color_space, yuva_textures, indices, - SkISize::Make(yuva_textures[0].width(), yuva_textures[1].height()), - kTopLeft_GrSurfaceOrigin, dst_color_space); -} - -void SkiaOutputSurfaceImplNonDDL::ReleaseCachedResources( - const std::vector<ResourceId>& ids) { - if (ids.empty()) - return; - for (auto id : ids) { - auto it = promise_image_cache_.find(id); - if (it == promise_image_cache_.end()) - continue; - it->second->image = nullptr; - promise_image_cache_.erase(it); - } -} - -void SkiaOutputSurfaceImplNonDDL::SkiaSwapBuffers(OutputSurfaceFrame frame) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - gfx::SwapTimings swap_timings; - swap_timings.swap_start = base::TimeTicks::Now(); - gl_surface_->SwapBuffers( - base::BindOnce(&SkiaOutputSurfaceImplNonDDL::BufferPresented, - weak_ptr_factory_.GetWeakPtr())); - swap_timings.swap_end = base::TimeTicks::Now(); - if (need_swapbuffers_ack_) - client_->DidReceiveSwapBuffersAck(swap_timings); -} - -SkCanvas* SkiaOutputSurfaceImplNonDDL::BeginPaintRenderPass( - const RenderPassId& id, - const gfx::Size& surface_size, - ResourceFormat format, - bool mipmap, - sk_sp<SkColorSpace> color_space) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - // Make sure there is no unsubmitted PaintFrame or PaintRenderPass. - DCHECK_EQ(current_render_pass_id_, 0u); - DCHECK(!scoped_gpu_task_); - scoped_gpu_task_.emplace(sync_point_order_data_.get()); - current_render_pass_id_ = id; - auto& sk_surface = offscreen_sk_surfaces_[id]; - - if (!sk_surface) { - SkColorType color_type = - ResourceFormatToClosestSkColorType(true /* gpu_compositing */, format); - SkImageInfo image_info = SkImageInfo::Make( - surface_size.width(), surface_size.height(), color_type, - kPremul_SkAlphaType, std::move(color_space)); - sk_surface = - SkSurface::MakeRenderTarget(gr_context(), SkBudgeted::kNo, image_info); - } - - sk_current_surface_ = sk_surface.get(); - return sk_current_surface_->getCanvas(); -} - -gpu::SyncToken SkiaOutputSurfaceImplNonDDL::SubmitPaint( - base::OnceClosure on_finished) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - // To make sure sync_token is valid, we need make sure we are processing a gpu - // task. - DCHECK(scoped_gpu_task_); - gpu::SyncToken sync_token( - gpu::CommandBufferNamespace::VIZ_SKIA_OUTPUT_SURFACE_NON_DDL, - sync_point_client_state_->command_buffer_id(), ++sync_fence_release_); - sync_token.SetVerifyFlush(); - - if (!sk_current_surface_) { -#if BUILDFLAG(ENABLE_VULKAN) - DCHECK(shared_context_state_->GrContextIsVulkan()); - DCHECK(draw_context_); - draw_context_->flush(); - draw_context_ = nullptr; - // Enqueue vk_semaphores which will be signalled when SecondaryCB is - // executed and finished. - std::vector<VkSemaphore> vk_semaphores; - vk_semaphores.reserve(pending_semaphores_.size()); - for (const auto& semaphore : pending_semaphores_) { - DCHECK(semaphore.vkSemaphore() != VK_NULL_HANDLE); - vk_semaphores.push_back(semaphore.vkSemaphore()); - } - pending_semaphores_.clear(); - auto* vk_context_provider = shared_context_state_->vk_context_provider(); - vk_context_provider->EnqueueSecondaryCBSemaphores(std::move(vk_semaphores)); - // Enqueue FinishPaint which will be executed when the SecondaryCB is - // submitted and all enqueued semaphores have been submitted for signalling. - // WebView will not destroy OutputSurface when DrawVk is pending - // (PostDrawVK is not called), so it is safe to use base::Unretaied() here. - vk_context_provider->EnqueueSecondaryCBPostSubmitTask( - base::BindOnce(&SkiaOutputSurfaceImplNonDDL::FinishPaint, - base::Unretained(this), sync_fence_release_)); - return sync_token; -#else - NOTREACHED(); - return gpu::SyncToken(); -#endif - } - - auto access = current_render_pass_id_ == 0 - ? SkSurface::BackendSurfaceAccess::kPresent - : SkSurface::BackendSurfaceAccess::kNoAccess; - GrFlushInfo flush_info = { - .fFlags = kNone_GrFlushFlags, - .fNumSemaphores = pending_semaphores_.size(), - .fSignalSemaphores = pending_semaphores_.data(), - }; - - gpu::AddVulkanCleanupTaskForSkiaFlush( - shared_context_state_->vk_context_provider(), &flush_info); - if (on_finished) - gpu::AddCleanupTaskForSkiaFlush(std::move(on_finished), &flush_info); - - auto result = sk_current_surface_->flush(access, flush_info); - DCHECK_EQ(result, GrSemaphoresSubmitted::kYes); - pending_semaphores_.clear(); - sk_current_surface_ = nullptr; - - FinishPaint(sync_fence_release_); - return sync_token; -} - -sk_sp<SkImage> SkiaOutputSurfaceImplNonDDL::MakePromiseSkImageFromRenderPass( - const RenderPassId& id, - const gfx::Size& size, - ResourceFormat format, - bool mipmap, - sk_sp<SkColorSpace> color_space) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - auto it = offscreen_sk_surfaces_.find(id); - DCHECK(it != offscreen_sk_surfaces_.end()); - return it->second->makeImageSnapshot(); -} - -void SkiaOutputSurfaceImplNonDDL::RemoveRenderPassResource( - std::vector<RenderPassId> ids) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!ids.empty()); - - for (const auto& id : ids) { - auto it = offscreen_sk_surfaces_.find(id); - DCHECK(it != offscreen_sk_surfaces_.end()); - offscreen_sk_surfaces_.erase(it); - } -} - -void SkiaOutputSurfaceImplNonDDL::CopyOutput( - RenderPassId id, - const copy_output::RenderPassGeometry& geometry, - const gfx::ColorSpace& color_space, - std::unique_ptr<CopyOutputRequest> request) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - NOTIMPLEMENTED(); -} - -bool SkiaOutputSurfaceImplNonDDL::WaitSyncToken( - const gpu::SyncToken& sync_token) { - base::WaitableEvent event; - if (!sync_point_client_state_->Wait( - sync_token, base::BindOnce(&base::WaitableEvent::Signal, - base::Unretained(&event)))) { - return false; - } - event.Wait(); - return true; -} - -std::unique_ptr<ImageContext> -SkiaOutputSurfaceImplNonDDL::MakeSkImageFromSharedImage( - const ResourceMetadata& metadata) { - auto image_context = std::make_unique<ImageContext>(metadata); - WaitSyncToken(image_context->sync_token); - image_context->representation = sir_factory_->ProduceSkia( - image_context->mailbox, shared_context_state_.get()); - if (!image_context->representation) { - DLOG(ERROR) << "Failed to make the SkImage - SharedImage mailbox not found " - "in SharedImageManager."; - return nullptr; - } - - if (!(image_context->representation->usage() & - gpu::SHARED_IMAGE_USAGE_DISPLAY)) { - DLOG(ERROR) << "Failed to make the SkImage - SharedImage was not created " - "with display usage."; - return nullptr; - } - - std::vector<GrBackendSemaphore> begin_semaphores; - image_context->promise_image_texture = - image_context->representation->BeginReadAccess(&begin_semaphores, - &pending_semaphores_); - if (!image_context->promise_image_texture) { - DLOG(ERROR) - << "Failed to make the SkImage - SharedImage begin access failed."; - return nullptr; - } - image_context->representation_is_being_accessed = true; - WaitSemaphores(std::move(begin_semaphores)); - - SkColorType color_type = ResourceFormatToClosestSkColorType( - true /* gpu_compositing */, metadata.resource_format); - - image_context->image = SkImage::MakeFromTexture( - gr_context(), image_context->promise_image_texture->backendTexture(), - kTopLeft_GrSurfaceOrigin, color_type, image_context->alpha_type, - image_context->color_space); - - if (!image_context->image) { - DLOG(ERROR) << "Failed to create the SkImage"; - return nullptr; - } - return image_context; -} - -bool SkiaOutputSurfaceImplNonDDL::GetGrBackendTexture( - const ResourceMetadata& metadata, - GrBackendTexture* backend_texture) { - DCHECK(!metadata.mailbox_holder.mailbox.IsZero()); - if (WaitSyncToken(metadata.mailbox_holder.sync_token)) { - if (shared_context_state_->GrContextIsGL()) { - DCHECK(mailbox_manager_->UsesSync()); - mailbox_manager_->PullTextureUpdates(metadata.mailbox_holder.sync_token); - } - } - - auto* texture_base = - mailbox_manager_->ConsumeTexture(metadata.mailbox_holder.mailbox); - if (!texture_base) { - DLOG(ERROR) << "Failed to make the SkImage"; - return false; - } - - auto* gl_version_info = - shared_context_state_->real_context()->GetVersionInfo(); - return gpu::GetGrBackendTexture(gl_version_info, texture_base->target(), - metadata.size, texture_base->service_id(), - metadata.resource_format, backend_texture); -} - -void SkiaOutputSurfaceImplNonDDL::FinishPaint(uint64_t sync_fence_release) { - DCHECK(scoped_gpu_task_); - for (auto* image_context : images_in_current_paint_) { - if (!image_context->representation_is_being_accessed) - continue; - DCHECK(image_context->representation); - image_context->representation->EndReadAccess(); - image_context->representation_is_being_accessed = false; - } - images_in_current_paint_.clear(); - - if (shared_context_state_->GrContextIsGL()) { - DCHECK(mailbox_manager_->UsesSync()); - gpu::SyncToken sync_token( - gpu::CommandBufferNamespace::VIZ_SKIA_OUTPUT_SURFACE_NON_DDL, - sync_point_client_state_->command_buffer_id(), sync_fence_release); - sync_token.SetVerifyFlush(); - mailbox_manager_->PushTextureUpdates(sync_token); - } - sync_point_client_state_->ReleaseFenceSync(sync_fence_release); - scoped_gpu_task_.reset(); - current_render_pass_id_ = 0; -} - -void SkiaOutputSurfaceImplNonDDL::BufferPresented( - const gfx::PresentationFeedback& feedback) { - client_->DidReceivePresentationFeedback(feedback); -} - -void SkiaOutputSurfaceImplNonDDL::WaitSemaphores( - std::vector<GrBackendSemaphore> semaphores) { - if (semaphores.empty()) - return; -#if BUILDFLAG(ENABLE_VULKAN) - DCHECK(sk_current_surface_ || draw_context_); - auto result = - sk_current_surface_ - ? sk_current_surface_->wait(semaphores.size(), semaphores.data()) - : draw_context_->wait(semaphores.size(), semaphores.data()); -#else - DCHECK(sk_current_surface_); - auto result = sk_current_surface_->wait(semaphores.size(), semaphores.data()); -#endif - - DCHECK(result); -} - -SkiaOutputSurfaceImplNonDDL::ScopedGpuTask::ScopedGpuTask( - gpu::SyncPointOrderData* sync_point_order_data) - : sync_point_order_data_(sync_point_order_data), - order_num_(sync_point_order_data_->GenerateUnprocessedOrderNumber()) { - sync_point_order_data_->BeginProcessingOrderNumber(order_num_); -} - -SkiaOutputSurfaceImplNonDDL::ScopedGpuTask::~ScopedGpuTask() { - sync_point_order_data_->FinishProcessingOrderNumber(order_num_); -} - -} // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.h b/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.h deleted file mode 100644 index d2635f7..0000000 --- a/components/viz/service/display_embedder/skia_output_surface_impl_non_ddl.h +++ /dev/null
@@ -1,168 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_NON_DDL_H_ -#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_NON_DDL_H_ - -#include <memory> -#include <vector> - -#include "base/containers/flat_map.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/optional.h" -#include "components/viz/service/display_embedder/skia_output_surface_base.h" -#include "components/viz/service/viz_service_export.h" -#include "gpu/command_buffer/common/sync_token.h" -#include "gpu/command_buffer/service/shared_context_state.h" -#include "gpu/vulkan/buildflags.h" - -#if BUILDFLAG(ENABLE_VULKAN) -class GrVkSecondaryCBDrawContext; -#endif - -namespace gfx { -struct PresentationFeedback; -} - -namespace gl { -class GLSurface; -} - -namespace gpu { -class MailboxManager; -class SharedImageManager; -class SharedImageRepresentationFactory; -class SyncPointClientState; -class SyncPointManager; -class SyncPointOrderData; -} // namespace gpu - -namespace viz { - -// A SkiaOutputSurface implementation for running SkiaRenderer on GpuThread. -// Comparing to SkiaOutputSurfaceImpl, it will issue skia draw operations -// against OS graphics API (GL, Vulkan, etc) instead of recording deferred -// display list first. -class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImplNonDDL - : public SkiaOutputSurfaceBase { - public: - SkiaOutputSurfaceImplNonDDL( - scoped_refptr<gl::GLSurface> gl_surface, - scoped_refptr<gpu::SharedContextState> shared_context_state, - gpu::MailboxManager* mailbox_manager, - gpu::SharedImageManager* shared_image_manager, - gpu::SyncPointManager* sync_point_manager, - bool need_swapbuffers_ack); - ~SkiaOutputSurfaceImplNonDDL() override; - - // OutputSurface implementation: - void EnsureBackbuffer() override; - void DiscardBackbuffer() override; - void Reshape(const gfx::Size& size, - float device_scale_factor, - const gfx::ColorSpace& color_space, - bool has_alpha, - bool use_stencil) override; - - // SkiaOutputSurface implementation: - SkCanvas* BeginPaintCurrentFrame() override; - sk_sp<SkImage> MakePromiseSkImageFromYUV( - const std::vector<ResourceMetadata>& metadatas, - SkYUVColorSpace yuv_color_space, - sk_sp<SkColorSpace> dst_color_space, - bool has_alpha) override; - void SkiaSwapBuffers(OutputSurfaceFrame frame) override; - SkCanvas* BeginPaintRenderPass(const RenderPassId& id, - const gfx::Size& surface_size, - ResourceFormat format, - bool mipmap, - sk_sp<SkColorSpace> color_space) override; - gpu::SyncToken SubmitPaint(base::OnceClosure on_finished) override; - sk_sp<SkImage> MakePromiseSkImage(const ResourceMetadata& metadata) override; - sk_sp<SkImage> MakePromiseSkImageFromRenderPass( - const RenderPassId& id, - const gfx::Size& size, - ResourceFormat format, - bool mipmap, - sk_sp<SkColorSpace> color_space) override; - void RemoveRenderPassResource(std::vector<RenderPassId> ids) override; - void CopyOutput(RenderPassId id, - const copy_output::RenderPassGeometry& geometry, - const gfx::ColorSpace& color_space, - std::unique_ptr<CopyOutputRequest> request) override; - - // ExternalUseClient implementation: - void ReleaseCachedResources(const std::vector<ResourceId>& ids) override; - - private: - class ScopedGpuTask { - public: - explicit ScopedGpuTask(gpu::SyncPointOrderData* sync_point_order_data); - ~ScopedGpuTask(); - - private: - gpu::SyncPointOrderData* const sync_point_order_data_; - const uint32_t order_num_; - - DISALLOW_COPY_AND_ASSIGN(ScopedGpuTask); - }; - - GrContext* gr_context() { return shared_context_state_->gr_context(); } - - bool WaitSyncToken(const gpu::SyncToken& sync_token); - std::unique_ptr<ImageContext> MakeSkImageFromSharedImage( - const ResourceMetadata& metadata); - bool GetGrBackendTexture(const ResourceMetadata& metadata, - GrBackendTexture* backend_texture); - void FinishPaint(uint64_t sync_fence_release); - void BufferPresented(const gfx::PresentationFeedback& feedback); - void WaitSemaphores(std::vector<GrBackendSemaphore> semaphores); - - uint64_t sync_fence_release_ = 0; - - // Stuffs for running with |task_executor_| instead of |gpu_service_|. - scoped_refptr<gl::GLSurface> gl_surface_; - scoped_refptr<gpu::SharedContextState> shared_context_state_; - gpu::MailboxManager* const mailbox_manager_; - std::unique_ptr<gpu::SharedImageRepresentationFactory> sir_factory_; - scoped_refptr<gpu::SyncPointOrderData> sync_point_order_data_; - scoped_refptr<gpu::SyncPointClientState> sync_point_client_state_; - const bool need_swapbuffers_ack_; - base::Optional<ScopedGpuTask> scoped_gpu_task_; - - unsigned int backing_framebuffer_object_ = 0; - gfx::Size reshape_surface_size_; - float reshape_device_scale_factor_ = 0.f; - gfx::ColorSpace reshape_color_space_; - bool reshape_has_alpha_ = false; - bool reshape_use_stencil_ = false; - - // The current render pass id set by BeginPaintRenderPass. - RenderPassId current_render_pass_id_ = 0; - - // The SkSurface for the framebuffer. - sk_sp<SkSurface> sk_surface_; - -#if BUILDFLAG(ENABLE_VULKAN) - // The |draw_context_| for the current frame. - GrVkSecondaryCBDrawContext* draw_context_ = nullptr; -#endif - - SkSurface* sk_current_surface_ = nullptr; - - // Offscreen SkSurfaces for render passes. - base::flat_map<RenderPassId, sk_sp<SkSurface>> offscreen_sk_surfaces_; - - // Semaphores which need to be signalled for the current paint. - std::vector<GrBackendSemaphore> pending_semaphores_; - - base::WeakPtrFactory<SkiaOutputSurfaceImplNonDDL> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(SkiaOutputSurfaceImplNonDDL); -}; - -} // namespace viz - -#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_NON_DDL_H_
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index 5b0adbca..9801435 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -491,8 +491,8 @@ CreateGpuMemoryBufferCallback callback) { DCHECK(io_runner_->BelongsToCurrentThread()); // This needs to happen in the IO thread. - std::move(callback).Run(gpu_memory_buffer_factory_->CreateGpuMemoryBuffer( - id, size, format, usage, client_id, surface_handle)); + gpu_memory_buffer_factory_->CreateGpuMemoryBufferAsync( + id, size, format, usage, client_id, surface_handle, std::move(callback)); } void GpuServiceImpl::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
diff --git a/content/browser/accessibility/accessibility_auralinux_browsertest.cc b/content/browser/accessibility/accessibility_auralinux_browsertest.cc index ea5df567..ebaf887 100644 --- a/content/browser/accessibility/accessibility_auralinux_browsertest.cc +++ b/content/browser/accessibility/accessibility_auralinux_browsertest.cc
@@ -17,16 +17,8 @@ #include "content/test/content_browser_test_utils_internal.h" #include "ui/accessibility/platform/ax_platform_node_auralinux.h" -// TODO(crbug.com/961029): Fix memory leaks in tests and re-enable on LSAN. -#if defined(LEAK_SANITIZER) -#define MAYBE_TestAtkTextListItem DISABLED_TestAtkTextListItem -#else -#define MAYBE_TestAtkTextListItem TestAtkTextListItem -#endif - -// TODO(crbug.com/961029): Fix memory leaks in tests and re-enable on LSAN. // TODO(crbug.com/981913): This flakes on linux tsan. -#if defined(LEAK_SANITIZER) || defined(THREAD_SANITIZER) +#if defined(THREAD_SANITIZER) #define MAYBE_TestSetCaretSetsSequentialFocusNavigationStartingPoint \ DISABLED_TestSetCaretSetsSequentialFocusNavigationStartingPoint #else @@ -741,8 +733,7 @@ g_object_unref(atk_text); } -IN_PROC_BROWSER_TEST_F(AccessibilityAuraLinuxBrowserTest, - MAYBE_TestAtkTextListItem) { +IN_PROC_BROWSER_TEST_F(AccessibilityAuraLinuxBrowserTest, TestAtkTextListItem) { LoadInitialAccessibilityTreeFromHtml( R"HTML(<!DOCTYPE html> <html> @@ -781,6 +772,7 @@ g_free(text); g_object_unref(list_item_1); + g_object_unref(list_item_2); } IN_PROC_BROWSER_TEST_F(AccessibilityAuraLinuxBrowserTest, @@ -928,6 +920,7 @@ g_object_unref(child_2); g_object_unref(child_3); g_object_unref(child_7); + g_object_unref(parent_div); } IN_PROC_BROWSER_TEST_F(AccessibilityAuraLinuxBrowserTest,
diff --git a/content/browser/accessibility/accessibility_tree_formatter_base.cc b/content/browser/accessibility/accessibility_tree_formatter_base.cc index 2a231537..02f44d16 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_base.cc +++ b/content/browser/accessibility/accessibility_tree_formatter_base.cc
@@ -201,18 +201,36 @@ } base::string16 AccessibilityTreeFormatterBase::FormatCoordinates( - const char* name, - const char* x_name, - const char* y_name, - const base::DictionaryValue& value) { + const base::DictionaryValue& value, + const std::string& name, + const std::string& x_name, + const std::string& y_name) { int x, y; value.GetInteger(x_name, &x); value.GetInteger(y_name, &y); - std::string xy_str(base::StringPrintf("%s=(%d, %d)", name, x, y)); + std::string xy_str(base::StringPrintf("%s=(%d, %d)", name.c_str(), x, y)); return base::UTF8ToUTF16(xy_str); } +base::string16 AccessibilityTreeFormatterBase::FormatRectangle( + const base::DictionaryValue& value, + const std::string& name, + const std::string& left_name, + const std::string& top_name, + const std::string& width_name, + const std::string& height_name) { + int left, top, width, height; + value.GetInteger(left_name, &left); + value.GetInteger(top_name, &top); + value.GetInteger(width_name, &width); + value.GetInteger(height_name, &height); + std::string rect_str(base::StringPrintf("%s=(%d, %d, %d, %d)", name.c_str(), + left, top, width, height)); + + return base::UTF8ToUTF16(rect_str); +} + bool AccessibilityTreeFormatterBase::WriteAttribute(bool include_by_default, const std::string& attr, base::string16* line) {
diff --git a/content/browser/accessibility/accessibility_tree_formatter_base.h b/content/browser/accessibility/accessibility_tree_formatter_base.h index d2430c04..584c15e 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_base.h +++ b/content/browser/accessibility/accessibility_tree_formatter_base.h
@@ -73,10 +73,17 @@ // Utility functions to be used by each platform. // - base::string16 FormatCoordinates(const char* name, - const char* x_name, - const char* y_name, - const base::DictionaryValue& value); + base::string16 FormatCoordinates(const base::DictionaryValue& value, + const std::string& name, + const std::string& x_name, + const std::string& y_name); + + base::string16 FormatRectangle(const base::DictionaryValue& value, + const std::string& name, + const std::string& left_name, + const std::string& top_name, + const std::string& width_name, + const std::string& height_name); // Writes the given attribute string out to |line| if it matches the property // filters.
diff --git a/content/browser/accessibility/accessibility_tree_formatter_blink.cc b/content/browser/accessibility/accessibility_tree_formatter_blink.cc index 2ba2aa0..ec7637d 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_blink.cc +++ b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
@@ -403,9 +403,9 @@ WriteAttribute(false, STATE_FOCUSED, &line); WriteAttribute( - false, FormatCoordinates("location", "boundsX", "boundsY", dict), &line); + false, FormatCoordinates(dict, "location", "boundsX", "boundsY"), &line); WriteAttribute(false, - FormatCoordinates("size", "boundsWidth", "boundsHeight", dict), + FormatCoordinates(dict, "size", "boundsWidth", "boundsHeight"), &line); bool ignored = false; @@ -413,20 +413,21 @@ if (!ignored) { WriteAttribute( false, - FormatCoordinates("pageLocation", "pageBoundsX", "pageBoundsY", dict), + FormatCoordinates(dict, "pageLocation", "pageBoundsX", "pageBoundsY"), &line); WriteAttribute(false, - FormatCoordinates("pageSize", "pageBoundsWidth", - "pageBoundsHeight", dict), + FormatCoordinates(dict, "pageSize", "pageBoundsWidth", + "pageBoundsHeight"), &line); WriteAttribute(false, - FormatCoordinates("unclippedLocation", "unclippedBoundsX", - "unclippedBoundsY", dict), + FormatCoordinates(dict, "unclippedLocation", + "unclippedBoundsX", "unclippedBoundsY"), &line); - WriteAttribute(false, - FormatCoordinates("unclippedSize", "unclippedBoundsWidth", - "unclippedBoundsHeight", dict), - &line); + WriteAttribute( + false, + FormatCoordinates(dict, "unclippedSize", "unclippedBoundsWidth", + "unclippedBoundsHeight"), + &line); } bool transform;
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/content/browser/accessibility/accessibility_tree_formatter_mac.mm index 71b71384..ded69c1c 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_mac.mm +++ b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -349,14 +349,14 @@ const base::DictionaryValue* d_value = NULL; if (dict.GetDictionary(kPositionDictAttr, &d_value)) { WriteAttribute(false, - FormatCoordinates(kPositionDictAttr, kXCoordDictAttr, - kYCoordDictAttr, *d_value), + FormatCoordinates(*d_value, kPositionDictAttr, + kXCoordDictAttr, kYCoordDictAttr), &line); } if (dict.GetDictionary(kSizeDictAttr, &d_value)) { WriteAttribute(false, - FormatCoordinates(kSizeDictAttr, kWidthDictAttr, - kHeightDictAttr, *d_value), + FormatCoordinates(*d_value, kSizeDictAttr, kWidthDictAttr, + kHeightDictAttr), &line); }
diff --git a/content/browser/accessibility/accessibility_tree_formatter_uia_win.cc b/content/browser/accessibility/accessibility_tree_formatter_uia_win.cc index 4d0fc61e..34efb96 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_uia_win.cc +++ b/content/browser/accessibility/accessibility_tree_formatter_uia_win.cc
@@ -348,6 +348,10 @@ uia_->ElementFromHandle(hwnd, &root); CHECK(root.Get()); + // Get the bounds of the root element, to pass into tree building later. + RECT root_bounds = {0}; + root->get_CurrentBoundingRectangle(&root_bounds); + // The root element is provided by AXFragmentRootWin, whose RuntimeId is not // in the same form as elements provided by BrowserAccessibility. // Find the root element's first child, which should be provided by @@ -393,7 +397,8 @@ // Build an accessibility tree starting from that element. std::unique_ptr<base::DictionaryValue> tree = std::make_unique<base::DictionaryValue>(); - RecursiveBuildAccessibilityTree(start_element.Get(), tree.get()); + RecursiveBuildAccessibilityTree(start_element.Get(), root_bounds.left, + root_bounds.top, tree.get()); return tree; } @@ -415,9 +420,13 @@ uia_->ElementFromHandle(hwnd, &root); CHECK(root.Get()); + RECT root_bounds = {0}; + root->get_CurrentBoundingRectangle(&root_bounds); + std::unique_ptr<base::DictionaryValue> tree = std::make_unique<base::DictionaryValue>(); - RecursiveBuildAccessibilityTree(root.Get(), tree.get()); + RecursiveBuildAccessibilityTree(root.Get(), root_bounds.left, root_bounds.top, + tree.get()); return tree; } @@ -431,9 +440,11 @@ void AccessibilityTreeFormatterUia::RecursiveBuildAccessibilityTree( IUIAutomationElement* uncached_node, + int root_x, + int root_y, base::DictionaryValue* dict) { // Process this node. - AddProperties(uncached_node, dict); + AddProperties(uncached_node, root_x, root_y, dict); // Update the cache to get children Microsoft::WRL::ComPtr<IUIAutomationElement> parent; @@ -451,7 +462,8 @@ std::unique_ptr<base::DictionaryValue> child_dict = std::make_unique<base::DictionaryValue>(); if (SUCCEEDED(children->GetElement(i, &child))) { - RecursiveBuildAccessibilityTree(child.Get(), child_dict.get()); + RecursiveBuildAccessibilityTree(child.Get(), root_x, root_y, + child_dict.get()); } else { child_dict->SetString("error", L"[Error retrieving child]"); } @@ -462,6 +474,8 @@ void AccessibilityTreeFormatterUia::AddProperties( IUIAutomationElement* uncached_node, + int root_x, + int root_y, base::DictionaryValue* dict) { // Update the cache for this node's information. Microsoft::WRL::ComPtr<IUIAutomationElement> node; @@ -471,7 +485,7 @@ for (long i : properties_) { base::win::ScopedVariant variant; if (SUCCEEDED(node->GetCachedPropertyValue(i, variant.Receive()))) { - WriteProperty(i, variant, dict); + WriteProperty(i, variant, root_x, root_y, dict); } } // Add control pattern specific properties @@ -772,6 +786,8 @@ void AccessibilityTreeFormatterUia::WriteProperty( long propertyId, const base::win::ScopedVariant& var, + int root_x, + int root_y, base::DictionaryValue* dict) { switch (var.type()) { case VT_EMPTY: @@ -820,17 +836,14 @@ case VT_UNKNOWN: WriteUnknownProperty(propertyId, var.ptr()->punkVal, dict); break; - case VT_DISPATCH: - case VT_ERROR: - case VT_CY: - case VT_DATE: - case VT_VARIANT: - case VT_DECIMAL: - case VT_INT: - case VT_UINT: - case VT_ARRAY: - case VT_BYREF: default: + switch (propertyId) { + case UIA_BoundingRectanglePropertyId: + WriteRectangleProperty(propertyId, var, root_x, root_y, dict); + break; + default: + break; + } break; } } @@ -885,6 +898,27 @@ } } +void AccessibilityTreeFormatterUia::WriteRectangleProperty( + long propertyId, + const VARIANT& value, + int root_x, + int root_y, + base::DictionaryValue* dict) { + CHECK(value.vt == (VT_ARRAY | VT_R8)); + + double* data = nullptr; + SafeArrayAccessData(value.parray, reinterpret_cast<void**>(&data)); + + auto rectangle = std::make_unique<base::DictionaryValue>(); + rectangle->SetInteger("left", data[0] - root_x); + rectangle->SetInteger("top", data[1] - root_y); + rectangle->SetInteger("width", data[2]); + rectangle->SetInteger("height", data[3]); + dict->Set(UiaIdentifierToCondensedString(propertyId), std::move(rectangle)); + + SafeArrayUnaccessData(value.parray); +} + void AccessibilityTreeFormatterUia::WriteElementArray( long propertyId, IUIAutomationElementArray* array, @@ -1084,6 +1118,21 @@ filtered_result->SetDouble(name, double_value); break; } + case base::Value::Type::DICTIONARY: { + const base::DictionaryValue* dict_value = nullptr; + value->GetAsDictionary(&dict_value); + bool did_pass_filters = false; + if (name == "BoundingRectangle") { + did_pass_filters = + WriteAttribute(false, + FormatRectangle(*dict_value, "BoundingRectangle", + "left", "top", "width", "height"), + &line); + } + if (filtered_result && did_pass_filters) + filtered_result->SetKey(name, dict_value->Clone()); + break; + } default: NOTREACHED(); break;
diff --git a/content/browser/accessibility/accessibility_tree_formatter_uia_win.h b/content/browser/accessibility/accessibility_tree_formatter_uia_win.h index e6abfb7..f6016e42 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_uia_win.h +++ b/content/browser/accessibility/accessibility_tree_formatter_uia_win.h
@@ -48,9 +48,14 @@ static const long patterns_[]; static const long pattern_properties_[]; void RecursiveBuildAccessibilityTree(IUIAutomationElement* node, + int root_x, + int root_y, base::DictionaryValue* dict); void BuildCacheRequests(); - void AddProperties(IUIAutomationElement* node, base::DictionaryValue* dict); + void AddProperties(IUIAutomationElement* node, + int root_x, + int root_y, + base::DictionaryValue* dict); void AddExpandCollapseProperties(IUIAutomationElement* node, base::DictionaryValue* dict); void AddGridProperties(IUIAutomationElement* node, @@ -75,12 +80,19 @@ base::DictionaryValue* dict); void WriteProperty(long propertyId, const base::win::ScopedVariant& var, + int root_x, + int root_y, base::DictionaryValue* dict); // UIA enums have type I4, print formatted string for these when possible void WriteI4Property(long propertyId, long lval, base::DictionaryValue* dict); void WriteUnknownProperty(long propertyId, IUnknown* unk, base::DictionaryValue* dict); + void WriteRectangleProperty(long propertyId, + const VARIANT& value, + int root_x, + int root_y, + base::DictionaryValue* dict); void WriteElementArray(long propertyId, IUIAutomationElementArray* array, base::DictionaryValue* dict);
diff --git a/content/browser/accessibility/accessibility_tree_formatter_win.cc b/content/browser/accessibility/accessibility_tree_formatter_win.cc index 41e4ba70..c8f91b6 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_win.cc +++ b/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -995,11 +995,11 @@ bool did_pass_filters = false; if (strcmp(attribute_name, "size") == 0) { did_pass_filters = WriteAttribute( - false, FormatCoordinates("size", "width", "height", *dict_value), + false, FormatCoordinates(*dict_value, "size", "width", "height"), &line); } else if (strcmp(attribute_name, "location") == 0) { did_pass_filters = WriteAttribute( - false, FormatCoordinates("location", "x", "y", *dict_value), + false, FormatCoordinates(*dict_value, "location", "x", "y"), &line); } if (filtered_dict_result && did_pass_filters)
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc index 36e2898..9785cbf8 100644 --- a/content/browser/child_process_security_policy_impl.cc +++ b/content/browser/child_process_security_policy_impl.cc
@@ -1152,10 +1152,8 @@ // API either. // TODO(lukasza): Audit whether CanAccessDataForOrigin can be used directly // here. - if (!CanCommitURL(child_id, filesystem_url.origin().GetURL())) { - UMA_HISTOGRAM_BOOLEAN("FileSystem.OriginFailedCanCommitURL", true); + if (!CanCommitURL(child_id, filesystem_url.origin().GetURL())) return false; - } int found_permissions = 0; {
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc index f695189..b4357afa 100644 --- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc +++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
@@ -121,6 +121,12 @@ } } +gfx::Rect +GpuSurfacelessBrowserCompositorOutputSurface::GetCurrentFramebufferDamage() + const { + return buffer_queue_->CurrentBufferDamage(); +} + GLenum GpuSurfacelessBrowserCompositorOutputSurface:: GetFramebufferCopyTextureFormat() { return buffer_queue_->internal_format(); @@ -180,12 +186,6 @@ return gpu_fence_id_; } -void GpuSurfacelessBrowserCompositorOutputSurface::SetDrawRectangle( - const gfx::Rect& damage) { - GpuBrowserCompositorOutputSurface::SetDrawRectangle(damage); - buffer_queue_->CopyDamageForCurrentSurface(damage); -} - gpu::SurfaceHandle GpuSurfacelessBrowserCompositorOutputSurface::GetSurfaceHandle() const { return surface_handle_;
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h index 49c1e62..7caf285 100644 --- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h +++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
@@ -36,6 +36,7 @@ // viz::OutputSurface implementation. void SwapBuffers(viz::OutputSurfaceFrame frame) override; void BindFramebuffer() override; + gfx::Rect GetCurrentFramebufferDamage() const override; uint32_t GetFramebufferCopyTextureFormat() override; void Reshape(const gfx::Size& size, float device_scale_factor, @@ -46,7 +47,6 @@ unsigned GetOverlayTextureId() const override; gfx::BufferFormat GetOverlayBufferFormat() const override; unsigned UpdateGpuFence() override; - void SetDrawRectangle(const gfx::Rect& damage) override; gpu::SurfaceHandle GetSurfaceHandle() const override; // BrowserCompositorOutputSurface implementation.
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc index 6aa1956..84e85870 100644 --- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc +++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -8802,9 +8802,10 @@ EXPECT_TRUE(controller.GetEntryAtIndex(3)->should_skip_on_back_forward_ui()); EXPECT_FALSE(controller.GetEntryAtIndex(4)->should_skip_on_back_forward_ui()); - // Simulate a user gesture. - root->UpdateUserActivationState( - blink::UserActivationUpdateType::kNotifyActivation); + // Simulate a user gesture. ExecuteScript internally also sends a user + // gesture. + script = "a=5"; + EXPECT_TRUE(content::ExecuteScript(shell()->web_contents(), script)); // We now have (After user gesture) // [skippable_url(skip), redirected_url, push_state_url1*, push_state_url2,
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc index aef415fe..54ff6d5 100644 --- a/content/browser/frame_host/navigation_handle_impl.cc +++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -405,23 +405,6 @@ new ServiceWorkerNavigationHandle(service_worker_context)); } -void NavigationHandleImpl::RunCompleteCallback( - NavigationThrottle::ThrottleCheckResult result) { - DCHECK(result.action() != NavigationThrottle::DEFER); - - ThrottleChecksFinishedCallback callback = std::move(complete_callback_); - complete_callback_.Reset(); - - if (!complete_callback_for_testing_.is_null()) - std::move(complete_callback_for_testing_).Run(result); - - if (!callback.is_null()) - std::move(callback).Run(result); - - // No code after running the callback, as it might have resulted in our - // destruction. -} - void NavigationHandleImpl::RenderProcessBlockedStateChanged(bool blocked) { if (blocked) StopCommitTimeout();
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h index bd8de94..de8a792 100644 --- a/content/browser/frame_host/navigation_handle_impl.h +++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -184,11 +184,6 @@ response_headers_for_testing_ = response_headers; } - void set_complete_callback_for_testing( - ThrottleChecksFinishedCallback callback) { - complete_callback_for_testing_ = std::move(callback); - } - CSPDisposition should_check_main_world_csp() const { return navigation_request_->common_params() .initiator_csp_info.should_check_main_world_csp; @@ -233,14 +228,6 @@ int pending_nav_entry_id, net::HttpRequestHeaders request_headers); - // Helper function to run and reset the |complete_callback_|. This marks the - // end of a round of NavigationThrottleChecks. - void RunCompleteCallback(NavigationThrottle::ThrottleCheckResult result); - - void SetCompleteCallback(ThrottleChecksFinishedCallback callback) { - complete_callback_ = std::move(callback); - } - NavigationRequest::NavigationHandleState state() const { return navigation_request_->handle_state(); } @@ -280,16 +267,6 @@ // The unique id of the corresponding NavigationEntry. int pending_nav_entry_id_; - // This callback will be run when all throttle checks have been performed. Be - // careful about relying on it as the member may be removed as part of the - // PlzNavigate refactoring. - ThrottleChecksFinishedCallback complete_callback_; - - // This test-only callback will be run when all throttle checks have been - // performed. - // TODO(clamy): Revisit the unit test architecture when PlzNavigate ships. - ThrottleChecksFinishedCallback complete_callback_for_testing_; - // Manages the lifetime of a pre-created ServiceWorkerProviderHost until a // corresponding provider is created in the renderer. std::unique_ptr<ServiceWorkerNavigationHandle> service_worker_handle_;
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index 3667d34..ccbd052 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -2500,9 +2500,9 @@ else handle_state_ = CANCELING; - // TODO(zetamoo): Remove CompleteCallback from NavigationHandleImpl, and call - // the NavigationRequest methods directly. - navigation_handle_->RunCompleteCallback(result); + // TODO(zetamoo): Remove CompleteCallback, and call NavigationRequest methods + // directly. + RunCompleteCallback(result); } void NavigationRequest::OnWillRedirectRequestProcessed( @@ -2518,7 +2518,7 @@ } else { handle_state_ = NavigationRequest::CANCELING; } - navigation_handle_->RunCompleteCallback(result); + RunCompleteCallback(result); } void NavigationRequest::OnWillFailRequestProcessed( @@ -2532,7 +2532,7 @@ } else { handle_state_ = CANCELING; } - navigation_handle_->RunCompleteCallback(result); + RunCompleteCallback(result); } void NavigationRequest::OnWillProcessResponseProcessed( @@ -2550,7 +2550,7 @@ } else { handle_state_ = NavigationRequest::CANCELING; } - navigation_handle_->RunCompleteCallback(result); + RunCompleteCallback(result); } NavigatorDelegate* NavigationRequest::GetDelegate() const { @@ -2613,7 +2613,7 @@ TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationRequest", this, "CancelDeferredNavigation"); handle_state_ = NavigationRequest::CANCELING; - navigation_handle_->RunCompleteCallback(result); + RunCompleteCallback(result); } void NavigationRequest::WillStartRequest( @@ -2623,16 +2623,16 @@ // WillStartRequest should only be called once. if (handle_state_ != INITIAL) { handle_state_ = CANCELING; - navigation_handle_->RunCompleteCallback(NavigationThrottle::CANCEL); + RunCompleteCallback(NavigationThrottle::CANCEL); return; } handle_state_ = PROCESSING_WILL_START_REQUEST; - navigation_handle_->SetCompleteCallback(std::move(callback)); + complete_callback_ = std::move(callback); if (IsSelfReferentialURL()) { handle_state_ = CANCELING; - navigation_handle_->RunCompleteCallback(NavigationThrottle::CANCEL); + RunCompleteCallback(NavigationThrottle::CANCEL); return; } @@ -2664,7 +2664,7 @@ if (IsSelfReferentialURL()) { handle_state_ = CANCELING; - navigation_handle_->RunCompleteCallback(NavigationThrottle::CANCEL); + RunCompleteCallback(NavigationThrottle::CANCEL); return; } @@ -2680,7 +2680,7 @@ TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationRequest", this, "WillFailRequest"); - navigation_handle_->SetCompleteCallback(std::move(callback)); + complete_callback_ = std::move(callback); handle_state_ = PROCESSING_WILL_FAIL_REQUEST; // Notify each throttle of the request. @@ -2696,7 +2696,7 @@ "WillProcessResponse"); handle_state_ = PROCESSING_WILL_PROCESS_RESPONSE; - navigation_handle_->SetCompleteCallback(std::move(callback)); + complete_callback_ = std::move(callback); // Notify each throttle of the response. throttle_runner_->ProcessNavigationEvent( @@ -2828,7 +2828,7 @@ navigation_handle_proxy_->DidRedirect(); #endif - navigation_handle_->SetCompleteCallback(std::move(callback)); + complete_callback_ = std::move(callback); } void NavigationRequest::SetNavigationClient( @@ -2897,4 +2897,20 @@ return handle_state_ == NavigationRequest::READY_TO_COMMIT; } +void NavigationRequest::RunCompleteCallback( + NavigationThrottle::ThrottleCheckResult result) { + DCHECK(result.action() != NavigationThrottle::DEFER); + + ThrottleChecksFinishedCallback callback = std::move(complete_callback_); + + if (!complete_callback_for_testing_.is_null()) + std::move(complete_callback_for_testing_).Run(result); + + if (!callback.is_null()) + std::move(callback).Run(result); + + // No code after running the callback, as it might have resulted in our + // destruction. +} + } // namespace content
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h index 090e589..e1a89aa 100644 --- a/content/browser/frame_host/navigation_request.h +++ b/content/browser/frame_host/navigation_request.h
@@ -450,6 +450,11 @@ return is_same_process_; } + void set_complete_callback_for_testing( + ThrottleChecksFinishedCallback callback) { + complete_callback_for_testing_ = std::move(callback); + } + private: // TODO(clamy): Transform NavigationHandleImplTest into NavigationRequestTest // once NavigationHandleImpl has become a wrapper around NavigationRequest. @@ -726,6 +731,11 @@ // navigation or an error page. bool IsWaitingToCommit(); + // Helper function to run and reset the |complete_callback_|. This marks the + // end of a round of NavigationThrottleChecks. + // TODO(zetamoo): This can be removed once the navigation states are merged. + void RunCompleteCallback(NavigationThrottle::ThrottleCheckResult result); + FrameTreeNode* frame_tree_node_; // Invariant: At least one of |loader_| or |render_frame_host_| is null. @@ -921,6 +931,15 @@ // Set in ReadyToCommitNavigation. bool is_same_process_ = true; + // This callback will be run when all throttle checks have been performed. + // TODO(zetamoo): This can be removed once the navigation states are merged. + ThrottleChecksFinishedCallback complete_callback_; + + // This test-only callback will be run when all throttle checks have been + // performed. + // TODO(clamy): Revisit the unit test architecture. + ThrottleChecksFinishedCallback complete_callback_for_testing_; + base::WeakPtrFactory<NavigationRequest> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(NavigationRequest);
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc index 70f10609..7e2774d 100644 --- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc +++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -1097,6 +1097,7 @@ if (navigation_handle->GetURL().path() != "/title2.html") return; static_cast<NavigationHandleImpl*>(navigation_handle) + ->navigation_request() ->set_complete_callback_for_testing( base::Bind(&NavigationHandleGrabber::SendingNavigationCommitted, base::Unretained(this), navigation_handle));
diff --git a/content/browser/frame_host/sec_fetch_browsertest.cc b/content/browser/frame_host/sec_fetch_browsertest.cc index bc038189..e5a3ba7 100644 --- a/content/browser/frame_host/sec_fetch_browsertest.cc +++ b/content/browser/frame_host/sec_fetch_browsertest.cc
@@ -12,6 +12,7 @@ #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" +#include "content/public/test/test_navigation_observer.h" #include "content/shell/browser/shell.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -97,4 +98,34 @@ } } +// Verify that cross-port navigations are treated as same-site by +// Sec-Fetch-Site. +IN_PROC_BROWSER_TEST_F(SecFetchBrowserTest, CrossPortNavigation) { + net::EmbeddedTestServer server2(net::EmbeddedTestServer::TYPE_HTTPS); + server2.AddDefaultHandlers(GetTestDataFilePath()); + server2.SetSSLConfig(net::EmbeddedTestServer::CERT_OK); + ASSERT_TRUE(server2.Start()); + + GURL initial_url = server2.GetURL("/title1.html"); + GURL final_url = GetSecFetchUrl(); + EXPECT_EQ(initial_url.scheme(), final_url.scheme()); + EXPECT_EQ(initial_url.host(), final_url.host()); + EXPECT_NE(initial_url.port(), final_url.port()); + + // Navigate to (paraphrasing): https://foo.com:port1/... + ASSERT_TRUE(NavigateToURL(shell(), initial_url)); + + // Navigate to (paraphrasing): https://foo.com:port2/... when the navigation + // is initiated from (paraphrasing): https://foo.com:port1/... + { + TestNavigationObserver nav_observer(shell()->web_contents()); + ASSERT_TRUE(ExecJs(shell(), JsReplace("location = $1", final_url))); + nav_observer.Wait(); + } + + // Verify that https://foo.com:port1 is treated as same-site wrt + // https://foo.com:port2. + EXPECT_EQ("same-site", GetContent()); +} + } // namespace content
diff --git a/content/browser/idle/OWNERS b/content/browser/idle/OWNERS index 8240ddd..fe122b5 100644 --- a/content/browser/idle/OWNERS +++ b/content/browser/idle/OWNERS
@@ -1,3 +1,5 @@ +ayui@chromium.org jsbell@chromium.org reillyg@chromium.org +# TEAM: fugu-dev@chromium.org
diff --git a/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc b/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc index e278ba17..b40a5ab 100644 --- a/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc +++ b/content/browser/indexed_db/scopes/disjoint_range_lock_manager.cc
@@ -19,13 +19,14 @@ : requested_type(type), locks_holder(std::move(locks_holder)), acquired_callback(std::move(acquired_callback)) {} -DisjointRangeLockManager::LockRequest::LockRequest(LockRequest&&) = default; +DisjointRangeLockManager::LockRequest::LockRequest(LockRequest&&) noexcept = + default; DisjointRangeLockManager::LockRequest::~LockRequest() = default; DisjointRangeLockManager::Lock::Lock() = default; -DisjointRangeLockManager::Lock::Lock(Lock&&) = default; +DisjointRangeLockManager::Lock::Lock(Lock&&) noexcept = default; DisjointRangeLockManager::Lock::~Lock() = default; DisjointRangeLockManager::Lock& DisjointRangeLockManager::Lock::operator=( - DisjointRangeLockManager::Lock&&) = default; + DisjointRangeLockManager::Lock&&) noexcept = default; DisjointRangeLockManager::DisjointRangeLockManager(int level_count) : task_runner_(base::SequencedTaskRunnerHandle::Get()) {
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index 577daea..b2a8edad 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -26,6 +26,7 @@ #include "base/metrics/field_trial.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#include "base/process/process_metrics.h" #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/task/post_task.h" @@ -362,7 +363,7 @@ is_shutdown_(false), enable_resource_scheduler_(enable_resource_scheduler), num_in_flight_requests_(0), - max_num_in_flight_requests_(base::SharedMemory::GetHandleLimit()), + max_num_in_flight_requests_(base::GetHandleLimit()), max_num_in_flight_requests_per_process_(static_cast<int>( max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)), max_outstanding_requests_cost_per_process_(
diff --git a/content/browser/media/android/OWNERS b/content/browser/media/android/OWNERS deleted file mode 100644 index 5abf5a1..0000000 --- a/content/browser/media/android/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -qinmin@chromium.org
diff --git a/content/browser/native_file_system/file_system_chooser_browsertest.cc b/content/browser/native_file_system/file_system_chooser_browsertest.cc index 614583b..dcc1139 100644 --- a/content/browser/native_file_system/file_system_chooser_browsertest.cc +++ b/content/browser/native_file_system/file_system_chooser_browsertest.cc
@@ -5,9 +5,15 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/gmock_callback_support.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" #include "content/browser/native_file_system/file_system_chooser_test_helpers.h" +#include "content/browser/native_file_system/mock_native_file_system_permission_context.h" +#include "content/browser/native_file_system/native_file_system_manager_impl.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/storage_partition.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" @@ -21,6 +27,9 @@ namespace content { +using base::test::RunOnceCallback; +using blink::mojom::PermissionStatus; + // This browser test implements end-to-end tests for the chooseFileSystemEntry // API. class FileSystemChooserBrowserTest : public ContentBrowserTest { @@ -174,6 +183,37 @@ EXPECT_EQ(ui::SelectFileDialog::SELECT_FOLDER, dialog_params.type); } +IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenDirectory_DenyAccess) { + base::FilePath test_dir = CreateTestDir(); + SelectFileDialogParams dialog_params; + ui::SelectFileDialog::SetFactory( + new FakeSelectFileDialogFactory({test_dir}, &dialog_params)); + + testing::StrictMock<MockNativeFileSystemPermissionContext> permission_context; + static_cast<NativeFileSystemManagerImpl*>( + BrowserContext::GetStoragePartition( + shell()->web_contents()->GetBrowserContext(), + shell()->web_contents()->GetSiteInstance()) + ->GetNativeFileSystemEntryFactory()) + ->SetPermissionContextForTesting(&permission_context); + + EXPECT_CALL( + permission_context, + ConfirmDirectoryReadAccess_( + url::Origin::Create(embedded_test_server()->GetURL("/title1.html")), + test_dir, + shell()->web_contents()->GetMainFrame()->GetProcess()->GetID(), + shell()->web_contents()->GetMainFrame()->GetRoutingID(), testing::_)) + .WillOnce(RunOnceCallback<4>(PermissionStatus::DENIED)); + + ASSERT_TRUE( + NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"))); + auto result = + EvalJs(shell(), "self.chooseFileSystemEntries({type: 'openDirectory'})"); + EXPECT_TRUE(result.error.find("AbortError") != std::string::npos) + << result.error; +} + IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, AcceptsOptions) { SelectFileDialogParams dialog_params; ui::SelectFileDialog::SetFactory(
diff --git a/content/browser/native_file_system/mock_native_file_system_permission_context.cc b/content/browser/native_file_system/mock_native_file_system_permission_context.cc new file mode 100644 index 0000000..5755205 --- /dev/null +++ b/content/browser/native_file_system/mock_native_file_system_permission_context.cc
@@ -0,0 +1,23 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/native_file_system/mock_native_file_system_permission_context.h" + +namespace content { + +MockNativeFileSystemPermissionContext::MockNativeFileSystemPermissionContext() = + default; +MockNativeFileSystemPermissionContext:: + ~MockNativeFileSystemPermissionContext() = default; + +void MockNativeFileSystemPermissionContext::ConfirmDirectoryReadAccess( + const url::Origin& origin, + const base::FilePath& path, + int process_id, + int frame_id, + base::OnceCallback<void(PermissionStatus)> callback) { + ConfirmDirectoryReadAccess_(origin, path, process_id, frame_id, callback); +} + +} // namespace content
diff --git a/content/browser/native_file_system/mock_native_file_system_permission_context.h b/content/browser/native_file_system/mock_native_file_system_permission_context.h new file mode 100644 index 0000000..bcba4dc --- /dev/null +++ b/content/browser/native_file_system/mock_native_file_system_permission_context.h
@@ -0,0 +1,41 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_NATIVE_FILE_SYSTEM_MOCK_NATIVE_FILE_SYSTEM_PERMISSION_CONTEXT_H_ +#define CONTENT_BROWSER_NATIVE_FILE_SYSTEM_MOCK_NATIVE_FILE_SYSTEM_PERMISSION_CONTEXT_H_ + +#include "content/public/browser/native_file_system_permission_context.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace content { +// Mock NativeFileSystemPermissionContext implementation. +class MockNativeFileSystemPermissionContext + : public NativeFileSystemPermissionContext { + public: + MockNativeFileSystemPermissionContext(); + ~MockNativeFileSystemPermissionContext(); + + MOCK_METHOD3( + GetWritePermissionGrant, + scoped_refptr<NativeFileSystemPermissionGrant>(const url::Origin& origin, + const base::FilePath& path, + bool is_directory)); + + void ConfirmDirectoryReadAccess( + const url::Origin& origin, + const base::FilePath& path, + int process_id, + int frame_id, + base::OnceCallback<void(PermissionStatus)> callback); + MOCK_METHOD5(ConfirmDirectoryReadAccess_, + void(const url::Origin& origin, + const base::FilePath& path, + int process_id, + int frame_id, + base::OnceCallback<void(PermissionStatus)>& callback)); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_NATIVE_FILE_SYSTEM_MOCK_NATIVE_FILE_SYSTEM_PERMISSION_CONTEXT_H_
diff --git a/content/browser/native_file_system/native_file_system_handle_base.cc b/content/browser/native_file_system/native_file_system_handle_base.cc index 5f9ec024..6887c3cb 100644 --- a/content/browser/native_file_system/native_file_system_handle_base.cc +++ b/content/browser/native_file_system/native_file_system_handle_base.cc
@@ -14,19 +14,23 @@ class NativeFileSystemHandleBase::UsageIndicatorTracker : public WebContentsObserver { public: - UsageIndicatorTracker(int process_id, int frame_id, bool is_directory) + UsageIndicatorTracker(int process_id, + int frame_id, + bool is_directory, + const base::FilePath& directory_path) : WebContentsObserver( WebContentsImpl::FromRenderFrameHostID(process_id, frame_id)), - is_directory_(is_directory) { + is_directory_(is_directory), + directory_path_(directory_path) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (web_contents() && is_directory_) - web_contents()->IncrementNativeFileSystemDirectoryHandleCount(); + web_contents()->AddNativeFileSystemDirectoryHandle(directory_path_); } ~UsageIndicatorTracker() override { if (web_contents()) { if (is_directory_) - web_contents()->DecrementNativeFileSystemDirectoryHandleCount(); + web_contents()->RemoveNativeFileSystemDirectoryHandle(directory_path_); if (is_writable_) web_contents()->DecrementWritableNativeFileSystemHandleCount(); } @@ -49,6 +53,7 @@ private: const bool is_directory_; + const base::FilePath directory_path_; bool is_writable_ = false; }; @@ -74,9 +79,23 @@ << url_.type(); if (url_.type() == storage::kFileSystemTypeNativeLocal) { DCHECK_EQ(url_.mount_type(), storage::kFileSystemTypeIsolated); + base::FilePath directory_path; + if (is_directory) { + // For usage reporting purposes try to get the root path of the isolated + // file system, i.e. the path the user picked in a directory picker. + auto* isolated_context = storage::IsolatedContext::GetInstance(); + if (!isolated_context->GetRegisteredPath(handle_state_.file_system.id(), + &directory_path)) { + // If for some reason the isolated file system no longer exists, fall + // back to the path of the handle itself, which could be a child of the + // originally picked path. + directory_path = url.path(); + } + } usage_indicator_tracker_ = base::SequenceBound<UsageIndicatorTracker>( base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}), - context_.process_id, context_.frame_id, bool{is_directory}); + context_.process_id, context_.frame_id, bool{is_directory}, + base::FilePath(directory_path)); UpdateWritableUsage(); } }
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.cc b/content/browser/native_file_system/native_file_system_manager_impl.cc index 7a25bd3..499fa96d 100644 --- a/content/browser/native_file_system/native_file_system_manager_impl.cc +++ b/content/browser/native_file_system/native_file_system_manager_impl.cc
@@ -295,20 +295,50 @@ std::move(callback).Run(std::move(result), std::move(result_entries)); return; } - result_entries.reserve(entries.size()); - for (const auto& entry : entries) { - if (type == blink::mojom::ChooseFileSystemEntryType::kOpenDirectory) { - result_entries.push_back( - CreateDirectoryEntryFromPath(binding_context, entry)); + + if (type == blink::mojom::ChooseFileSystemEntryType::kOpenDirectory) { + DCHECK_EQ(entries.size(), 1u); + if (permission_context_) { + permission_context_->ConfirmDirectoryReadAccess( + binding_context.origin, entries.front(), binding_context.process_id, + binding_context.frame_id, + base::BindOnce(&NativeFileSystemManagerImpl::DidChooseDirectory, this, + binding_context, entries.front(), + std::move(callback))); } else { - result_entries.push_back(CreateFileEntryFromPath(binding_context, entry)); + DidChooseDirectory(binding_context, entries.front(), std::move(callback), + PermissionStatus::GRANTED); } + return; } + + result_entries.reserve(entries.size()); + for (const auto& entry : entries) + result_entries.push_back(CreateFileEntryFromPath(binding_context, entry)); + // TODO(mek): Auto-grant write permission if this was a file as a result of a // save dialog. std::move(callback).Run(std::move(result), std::move(result_entries)); } +void NativeFileSystemManagerImpl::DidChooseDirectory( + const BindingContext& binding_context, + const base::FilePath& path, + ChooseEntriesCallback callback, + NativeFileSystemPermissionContext::PermissionStatus permission) { + std::vector<blink::mojom::NativeFileSystemEntryPtr> result_entries; + if (permission != PermissionStatus::GRANTED) { + std::move(callback).Run( + NativeFileSystemError::New(base::File::FILE_ERROR_ABORT), + std::move(result_entries)); + return; + } + + result_entries.push_back(CreateDirectoryEntryFromPath(binding_context, path)); + std::move(callback).Run(NativeFileSystemError::New(base::File::FILE_OK), + std::move(result_entries)); +} + void NativeFileSystemManagerImpl::CreateTransferTokenImpl( const storage::FileSystemURL& url, const SharedHandleState& handle_state,
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.h b/content/browser/native_file_system/native_file_system_manager_impl.h index 1ae9483..3276206 100644 --- a/content/browser/native_file_system/native_file_system_manager_impl.h +++ b/content/browser/native_file_system/native_file_system_manager_impl.h
@@ -141,6 +141,11 @@ } storage::FileSystemOperationRunner* operation_runner(); + void SetPermissionContextForTesting( + NativeFileSystemPermissionContext* permission_context) { + permission_context_ = permission_context; + } + private: ~NativeFileSystemManagerImpl() override; void DidOpenSandboxedFileSystem(const BindingContext& binding_context, @@ -154,6 +159,11 @@ ChooseEntriesCallback callback, blink::mojom::NativeFileSystemErrorPtr result, std::vector<base::FilePath> entries); + void DidChooseDirectory( + const BindingContext& binding_context, + const base::FilePath& path, + ChooseEntriesCallback callback, + NativeFileSystemPermissionContext::PermissionStatus permission); void CreateTransferTokenImpl( const storage::FileSystemURL& url, @@ -178,7 +188,7 @@ const scoped_refptr<storage::FileSystemContext> context_; const scoped_refptr<ChromeBlobStorageContext> blob_context_; std::unique_ptr<storage::FileSystemOperationRunner> operation_runner_; - NativeFileSystemPermissionContext* const permission_context_; + NativeFileSystemPermissionContext* permission_context_; // All the mojo bindings for this NativeFileSystemManager itself. Keeps track // of associated origin and other state as well to not have to rely on the
diff --git a/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc b/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc index ddf45d21..4f7cbee 100644 --- a/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc +++ b/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc
@@ -10,6 +10,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" #include "content/browser/native_file_system/fixed_native_file_system_permission_grant.h" +#include "content/browser/native_file_system/mock_native_file_system_permission_context.h" #include "content/public/test/test_browser_thread_bundle.h" #include "storage/browser/blob/blob_storage_context.h" #include "storage/browser/test/test_file_system_context.h" @@ -22,17 +23,6 @@ using blink::mojom::PermissionStatus; using storage::FileSystemURL; -// Mock NativeFileSystemPermissionContext implementation. -class MockNativeFileSystemPermissionContext - : public NativeFileSystemPermissionContext { - public: - MOCK_METHOD3( - GetWritePermissionGrant, - scoped_refptr<NativeFileSystemPermissionGrant>(const url::Origin& origin, - const base::FilePath& path, - bool is_directory)); -}; - class NativeFileSystemManagerImplTest : public testing::Test { public: NativeFileSystemManagerImplTest()
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc index f19d1ed..657e1a0 100644 --- a/content/browser/renderer_host/input/input_router_impl_unittest.cc +++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -1274,10 +1274,10 @@ EXPECT_EQ(0U, disposition_handler_->GetAndResetAckCount()); EXPECT_EQ(1U, GetAndResetDispatchedMessages().size()); - // The remainder of the touch sequence should be dropped. + // The remainder of the touch sequence should be forwarded. ReleaseTouchPoint(0); SendTouchEvent(); - EXPECT_EQ(1U, disposition_handler_->GetAndResetAckCount()); + EXPECT_EQ(0U, disposition_handler_->GetAndResetAckCount()); PressAndSetTouchActionAuto(); EXPECT_EQ(0U, GetAndResetDispatchedMessages().size()); @@ -2061,7 +2061,7 @@ } // Tests that touch event stream validation passes when events are filtered -// out. See crbug.com/581231 for details. +// out. See https://crbug.com/581231 for details. TEST_P(InputRouterImplTest, TouchValidationPassesWithFilteredInputEvents) { // Touch sequence with touch handler. OnHasTouchEventHandlers(true); @@ -2081,11 +2081,11 @@ dispatched_messages[0]->ToEvent()->CallCallback( INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); - // This event will be filtered out, since no consumer exists. + // This event will not be filtered out even though no consumer exists. ReleaseTouchPoint(1); SendTouchEvent(); dispatched_messages = GetAndResetDispatchedMessages(); - EXPECT_EQ(0U, dispatched_messages.size()); + EXPECT_EQ(1U, dispatched_messages.size()); // If the validator didn't see the filtered out release event, it will crash // now, upon seeing a press for a touch which it believes to be still pressed.
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue.cc b/content/browser/renderer_host/input/passthrough_touch_event_queue.cc index dd26e35..238e3a1 100644 --- a/content/browser/renderer_host/input/passthrough_touch_event_queue.cc +++ b/content/browser/renderer_host/input/passthrough_touch_event_queue.cc
@@ -47,7 +47,7 @@ PassthroughTouchEventQueue::kSkipTouchEventFilterType{ &features::kSkipTouchEventFilter, features::kSkipTouchEventFilterTypeParamName, - features::kSkipTouchEventFilterTypeParamValueDiscrete}; + features::kSkipTouchEventFilterTypeParamValueAll}; PassthroughTouchEventQueue::TouchEventWithLatencyInfoAndAckState:: TouchEventWithLatencyInfoAndAckState(const TouchEventWithLatencyInfo& event)
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue.h b/content/browser/renderer_host/input/passthrough_touch_event_queue.h index 3399455..f62862c 100644 --- a/content/browser/renderer_host/input/passthrough_touch_event_queue.h +++ b/content/browser/renderer_host/input/passthrough_touch_event_queue.h
@@ -129,13 +129,13 @@ FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest, TouchScrollStartedUnfiltered); FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest, - TouchStartWithoutPageHandlersFiltered); + TouchStartWithoutPageHandlersUnfiltered); FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest, TouchStartWithPageHandlersUnfiltered); FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest, TouchMoveFilteredAfterTimeout); FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest, - TouchMoveWithoutPageHandlersFiltered); + TouchMoveWithoutPageHandlersUnfiltered); FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest, StationaryTouchMoveFiltered); FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest, @@ -145,7 +145,7 @@ FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest, TouchMoveWithNonTouchMoveUnfiltered); FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest, - TouchMoveWithoutSequenceHandlerFiltered); + TouchMoveWithoutSequenceHandlerUnfiltered); FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest, TouchMoveWithoutPageHandlersUnfilteredWithSkipFlag); FRIEND_TEST_ALL_PREFIXES(PassthroughTouchEventQueueTest,
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc b/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc index 8d51360..9f9c2f4 100644 --- a/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc +++ b/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
@@ -495,36 +495,36 @@ EXPECT_EQ(INPUT_EVENT_ACK_STATE_CONSUMED, acked_event_state()); } -// Tests that addition of a touch handler during a touch sequence will not cause -// the remaining sequence to be forwarded. +// Tests that addition of a touch handler during a touch sequence will continue +// forwarding events. TEST_F(PassthroughTouchEventQueueTest, - ActiveSequenceNotForwardedWhenHandlersAdded) { + ActiveSequenceStillForwardedWhenHandlersAdded) { OnHasTouchEventHandlers(false); // Send a touch-press event while there is no handler. PressTouchPoint(1, 1); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(0U, queued_event_count()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + EXPECT_EQ(1U, queued_event_count()); OnHasTouchEventHandlers(true); - // The remaining touch sequence should not be forwarded. + // The remaining touch sequence should be forwarded. MoveTouchPoint(0, 5, 5); ReleaseTouchPoint(0); - EXPECT_EQ(2U, GetAndResetAckedEventCount()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(0U, queued_event_count()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); + EXPECT_EQ(2U, GetAndResetSentEventCount()); + EXPECT_EQ(3U, queued_event_count()); - // A new touch sequence should resume forwarding. + // A new touch sequence should continue forwarding. PressTouchPoint(1, 1); - EXPECT_EQ(1U, queued_event_count()); + EXPECT_EQ(4U, queued_event_count()); EXPECT_EQ(1U, GetAndResetSentEventCount()); } -// Tests that removal of a touch handler during a touch sequence will prevent -// the remaining sequence from being forwarded, even if another touch handler is -// registered during the same touch sequence. +// Tests that removal of a touch handler during a touch sequence will not +// prevent the remaining sequence from being forwarded, even if another touch +// handler is registered during the same touch sequence. TEST_F(PassthroughTouchEventQueueTest, ActiveSequenceDroppedWhenHandlersRemoved) { // Send a touch-press event. @@ -543,8 +543,7 @@ EXPECT_EQ(0U, GetAndResetAckedEventCount()); EXPECT_EQ(2U, queued_event_count()); - // Repeated registration/unregstration of handlers should have no effect as - // we're still awaiting the ack arrival. + // Repeated registration/unregstration of handlers should have no effect. OnHasTouchEventHandlers(true); EXPECT_EQ(0U, GetAndResetAckedEventCount()); EXPECT_EQ(2U, queued_event_count()); @@ -552,30 +551,30 @@ EXPECT_EQ(0U, GetAndResetAckedEventCount()); EXPECT_EQ(2U, queued_event_count()); - // clear the queue . + // Clear the queue. SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); EXPECT_EQ(2U, GetAndResetAckedEventCount()); EXPECT_EQ(0U, queued_event_count()); - // Events should be dropped while there is no touch handler. + // Events should still be forwarded while there is no touch handler. MoveTouchPoint(0, 10, 10); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); + EXPECT_EQ(1U, queued_event_count()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); // Simulate touch handler registration in the middle of a touch sequence. OnHasTouchEventHandlers(true); // The touch end for the interrupted sequence should be dropped. ReleaseTouchPoint(0); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); + EXPECT_EQ(2U, queued_event_count()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); // A new touch sequence should be forwarded properly. PressTouchPoint(1, 1); - EXPECT_EQ(1U, queued_event_count()); + EXPECT_EQ(3U, queued_event_count()); EXPECT_EQ(1U, GetAndResetSentEventCount()); } @@ -626,16 +625,14 @@ EXPECT_EQ(0U, GetAndResetAckedEventCount()); } -// Tests that touch-move events are not sent to the renderer if the preceding -// touch-press event did not have a consumer (and consequently, did not hit the -// main thread in the renderer). +// Tests that touch-move events are still sent to the renderer even if the +// preceding touch-press event did not have a consumer. TEST_F(PassthroughTouchEventQueueTest, NoConsumer) { // The first touch-press should reach the renderer. PressTouchPoint(1, 1); EXPECT_EQ(1U, GetAndResetSentEventCount()); - // The second touch should be sent since we don't know if there is - // a consumer or not. + // The second touch should be sent too. MoveTouchPoint(0, 5, 5); EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(2U, queued_event_count()); @@ -647,14 +644,13 @@ EXPECT_EQ(2U, GetAndResetAckedEventCount()); EXPECT_EQ(0U, GetAndResetSentEventCount()); - // Send a release event. This should not reach the renderer. + // Send a release event. This should reach the renderer. ReleaseTouchPoint(0); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(WebInputEvent::kTouchEnd, acked_event().GetType()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + EXPECT_EQ(WebInputEvent::kTouchMove, acked_event().GetType()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); - // Send a press-event, followed by move a following move should not - // be sent but held in the queue. + // Send a press-event, followed by a move should be sent. PressTouchPoint(10, 10); MoveTouchPoint(0, 5, 5); @@ -663,11 +659,11 @@ EXPECT_EQ(1U, GetAndResetAckedEventCount()); MoveTouchPoint(0, 6, 5); - EXPECT_EQ(0U, GetAndResetSentEventCount()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(0U, GetAndResetAckedEventCount()); - EXPECT_EQ(2U, queued_event_count()); + EXPECT_EQ(3U, queued_event_count()); SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED); - EXPECT_EQ(2U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, GetAndResetAckedEventCount()); } TEST_F(PassthroughTouchEventQueueTest, AckTouchEventInReverse) { @@ -844,25 +840,26 @@ EXPECT_EQ(WebInputEvent::kTouchMove, acked_event().GetType()); } -// Tests basic TouchEvent forwarding suppression. +// Tests that basic TouchEvent forwarding suppression has been disabled. TEST_F(PassthroughTouchEventQueueTest, NoTouchBasic) { - // Disable TouchEvent forwarding. + // The old behaviour was to suppress events when there were no handlers. + // Signal the no-handler case and test that events still get forwarded. OnHasTouchEventHandlers(false); PressTouchPoint(30, 5); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); - // TouchMove should not be sent to renderer. + // TouchMove should be sent to renderer. MoveTouchPoint(0, 65, 10); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); - // TouchEnd should not be sent to renderer. + // TouchEnd should be sent to renderer. ReleaseTouchPoint(0); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); - // Enable TouchEvent forwarding. + // Signal handlers-present and make sure events are still getting forwarded. OnHasTouchEventHandlers(true); PressTouchPoint(80, 10); @@ -1172,23 +1169,23 @@ EXPECT_EQ(1U, GetAndResetSentEventCount()); EXPECT_EQ(0U, GetAndResetAckedEventCount()); - // Ack the cancel event. Normally, this would resume touch forwarding, + // Ack the cancel event. Normally, this would resume touch forwarding, // but we're still within a scroll gesture so it remains disabled. SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED); EXPECT_FALSE(IsTimeoutRunning()); EXPECT_EQ(0U, GetAndResetSentEventCount()); EXPECT_EQ(0U, GetAndResetAckedEventCount()); - // Try to forward touch events for the current sequence. + // Forward touch events for the current sequence. GetAndResetSentEventCount(); GetAndResetAckedEventCount(); MoveTouchPoint(0, 1, 1); ReleaseTouchPoint(0); - EXPECT_FALSE(IsTimeoutRunning()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(2U, GetAndResetAckedEventCount()); + EXPECT_TRUE(IsTimeoutRunning()); + EXPECT_EQ(2U, GetAndResetSentEventCount()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); - // Now end the scroll sequence, resuming touch handling. + // Now end the scroll sequence. SendGestureEvent(blink::WebInputEvent::kGestureScrollEnd); PressTouchPoint(0, 1); EXPECT_TRUE(IsTimeoutRunning()); @@ -1385,11 +1382,11 @@ ASSERT_EQ(1U, GetAndResetSentEventCount()); ASSERT_EQ(1U, GetAndResetAckedEventCount()); - // Events should not be forwarded, as the point had no consumer. + // Events should be forwarded, even though the point had no consumer. MoveTouchPoint(0, 0, 15); - EXPECT_EQ(0U, queued_event_count()); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, queued_event_count()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); // Simulate a secondary pointer press. PressTouchPoint(20, 0); @@ -1399,7 +1396,7 @@ // TouchMove with a secondary pointer should not be suppressed. MoveTouchPoint(1, 25, 0); - EXPECT_EQ(1U, queued_event_count()); + EXPECT_EQ(2U, queued_event_count()); EXPECT_EQ(1U, GetAndResetSentEventCount()); SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); EXPECT_EQ(1U, GetAndResetAckedEventCount()); @@ -1420,8 +1417,8 @@ WebInputEvent::GetStaticTimeStampForTests()); SetFollowupEvent(followup_scroll); MoveTouchPoint(0, 20, 5); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); EXPECT_EQ(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, acked_event_state()); // The secondary pointer press should be forwarded. @@ -1432,7 +1429,7 @@ // TouchMove with a secondary pointer should also be forwarded. MoveTouchPoint(1, 25, 0); - EXPECT_EQ(1U, queued_event_count()); + EXPECT_EQ(2U, queued_event_count()); EXPECT_EQ(1U, GetAndResetSentEventCount()); SendTouchEventAck(INPUT_EVENT_ACK_STATE_CONSUMED); EXPECT_EQ(1U, GetAndResetAckedEventCount()); @@ -1566,11 +1563,11 @@ EXPECT_EQ(0U, GetAndResetSentEventCount()); EXPECT_EQ(1U, GetAndResetAckedEventCount()); - // Give the touchmove a valid id after release it shouldn't be sent. + // Give the touchmove a valid id after release; it should be sent. event.touches[0].id = press_id; SendTouchEvent(event); - EXPECT_EQ(0U, GetAndResetSentEventCount()); - EXPECT_EQ(1U, GetAndResetAckedEventCount()); + EXPECT_EQ(1U, GetAndResetSentEventCount()); + EXPECT_EQ(0U, GetAndResetAckedEventCount()); } // Tests that touch points states are correct in TouchMove events. @@ -1795,14 +1792,14 @@ FilterBeforeForwarding(event)); } -TEST_F(PassthroughTouchEventQueueTest, TouchStartWithoutPageHandlersFiltered) { +TEST_F(PassthroughTouchEventQueueTest, + TouchStartWithoutPageHandlersUnfiltered) { OnHasTouchEventHandlers(false); SyntheticWebTouchEvent event; event.PressPoint(1, 1); - EXPECT_EQ( - PassthroughTouchEventQueue::PreFilterResult::kFilteredNoPageHandlers, - FilterBeforeForwarding(event)); + EXPECT_EQ(PassthroughTouchEventQueue::PreFilterResult::kUnfiltered, + FilterBeforeForwarding(event)); } TEST_F(PassthroughTouchEventQueueTest, TouchStartWithPageHandlersUnfiltered) { @@ -1831,7 +1828,7 @@ FilterBeforeForwarding(event)); } -TEST_F(PassthroughTouchEventQueueTest, TouchMoveWithoutPageHandlersFiltered) { +TEST_F(PassthroughTouchEventQueueTest, TouchMoveWithoutPageHandlersUnfiltered) { OnHasTouchEventHandlers(false); // Start the touch sequence. PressTouchPoint(1, 1); @@ -1840,9 +1837,8 @@ int id = event.PressPoint(1, 1); event.MovePoint(id, 2, 2); - EXPECT_EQ( - PassthroughTouchEventQueue::PreFilterResult::kFilteredNoPageHandlers, - FilterBeforeForwarding(event)); + EXPECT_EQ(PassthroughTouchEventQueue::PreFilterResult::kUnfiltered, + FilterBeforeForwarding(event)); } TEST_F(PassthroughTouchEventQueueTest, StationaryTouchMoveFiltered) { @@ -1912,7 +1908,7 @@ } TEST_F(PassthroughTouchEventQueueTest, - TouchMoveWithoutSequenceHandlerFiltered) { + TouchMoveWithoutSequenceHandlerUnfiltered) { OnHasTouchEventHandlers(true); // Start the touch sequence. PressTouchPoint(1, 1); @@ -1920,13 +1916,12 @@ // Send an ack indicating that there's no handler for the current sequence. SendTouchEventAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); - // Any subsequent touches in the sequence should be filtered. + // Any subsequent touches in the sequence should be unfiltered. SyntheticWebTouchEvent event; int id = event.PressPoint(1, 1); event.MovePoint(id, 3, 3); - EXPECT_EQ(PassthroughTouchEventQueue::PreFilterResult:: - kFilteredNoHandlerForSequence, + EXPECT_EQ(PassthroughTouchEventQueue::PreFilterResult::kUnfiltered, FilterBeforeForwarding(event)); }
diff --git a/content/browser/renderer_host/render_widget_host_browsertest.cc b/content/browser/renderer_host/render_widget_host_browsertest.cc index 4d86c87..7a3ea100 100644 --- a/content/browser/renderer_host/render_widget_host_browsertest.cc +++ b/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -92,7 +92,8 @@ private: EventTypeVector dispatched_events_; - blink::WebInputEvent::Type acked_touch_event_type_; + blink::WebInputEvent::Type acked_touch_event_type_ = + blink::WebInputEvent::Type::kUndefined; }; class RenderWidgetHostTouchEmulatorBrowserTest : public ContentBrowserTest { @@ -145,7 +146,7 @@ RenderWidgetHostInputEventRouter* router_; base::TimeTicks last_simulated_event_time_; - base::TimeDelta simulated_event_time_delta_; + const base::TimeDelta simulated_event_time_delta_; }; // Synthetic mouse events not allowed on Android. @@ -211,8 +212,6 @@ IN_PROC_BROWSER_TEST_F(RenderWidgetHostTouchEmulatorBrowserTest, TouchEmulator) { - // All touches will be immediately acked instead of sending them to the - // renderer since the test page does not have a touch handler. host()->GetTouchEmulator()->Enable( TouchEmulator::Mode::kEmulatingTouchFromMouse, ui::GestureProviderConfigType::GENERIC_MOBILE); @@ -220,6 +219,8 @@ TestInputEventObserver observer; host()->AddInputEventObserver(&observer); + // Simulate a mouse move without any pressed buttons. This should not + // generate any touch events. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 10, 0, false); TestInputEventObserver::EventTypeVector dispatched_events = observer.GetAndResetDispatchedEventTypes(); @@ -227,71 +228,62 @@ // Mouse press becomes touch start which in turn becomes tap. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseDown, 10, 10, 0, true); - EXPECT_EQ(blink::WebInputEvent::kTouchStart, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(2u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchStart, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGestureTapDown, dispatched_events[1]); // Mouse drag generates touch move, cancels tap and starts scroll. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 30, 0, true); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(4u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchMove, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGestureTapCancel, dispatched_events[1]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin, dispatched_events[2]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollUpdate, dispatched_events[3]); - EXPECT_EQ(blink::WebInputEvent::kTouchMove, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); EXPECT_EQ(0u, observer.GetAndResetDispatchedEventTypes().size()); // Mouse drag with shift becomes pinch. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 35, blink::WebInputEvent::kShiftKey, true); - EXPECT_EQ(blink::WebInputEvent::kTouchMove, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(2u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchMove, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGesturePinchBegin, dispatched_events[1]); SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 50, blink::WebInputEvent::kShiftKey, true); - EXPECT_EQ(blink::WebInputEvent::kTouchMove, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(2u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchMove, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGesturePinchUpdate, dispatched_events[1]); // Mouse drag without shift becomes scroll again. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 60, 0, true); - EXPECT_EQ(blink::WebInputEvent::kTouchMove, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(3u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchMove, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGesturePinchEnd, dispatched_events[1]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollUpdate, dispatched_events[2]); SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 70, 0, true); - EXPECT_EQ(blink::WebInputEvent::kTouchMove, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(2u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchMove, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollUpdate, dispatched_events[1]); SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseUp, 10, 70, 0, true); - EXPECT_EQ(blink::WebInputEvent::kTouchEnd, observer.acked_touch_event_type()); + EXPECT_EQ(blink::WebInputEvent::kUndefined, + observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(2u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchEnd, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd, dispatched_events[1]); // Mouse move does nothing. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 80, 0, false); @@ -300,50 +292,42 @@ // Another mouse down continues scroll. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseDown, 10, 80, 0, true); - EXPECT_EQ(blink::WebInputEvent::kTouchStart, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(2u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchStart, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGestureTapDown, dispatched_events[1]); SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 100, 0, true); - EXPECT_EQ(blink::WebInputEvent::kTouchMove, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(4u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchMove, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGestureTapCancel, dispatched_events[1]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin, dispatched_events[2]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollUpdate, dispatched_events[3]); EXPECT_EQ(0u, observer.GetAndResetDispatchedEventTypes().size()); // Another pinch. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 110, blink::WebInputEvent::kShiftKey, true); - EXPECT_EQ(blink::WebInputEvent::kTouchMove, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - EXPECT_EQ(2u, dispatched_events.size()); + EXPECT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchMove, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGesturePinchBegin, dispatched_events[1]); SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 120, blink::WebInputEvent::kShiftKey, true); - EXPECT_EQ(blink::WebInputEvent::kTouchMove, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - EXPECT_EQ(2u, dispatched_events.size()); + EXPECT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchMove, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGesturePinchUpdate, dispatched_events[1]); // Turn off emulation during a pinch. host()->GetTouchEmulator()->Disable(); - EXPECT_EQ(blink::WebInputEvent::kTouchCancel, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(3u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchCancel, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGesturePinchEnd, dispatched_events[1]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd, dispatched_events[2]); // Mouse event should pass untouched. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 10, @@ -359,34 +343,29 @@ // Another touch. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseDown, 10, 10, 0, true); - EXPECT_EQ(blink::WebInputEvent::kTouchStart, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(2u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchStart, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGestureTapDown, dispatched_events[1]); // Scroll. SimulateRoutedMouseEvent(blink::WebInputEvent::kMouseMove, 10, 30, 0, true); - EXPECT_EQ(blink::WebInputEvent::kTouchMove, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(4u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchMove, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGestureTapCancel, dispatched_events[1]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollBegin, dispatched_events[2]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollUpdate, dispatched_events[3]); EXPECT_EQ(0u, observer.GetAndResetDispatchedEventTypes().size()); // Turn off emulation during a scroll. host()->GetTouchEmulator()->Disable(); - EXPECT_EQ(blink::WebInputEvent::kTouchCancel, + EXPECT_EQ(blink::WebInputEvent::kUndefined, observer.acked_touch_event_type()); dispatched_events = observer.GetAndResetDispatchedEventTypes(); - ASSERT_EQ(2u, dispatched_events.size()); + ASSERT_EQ(1u, dispatched_events.size()); EXPECT_EQ(blink::WebInputEvent::kTouchCancel, dispatched_events[0]); - EXPECT_EQ(blink::WebInputEvent::kGestureScrollEnd, dispatched_events[1]); host()->RemoveInputEventObserver(&observer); }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index cf362af0..977aa912 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -1489,20 +1489,22 @@ ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), ui::EventTimeForNow(), ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0)); - // The touch events should get forwarded from the view, but they should not - // reach the renderer. + // The touch events should get forwarded from the view and make it all the + // way to the renderer. view_->OnTouchEvent(&press); base::RunLoop().RunUntilIdle(); MockWidgetInputHandler::MessageVector events = GetAndResetDispatchedMessages(); - EXPECT_EQ(0U, events.size()); + EXPECT_EQ(1U, events.size()); + EXPECT_EQ("TouchStart", GetMessageNames(events)); EXPECT_TRUE(press.synchronous_handling_disabled()); EXPECT_EQ(ui::MotionEvent::Action::DOWN, pointer_state().GetAction()); view_->OnTouchEvent(&move); base::RunLoop().RunUntilIdle(); events = GetAndResetDispatchedMessages(); - EXPECT_EQ(0U, events.size()); + EXPECT_EQ(1U, events.size()); + EXPECT_EQ("TouchMove", GetMessageNames(events)); EXPECT_TRUE(press.synchronous_handling_disabled()); EXPECT_EQ(ui::MotionEvent::Action::MOVE, pointer_state().GetAction()); EXPECT_EQ(1U, pointer_state().GetPointerCount()); @@ -1510,7 +1512,8 @@ view_->OnTouchEvent(&release); base::RunLoop().RunUntilIdle(); events = GetAndResetDispatchedMessages(); - EXPECT_EQ(0U, events.size()); + EXPECT_EQ(1U, events.size()); + EXPECT_EQ("TouchEnd", GetMessageNames(events)); EXPECT_TRUE(press.synchronous_handling_disabled()); EXPECT_EQ(0U, pointer_state().GetPointerCount()); @@ -1574,7 +1577,8 @@ EXPECT_TRUE(press.synchronous_handling_disabled()); EXPECT_EQ(0U, pointer_state().GetPointerCount()); events = GetAndResetDispatchedMessages(); - EXPECT_EQ(0U, events.size()); + EXPECT_EQ(2U, events.size()); + EXPECT_EQ("TouchMove TouchEnd", GetMessageNames(events)); } // The DOM KeyCode map for Fuchsia maps all DomCodes to 0. This means that
diff --git a/content/browser/renderer_host/render_widget_targeter.cc b/content/browser/renderer_host/render_widget_targeter.cc index 0ee1b50..6fc0309e 100644 --- a/content/browser/renderer_host/render_widget_targeter.cc +++ b/content/browser/renderer_host/render_widget_targeter.cc
@@ -5,8 +5,6 @@ #include "content/browser/renderer_host/render_widget_targeter.h" #include "base/bind.h" -#include "base/debug/crash_logging.h" -#include "base/debug/dump_without_crashing.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" @@ -14,10 +12,8 @@ #include "components/viz/host/host_frame_sink_manager.h" #include "content/browser/compositor/surface_utils.h" #include "content/browser/renderer_host/input/one_shot_timeout_monitor.h" -#include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" -#include "content/public/browser/render_frame_host.h" #include "content/public/browser/site_isolation_policy.h" #include "third_party/blink/public/platform/web_input_event.h" #include "ui/events/blink/blink_event_util.h" @@ -55,29 +51,6 @@ constexpr const char kTracingCategory[] = "input,latency"; -// This function helps with debugging the reasons of viz hit testing mismatch. -void DumpWithoutCrashing(RenderWidgetHostViewBase* root_view, - RenderWidgetHostViewBase* target, - const base::Optional<gfx::PointF>& target_location) { - RenderViewHostImpl* rvh = - RenderViewHostImpl::From(root_view->GetRenderWidgetHost()); - if (!rvh || !rvh->GetMainFrame()) - return; - static auto* crash_key = base::debug::AllocateCrashKeyString( - "vizhittest-mismatch-v2-url", base::debug::CrashKeySize::Size256); - const std::string& url = - rvh->GetMainFrame()->GetLastCommittedURL().GetOrigin().spec(); - base::debug::SetCrashKeyString(crash_key, url); - - crash_key = base::debug::AllocateCrashKeyString( - "vizhittest-mismatch-v2-coordinate", base::debug::CrashKeySize::Size32); - const std::string& global_coordinate = - target->TransformPointToRootCoordSpaceF(target_location.value()) - .ToString(); - base::debug::SetCrashKeyString(crash_key, global_coordinate); - base::debug::DumpWithoutCrashing(); -} - } // namespace class TracingUmaTracker { @@ -481,7 +454,6 @@ // If the result did not change, it is likely that viz hit test finds // the wrong target. match_result = HitTestResultsMatch::kDoNotMatch; - DumpWithoutCrashing(root_view, target, target_location); } else { // Hit test data changed, so the result is no longer reliable. match_result = HitTestResultsMatch::kHitTestResultChanged;
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc index 5f7459ef..263d3864 100644 --- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc +++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -658,8 +658,15 @@ return false; network::ResourceRequest resource_request(original_request); - resource_request.resource_type = - static_cast<int>(ResourceType::kNavigationPreload); + if (resource_type_ == ResourceType::kMainFrame) { + resource_request.resource_type = + static_cast<int>(ResourceType::kNavigationPreloadMainFrame); + } else { + DCHECK_EQ(ResourceType::kSubFrame, resource_type_); + resource_request.resource_type = + static_cast<int>(ResourceType::kNavigationPreloadSubFrame); + } + resource_request.skip_service_worker = true; resource_request.do_not_prompt_for_login = true;
diff --git a/content/browser/sms/OWNERS b/content/browser/sms/OWNERS index a5caa2ed..9bb2ad2b 100644 --- a/content/browser/sms/OWNERS +++ b/content/browser/sms/OWNERS
@@ -1,5 +1,6 @@ +ayui@chromium.org jsbell@chromium.org reillyg@chromium.org # COMPONENT: Blink>SMS -# TEAM: fugu-dev@chromium.org \ No newline at end of file +# TEAM: fugu-dev@chromium.org
diff --git a/content/browser/sms/sms_provider.cc b/content/browser/sms/sms_provider.cc index 3b95cd2..13ecffa2 100644 --- a/content/browser/sms/sms_provider.cc +++ b/content/browser/sms/sms_provider.cc
@@ -54,10 +54,6 @@ } } -void SmsProvider::NotifyTimeout() { - observers_.begin()->OnTimeout(); -} - bool SmsProvider::HasObservers() { return observers_.might_have_observers(); }
diff --git a/content/browser/sms/sms_provider.h b/content/browser/sms/sms_provider.h index 48eebfa..6502afd 100644 --- a/content/browser/sms/sms_provider.h +++ b/content/browser/sms/sms_provider.h
@@ -28,7 +28,6 @@ // Receive an |sms| from an origin. Return true if the message is // handled, which stops its propagation to other observers. virtual bool OnReceive(const url::Origin&, const std::string& sms) = 0; - virtual void OnTimeout() = 0; }; SmsProvider(); @@ -44,7 +43,6 @@ void RemoveObserver(const Observer*); void NotifyReceive(const url::Origin&, const std::string& sms); void NotifyReceive(const std::string& sms); - void NotifyTimeout(); bool HasObservers(); private:
diff --git a/content/browser/sms/sms_provider_android.cc b/content/browser/sms/sms_provider_android.cc index 504c06b5..270d8f2 100644 --- a/content/browser/sms/sms_provider_android.cc +++ b/content/browser/sms/sms_provider_android.cc
@@ -48,7 +48,6 @@ void SmsProviderAndroid::OnTimeout( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj) { - NotifyTimeout(); } } // namespace content
diff --git a/content/browser/sms/sms_receiver_impl.cc b/content/browser/sms/sms_receiver_impl.cc index 56b7f1d..f6fa8e2 100644 --- a/content/browser/sms/sms_receiver_impl.cc +++ b/content/browser/sms/sms_receiver_impl.cc
@@ -21,48 +21,70 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } +SmsReceiverImpl::Request::Request(ReceiveCallback callback) + : callback(std::move(callback)) {} + +SmsReceiverImpl::Request::~Request() = default; + void SmsReceiverImpl::Receive(base::TimeDelta timeout, ReceiveCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - Push(std::move(callback)); -} -void SmsReceiverImpl::Push(ReceiveCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (callbacks_.empty()) + if (requests_.empty()) sms_provider_->AddObserver(this); - callbacks_.push(std::move(callback)); + auto request = std::make_unique<Request>(std::move(callback)); + // The |timer| is owned by |request|, and |request| is owned by |this|, so it + // is safe to hold raw pointers to |this| and |request| here in the callback. + request->timer.Start(FROM_HERE, timeout, + base::BindOnce(&SmsReceiverImpl::OnTimeout, + base::Unretained(this), request.get())); + requests_.push_back(std::move(request)); sms_provider_->Retrieve(); } -blink::mojom::SmsReceiver::ReceiveCallback SmsReceiverImpl::Pop() { - DCHECK(!callbacks_.empty()) << "Unexpected SMS received"; - - ReceiveCallback callback = std::move(callbacks_.front()); - callbacks_.pop(); - - if (callbacks_.empty()) - sms_provider_->RemoveObserver(this); - - return callback; -} - bool SmsReceiverImpl::OnReceive(const url::Origin& origin, const std::string& sms) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (origin_ != origin) return false; - Pop().Run(blink::mojom::SmsStatus::kSuccess, sms); + return Pop(sms); +} + +bool SmsReceiverImpl::Pop(const std::string& sms) { + DCHECK(!requests_.empty()); + + DCHECK(requests_.front()->timer.IsRunning()); + + requests_.front()->timer.Stop(); + std::move(requests_.front()->callback) + .Run(blink::mojom::SmsStatus::kSuccess, sms); + requests_.pop_front(); + + if (requests_.empty()) + sms_provider_->RemoveObserver(this); return true; } -void SmsReceiverImpl::OnTimeout() { +void SmsReceiverImpl::OnTimeout(Request* request) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - Pop().Run(blink::mojom::SmsStatus::kTimeout, base::nullopt); + DCHECK(!request->timer.IsRunning()); + + std::move(request->callback) + .Run(blink::mojom::SmsStatus::kTimeout, base::nullopt); + + // Remove the request from the list. + for (auto iter = requests_.begin(); iter != requests_.end(); ++iter) { + if ((*iter).get() == request) { + requests_.erase(iter); + if (requests_.empty()) + sms_provider_->RemoveObserver(this); + return; + } + } } } // namespace content
diff --git a/content/browser/sms/sms_receiver_impl.h b/content/browser/sms/sms_receiver_impl.h index cf0298c8..717732d 100644 --- a/content/browser/sms/sms_receiver_impl.h +++ b/content/browser/sms/sms_receiver_impl.h
@@ -5,13 +5,14 @@ #ifndef CONTENT_BROWSER_SMS_SMS_RECEIVER_IMPL_H_ #define CONTENT_BROWSER_SMS_SMS_RECEIVER_IMPL_H_ +#include <list> #include <memory> -#include <queue> #include "base/callback_forward.h" #include "base/macros.h" #include "base/sequence_checker.h" #include "base/time/time.h" +#include "base/timer/timer.h" #include "content/browser/sms/sms_provider.h" #include "content/common/content_export.h" #include "third_party/blink/public/mojom/sms/sms_receiver.mojom.h" @@ -25,23 +26,33 @@ SmsReceiverImpl(SmsProvider*, const url::Origin&); ~SmsReceiverImpl() override; + struct Request { + explicit Request(ReceiveCallback callback); + ~Request(); + + base::OneShotTimer timer; + ReceiveCallback callback; + + DISALLOW_COPY_AND_ASSIGN(Request); + }; + // content::SmsProvider::Observer: bool OnReceive(const url::Origin&, const std::string& message) override; - void OnTimeout() override; // blink::mojom::SmsReceiver: void Receive(base::TimeDelta timeout, ReceiveCallback) override; private: - // Manages the queue of callbacks. - void Push(ReceiveCallback); - ReceiveCallback Pop(); + bool Pop(const std::string& sms); + void OnTimeout(Request* request); // |sms_provider_| is safe because all instances of SmsReceiverImpl are owned // by SmsServiceImpl through a StrongBindingSet. SmsProvider* sms_provider_; const url::Origin origin_; - std::queue<ReceiveCallback> callbacks_; + + using SmsRequestList = std::list<std::unique_ptr<Request>>; + SmsRequestList requests_; SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(SmsReceiverImpl);
diff --git a/content/browser/sms/sms_service_impl_unittest.cc b/content/browser/sms/sms_service_impl_unittest.cc index abcff269..5cb666c 100644 --- a/content/browser/sms/sms_service_impl_unittest.cc +++ b/content/browser/sms/sms_service_impl_unittest.cc
@@ -299,12 +299,8 @@ base::RunLoop loop; - EXPECT_CALL(*mock, Retrieve()).WillOnce(Invoke([&mock]() { - mock->NotifyTimeout(); - })); - service_ptr->Receive( - base::TimeDelta::FromSeconds(10), + base::TimeDelta::FromSeconds(0), base::BindLambdaForTesting([&](blink::mojom::SmsStatus status, const base::Optional<std::string>& sms) { EXPECT_EQ(blink::mojom::SmsStatus::kTimeout, status); @@ -340,7 +336,7 @@ .WillOnce(Invoke([&listen]() { listen.Quit(); })); service_ptr1->Receive( - base::TimeDelta::FromSeconds(10), + base::TimeDelta::FromSeconds(0), base::BindLambdaForTesting([&](blink::mojom::SmsStatus status, const base::Optional<std::string>& sms) { sms_status1 = status; @@ -359,9 +355,8 @@ listen.Run(); - // Timesout the first request. - - mock->NotifyTimeout(); + // The first request immediately times out because it uses TimeDelta of 0 + // seconds. sms_loop1.Run(); @@ -377,4 +372,66 @@ EXPECT_EQ(blink::mojom::SmsStatus::kSuccess, sms_status2); } +TEST_F(SmsServiceImplTest, SecondRequestTimesOutEarlierThanFirstRequest) { + auto impl = std::make_unique<SmsServiceImpl>(); + auto* mock = new NiceMock<MockSmsProvider>(); + + impl->SetSmsProviderForTest(base::WrapUnique(mock)); + + blink::mojom::SmsReceiverPtr service_ptr1; + GURL url1("http://a.com"); + impl->Bind(mojo::MakeRequest(&service_ptr1), url::Origin::Create(url1)); + + blink::mojom::SmsReceiverPtr service_ptr2; + GURL url2("http://b.com"); + impl->Bind(mojo::MakeRequest(&service_ptr2), url::Origin::Create(url2)); + + blink::mojom::SmsStatus sms_status1; + base::Optional<std::string> response1; + blink::mojom::SmsStatus sms_status2; + base::Optional<std::string> response2; + + base::RunLoop listen, sms_loop1, sms_loop2; + + EXPECT_CALL(*mock, Retrieve()) + .WillOnce(testing::Return()) + .WillOnce(Invoke([&listen]() { listen.Quit(); })); + + service_ptr1->Receive( + base::TimeDelta::FromSeconds(10), + base::BindLambdaForTesting([&](blink::mojom::SmsStatus status, + const base::Optional<std::string>& sms) { + sms_status1 = status; + response1 = sms; + sms_loop1.Quit(); + })); + + service_ptr2->Receive( + base::TimeDelta::FromSeconds(0), + base::BindLambdaForTesting([&](blink::mojom::SmsStatus status, + const base::Optional<std::string>& sms) { + sms_status2 = status; + response2 = sms; + sms_loop2.Quit(); + })); + + listen.Run(); + + // The second request immediately times out because it uses TimeDelta of 0 + // seconds. + + sms_loop2.Run(); + + EXPECT_EQ(blink::mojom::SmsStatus::kTimeout, sms_status2); + + // Delivers the first SMS. + + mock->NotifyReceive(url::Origin::Create(url1), "first"); + + sms_loop1.Run(); + + EXPECT_EQ("first", response1.value()); + EXPECT_EQ(blink::mojom::SmsStatus::kSuccess, sms_status1); +} + } // namespace content
diff --git a/content/browser/tracing/background_tracing_config_impl.cc b/content/browser/tracing/background_tracing_config_impl.cc index 2cbac09a..c5b9bf88 100644 --- a/content/browser/tracing/background_tracing_config_impl.cc +++ b/content/browser/tracing/background_tracing_config_impl.cc
@@ -281,10 +281,10 @@ chrome_config.SetTraceBufferSizeInKb(GetMaximumTraceBufferSizeKb()); #if defined(OS_ANDROID) - // Set low trace buffer size on Android in order to upload small trace files. + // For legacy tracing backend, set low trace buffer size on Android in order + // to upload small trace files. if (tracing_mode() == BackgroundTracingConfigImpl::PREEMPTIVE) { chrome_config.SetTraceBufferSizeInEvents(20000); - chrome_config.SetTraceBufferSizeInKb(500); } #endif
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 702a9c4c..b912bd1 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -14,6 +14,7 @@ #include "base/command_line.h" #include "base/debug/dump_without_crashing.h" #include "base/feature_list.h" +#include "base/files/file_path.h" #include "base/i18n/character_encoding.h" #include "base/lazy_instance.h" #include "base/location.h" @@ -1575,7 +1576,16 @@ } bool WebContentsImpl::HasNativeFileSystemDirectoryHandles() { - return native_file_system_directory_handle_count_ > 0; + return !native_file_system_directory_handles_.empty(); +} + +std::vector<base::FilePath> +WebContentsImpl::GetNativeFileSystemDirectoryHandles() { + std::vector<base::FilePath> result; + result.reserve(native_file_system_directory_handles_.size()); + for (auto const& entry : native_file_system_directory_handles_) + result.push_back(entry.first); + return result; } bool WebContentsImpl::HasWritableNativeFileSystemHandles() { @@ -6882,7 +6892,8 @@ NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); } -void WebContentsImpl::IncrementNativeFileSystemDirectoryHandleCount() { +void WebContentsImpl::AddNativeFileSystemDirectoryHandle( + const base::FilePath& path) { // Trying to invalidate the tab state while being destroyed could result in a // use after free. if (IsBeingDestroyed()) @@ -6891,14 +6902,16 @@ // Notify for UI updates if the state changes. Need both TYPE_TAB and TYPE_URL // to update both the tab-level usage indicator and the usage indicator in the // omnibox. - native_file_system_directory_handle_count_++; - if (native_file_system_directory_handle_count_ == 1) { + const bool was_empty = native_file_system_directory_handles_.empty(); + native_file_system_directory_handles_[path]++; + if (was_empty) { NotifyNavigationStateChanged(static_cast<content::InvalidateTypes>( INVALIDATE_TYPE_TAB | INVALIDATE_TYPE_URL)); } } -void WebContentsImpl::DecrementNativeFileSystemDirectoryHandleCount() { +void WebContentsImpl::RemoveNativeFileSystemDirectoryHandle( + const base::FilePath& path) { // Trying to invalidate the tab state while being destroyed could result in a // use after free. if (IsBeingDestroyed()) @@ -6907,9 +6920,13 @@ // Notify for UI updates if the state changes. Need both TYPE_TAB and TYPE_URL // to update both the tab-level usage indicator and the usage indicator in the // omnibox. - DCHECK_NE(0u, native_file_system_directory_handle_count_); - native_file_system_directory_handle_count_--; - if (native_file_system_directory_handle_count_ == 0) { + auto it = native_file_system_directory_handles_.find(path); + DCHECK(it != native_file_system_directory_handles_.end()); + DCHECK_NE(0u, it->second); + it->second--; + if (it->second == 0) + native_file_system_directory_handles_.erase(it); + if (native_file_system_directory_handles_.empty()) { NotifyNavigationStateChanged(static_cast<content::InvalidateTypes>( INVALIDATE_TYPE_TAB | INVALIDATE_TYPE_URL)); }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 327184c1..f638d3c 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -77,6 +77,10 @@ #include "content/public/browser/android/child_process_importance.h" #endif +namespace base { +class FilePath; +} + namespace service_manager { class InterfaceProvider; } @@ -352,6 +356,7 @@ bool IsConnectedToBluetoothDevice() override; bool IsConnectedToSerialPort() override; bool HasNativeFileSystemDirectoryHandles() override; + std::vector<base::FilePath> GetNativeFileSystemDirectoryHandles() override; bool HasWritableNativeFileSystemHandles() override; bool HasPictureInPictureVideo() override; bool IsCrashed() override; @@ -961,10 +966,11 @@ void IncrementSerialActiveFrameCount(); void DecrementSerialActiveFrameCount(); - // Modify the counter of native file system directory handles for this - // WebContents. - void IncrementNativeFileSystemDirectoryHandleCount(); - void DecrementNativeFileSystemDirectoryHandleCount(); + // Add and remove a reference for a native file system directory handle for a + // certain |path|. Multiple Add calls should be balanced by the same number of + // Remove calls for the same |path|. + void AddNativeFileSystemDirectoryHandle(const base::FilePath& path); + void RemoveNativeFileSystemDirectoryHandle(const base::FilePath& path); // Modify the counter of native file system handles with write access for this // WebContents. @@ -1806,7 +1812,7 @@ size_t bluetooth_connected_device_count_ = 0; size_t serial_active_frame_count_ = 0; - size_t native_file_system_directory_handle_count_ = 0; + std::map<base::FilePath, size_t> native_file_system_directory_handles_; size_t native_file_system_writable_handle_count_ = 0; bool has_picture_in_picture_video_ = false;
diff --git a/content/browser/webauth/uv_preferred.md b/content/browser/webauth/uv_preferred.md new file mode 100644 index 0000000..d38208d --- /dev/null +++ b/content/browser/webauth/uv_preferred.md
@@ -0,0 +1,11 @@ +# Advice to sites regarding `preferred` user verification + +The default value for [user verification](https://www.w3.org/TR/webauthn/#enumdef-userverificationrequirement) in [Web Authentication](https://www.w3.org/TR/webauthn/)'s [create](https://www.w3.org/TR/webauthn/#createCredential) and [get](https://www.w3.org/TR/webauthn/#getAssertion) calls is `preferred`. The semantics of this have been surprising to several sites and so, if no value is provided, Blink will emit a warning in the Javascript console. This warning can be silenced by explicitly setting any valid value for `userVerification`. For a `create` call, this requires setting a value for publicKey.[authenticatorSelection](https://www.w3.org/TR/webauthn/#authenticatorSelection).[userVerification](https://www.w3.org/TR/webauthn/#dom-authenticatorselectioncriteria-userverification) and, for a `get` call, setting publicKey.[userVerification](https://www.w3.org/TR/webauthn/#dom-publickeycredentialrequestoptions-userverification). The valid values are enumerated as [UserVerificationRequirement](https://www.w3.org/TR/webauthn/#enumdef-userverificationrequirement). + +The default, `preferred` value instructs the user-agent to acquire [user verification](https://www.w3.org/TR/webauthn/#user-verification) “[if possible](https://www.w3.org/TR/webauthn/#dom-userverificationrequirement-preferred)”. On modern versions of Windows this is interpreted such that a user will be prompted to configure a PIN during credential creation on an authenticator that supports it, and such that a user will be prompted for a PIN if one is already set. On other platforms, Chrome will not direct the user to create a PIN if one is not already set, but will be prompt for a PIN if one is configured. This is quite different from the traditional user experience of security keys. + +The traditional user experience is best replicated by setting `userVerification` to `discouraged`. This does not preclude the [UV flag](https://www.w3.org/TR/webauthn/#flags) being set in a signature because some authenticators may always do user verification. (For example, a built-in fingerprint reader.) But it will prevent PIN prompts from appearing. + +Sites that desire user verification should set `userVerification` to `required` to indicate this. This will, however, limit users to authenticators that support some form of user verification and many do not. + +There is not currently a way in WebAuthn to express that a site would like user verification if it's low-cost for the user so that later reauthentication may use WebAuthn rather than a password.
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc index ba3d3ff..1667aa52 100644 --- a/content/browser/worker_host/shared_worker_host.cc +++ b/content/browser/worker_host/shared_worker_host.cc
@@ -311,17 +311,17 @@ url::Origin origin = instance_->constructor_origin(); network::mojom::TrustedURLLoaderHeaderClientPtrInfo no_header_client; - // TODO(crbug.com/955476): network_isolation_key to be created using worker - // script's origin. if (GetCreateNetworkFactoryCallbackForSharedWorker().is_null()) { - process->CreateURLLoaderFactory( - origin, nullptr /* preferences */, net::NetworkIsolationKey(), - std::move(no_header_client), std::move(request)); + process->CreateURLLoaderFactory(origin, nullptr /* preferences */, + net::NetworkIsolationKey(origin, origin), + std::move(no_header_client), + std::move(request)); } else { network::mojom::URLLoaderFactoryPtr original_factory; - process->CreateURLLoaderFactory( - origin, nullptr /* preferences */, net::NetworkIsolationKey(), - std::move(no_header_client), mojo::MakeRequest(&original_factory)); + process->CreateURLLoaderFactory(origin, nullptr /* preferences */, + net::NetworkIsolationKey(origin, origin), + std::move(no_header_client), + mojo::MakeRequest(&original_factory)); GetCreateNetworkFactoryCallbackForSharedWorker().Run( std::move(request), process_id_, original_factory.PassInterface()); }
diff --git a/content/browser/service_worker/service_worker_network_isolation_key_browsertest.cc b/content/browser/worker_network_isolation_key_browsertest.cc similarity index 64% rename from content/browser/service_worker/service_worker_network_isolation_key_browsertest.cc rename to content/browser/worker_network_isolation_key_browsertest.cc index f8f6264..5f980d5 100644 --- a/content/browser/service_worker/service_worker_network_isolation_key_browsertest.cc +++ b/content/browser/worker_network_isolation_key_browsertest.cc
@@ -6,6 +6,7 @@ #include "base/strings/strcat.h" #include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" +#include "build/build_config.h" #include "content/public/common/content_paths.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" @@ -16,10 +17,28 @@ namespace content { -class ServiceWorkerNetworkIsolationKeyBrowserTest +namespace { + +bool SupportsSharedWorker() { +#if defined(OS_ANDROID) + // SharedWorkers are not enabled on Android. https://crbug.com/154571 + return false; +#else + return true; +#endif +} + +} // namespace + +enum class WorkerType { + kServiceWorker, + kSharedWorker, +}; + +class WorkerNetworkIsolationKeyBrowserTest : public ContentBrowserTest, public ::testing::WithParamInterface< - bool /* test_same_network_isolation_key */> { + std::tuple<bool /* test_same_network_isolation_key */, WorkerType>> { public: void SetUp() override { feature_list_.InitAndEnableFeature( @@ -42,11 +61,12 @@ process_watcher.Wait(); } - // Register a service worker |main_script_file| in the scope of + // Register a service/shared worker |main_script_file| in the scope of // |embedded_test_server|'s origin, that does // importScripts(|import_script_url|) and fetch(|fetch_url|). - void RegisterServiceWorkerThatDoesImportScriptsAndFetch( + void RegisterWorkerThatDoesImportScriptsAndFetch( const net::EmbeddedTestServer* embedded_test_server, + WorkerType worker_type, const std::string& main_script_file, const GURL& import_script_url, const GURL& fetch_url) { @@ -54,8 +74,7 @@ shell()->web_contents(), /*number_of_navigations*/ 1, content::MessageLoopRunner::QuitMode::DEFERRED); std::string subframe_url = - embedded_test_server - ->GetURL("/service_worker/create_service_worker.html") + embedded_test_server->GetURL("/workers/service_worker_setup.html") .spec(); std::string subframe_name = GetUniqueSubframeName(); @@ -74,9 +93,18 @@ {main_script_file, "?import_script_url=", import_script_url.spec(), "&fetch_url=", fetch_url.spec()}); - EXPECT_EQ("DONE", - EvalJs(subframe_rfh, - JsReplace("register($1)", main_script_file_with_param))); + switch (worker_type) { + case WorkerType::kServiceWorker: + EXPECT_EQ("ok", + EvalJs(subframe_rfh, + JsReplace("setup($1)", main_script_file_with_param))); + break; + case WorkerType::kSharedWorker: + EXPECT_EQ(nullptr, EvalJs(subframe_rfh, + JsReplace("let worker = new SharedWorker($1)", + main_script_file_with_param))); + break; + } } private: @@ -89,17 +117,23 @@ base::test::ScopedFeatureList feature_list_; }; -// Test that network isolation key is filled in correctly for service workers. -// It checks the cache status of importScripts() as well as fetch() request from -// two different service workers, where the two workers may be from the same or -// different origin - network isolation key. When the origins are the same, we -// expect the 2nd importScripts and/or fetch request to exist in the cache, and -// when the origins are different, we expect the 2nd request to not exist in the -// cache. The imported/fetched script are always the same as it's a control -// variable for this test. -IN_PROC_BROWSER_TEST_P(ServiceWorkerNetworkIsolationKeyBrowserTest, +// Test that network isolation key is filled in correctly for service/shared +// workers. The test navigates to "a.com" and creates two cross-origin iframes +// that each start a worker. The frames/workers may have the same origin, so +// worker1 is on "b.com" and worker2 is on either "b.com" or "c.com". The test +// checks the cache status of importScripts() and a fetch() request from the +// workers to another origin "d.com". When the workers had the same origin (the +// same network isolation key), we expect the second importScripts() and fetch() +// request to exist in the cache. When the origins are different, we expect the +// second requests to not exist in the cache. +IN_PROC_BROWSER_TEST_P(WorkerNetworkIsolationKeyBrowserTest, ImportScriptsAndFetchRequest) { - bool test_same_network_isolation_key = GetParam(); + bool test_same_network_isolation_key; + WorkerType worker_type; + std::tie(test_same_network_isolation_key, worker_type) = GetParam(); + + if (worker_type == WorkerType::kSharedWorker && !SupportsSharedWorker()) + return; // Discard the old process to clear the in-memory cache. CrossProcessNavigation(); @@ -119,10 +153,8 @@ net::EmbeddedTestServer resource_request_server; resource_request_server.ServeFilesFromSourceDirectory(GetTestDataFilePath()); ASSERT_TRUE(resource_request_server.Start()); - GURL import_script_url = - resource_request_server.GetURL("/service_worker/empty.js"); - GURL fetch_url = - resource_request_server.GetURL("/service_worker/empty2.html"); + GURL import_script_url = resource_request_server.GetURL("/workers/empty.js"); + GURL fetch_url = resource_request_server.GetURL("/workers/empty.html"); std::map<GURL, size_t> request_completed_count; @@ -153,21 +185,24 @@ {}); NavigateToURLBlockUntilNavigationsComplete( - shell(), - embedded_test_server()->GetURL("/service_worker/frame_factory.html"), 1); + shell(), embedded_test_server()->GetURL("/workers/frame_factory.html"), + 1); - RegisterServiceWorkerThatDoesImportScriptsAndFetch( - &cross_origin_server_1, "worker_with_import_and_fetch.js", + RegisterWorkerThatDoesImportScriptsAndFetch( + &cross_origin_server_1, worker_type, "worker_with_import_and_fetch.js", import_script_url, fetch_url); - RegisterServiceWorkerThatDoesImportScriptsAndFetch( - &cross_origin_server_2, "worker_with_import_and_fetch_2.js", + RegisterWorkerThatDoesImportScriptsAndFetch( + &cross_origin_server_2, worker_type, "worker_with_import_and_fetch_2.js", import_script_url, fetch_url); cache_status_waiter.Run(); } -INSTANTIATE_TEST_SUITE_P(/* no prefix */, - ServiceWorkerNetworkIsolationKeyBrowserTest, - testing::Bool()); +INSTANTIATE_TEST_SUITE_P( + /* no prefix */, + WorkerNetworkIsolationKeyBrowserTest, + ::testing::Combine(testing::Bool(), + ::testing::Values(WorkerType::kServiceWorker, + WorkerType::kSharedWorker))); } // namespace content
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc index 4cf94cf3..296b3d1 100644 --- a/content/child/child_thread_impl.cc +++ b/content/child/child_thread_impl.cc
@@ -198,7 +198,8 @@ #elif defined(OS_MACOSX) auto* client = base::MachPortRendezvousClient::GetInstance(); if (!client) { - LOG(ERROR) << "Mach rendezvous failed."; + LOG(ERROR) << "Mach rendezvous failed, terminating process (parent died?)"; + base::Process::TerminateCurrentProcessImmediately(0); return {}; } auto receive = client->TakeReceiveRight('mojo');
diff --git a/content/common/tab_switch_time_recorder.cc b/content/common/tab_switch_time_recorder.cc index 1d051ca..9bac671 100644 --- a/content/common/tab_switch_time_recorder.cc +++ b/content/common/tab_switch_time_recorder.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/debug/dump_without_crashing.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/trace_event/trace_event.h" @@ -62,6 +63,17 @@ DCHECK(!tab_switch_start_state_); DCHECK(render_widget_visibility_request_timestamp_.is_null()); + if (tab_switch_start_state_) { + // TabWasShown() is called multiple times without the tab being hidden in + // between. This shouldn't happen per the DCHECK above. Dump without + // crashing to gather more information for https://crbug.com/981757. + // + // TODO(fdoray): This code should be removed no later than August 30, 2019. + // https://crbug.com/981757 + base::debug::DumpWithoutCrashing(); + weak_ptr_factory_.InvalidateWeakPtrs(); + } + has_saved_frames_ = has_saved_frames; tab_switch_start_state_ = start_state; render_widget_visibility_request_timestamp_ =
diff --git a/content/public/browser/native_file_system_permission_context.h b/content/public/browser/native_file_system_permission_context.h index f7af7aa..e1d4939 100644 --- a/content/public/browser/native_file_system_permission_context.h +++ b/content/public/browser/native_file_system_permission_context.h
@@ -29,6 +29,16 @@ const base::FilePath& path, bool is_directory) = 0; + // Displays a dialog to confirm that the user intended to give read access to + // a specific directory. + using PermissionStatus = blink::mojom::PermissionStatus; + virtual void ConfirmDirectoryReadAccess( + const url::Origin& origin, + const base::FilePath& path, + int process_id, + int frame_id, + base::OnceCallback<void(PermissionStatus)> callback) = 0; + protected: virtual ~NativeFileSystemPermissionContext() = default; };
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index b0f5041..bf36de8d 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -483,6 +483,10 @@ // directory handles. virtual bool HasNativeFileSystemDirectoryHandles() = 0; + // Returns the paths of all the native file system directory handles frames in + // this WebContents have access to. + virtual std::vector<base::FilePath> GetNativeFileSystemDirectoryHandles() = 0; + // Indicates whether any frame in the WebContents has writable native file // system handles. virtual bool HasWritableNativeFileSystemHandles() = 0;
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h index 8ef20bc..3e573cb8 100644 --- a/content/public/common/common_param_traits_macros.h +++ b/content/public/common/common_param_traits_macros.h
@@ -205,6 +205,9 @@ IPC_STRUCT_TRAITS_MEMBER(text_track_text_shadow) IPC_STRUCT_TRAITS_MEMBER(text_track_font_family) IPC_STRUCT_TRAITS_MEMBER(text_track_font_variant) + IPC_STRUCT_TRAITS_MEMBER(text_track_window_color) + IPC_STRUCT_TRAITS_MEMBER(text_track_window_padding) + IPC_STRUCT_TRAITS_MEMBER(text_track_window_radius) IPC_STRUCT_TRAITS_MEMBER(text_autosizing_enabled) IPC_STRUCT_TRAITS_MEMBER(double_tap_to_zoom_enabled) IPC_STRUCT_TRAITS_MEMBER(dont_send_key_events_to_javascript)
diff --git a/content/public/common/resource_type.h b/content/public/common/resource_type.h index 24084d75d..9d910c8 100644 --- a/content/public/common/resource_type.h +++ b/content/public/common/resource_type.h
@@ -11,26 +11,30 @@ // Used in histograms; explicitly assign each type and do not re-use old values. enum class ResourceType { - kMainFrame = 0, // top level page - kSubFrame = 1, // frame or iframe - kStylesheet = 2, // a CSS stylesheet - kScript = 3, // an external script - kImage = 4, // an image (jpg/gif/png/etc) - kFontResource = 5, // a font - kSubResource = 6, // an "other" subresource. - kObject = 7, // an object (or embed) tag for a plugin. - kMedia = 8, // a media resource. - kWorker = 9, // the main resource of a dedicated worker. - kSharedWorker = 10, // the main resource of a shared worker. - kPrefetch = 11, // an explicitly requested prefetch - kFavicon = 12, // a favicon - kXhr = 13, // a XMLHttpRequest - kPing = 14, // a ping request for <a ping>/sendBeacon. - kServiceWorker = 15, // the main resource of a service worker. - kCspReport = 16, // a report of Content Security Policy violations. - kPluginResource = 17, // a resource that a plugin requested. - kNavigationPreload = 18, // a service worker navigation preload request. - kMaxValue = kNavigationPreload, + kMainFrame = 0, // top level page + kSubFrame = 1, // frame or iframe + kStylesheet = 2, // a CSS stylesheet + kScript = 3, // an external script + kImage = 4, // an image (jpg/gif/png/etc) + kFontResource = 5, // a font + kSubResource = 6, // an "other" subresource. + kObject = 7, // an object (or embed) tag for a plugin. + kMedia = 8, // a media resource. + kWorker = 9, // the main resource of a dedicated worker. + kSharedWorker = 10, // the main resource of a shared worker. + kPrefetch = 11, // an explicitly requested prefetch + kFavicon = 12, // a favicon + kXhr = 13, // a XMLHttpRequest + kPing = 14, // a ping request for <a ping>/sendBeacon. + kServiceWorker = 15, // the main resource of a service worker. + kCspReport = 16, // a report of Content Security Policy violations. + kPluginResource = 17, // a resource that a plugin requested. + // kNavigationPreload = 18, // Deprecated. + // a main-frame service worker navigation preload request. + kNavigationPreloadMainFrame = 19, + // a sub-frame service worker navigation preload request. + kNavigationPreloadSubFrame = 20, + kMaxValue = kNavigationPreloadSubFrame, }; CONTENT_EXPORT bool IsResourceTypeFrame(ResourceType type);
diff --git a/content/public/common/resource_type.mojom b/content/public/common/resource_type.mojom index 6d3c442..9c9a48d 100644 --- a/content/public/common/resource_type.mojom +++ b/content/public/common/resource_type.mojom
@@ -24,5 +24,9 @@ kServiceWorker = 15, // the main resource of a service worker. kCspReport = 16, // a report of Content Security Policy violations. kPluginResource = 17, // a resource that a plugin requested. - kNavigationPreload = 18, // a service worker navigation preload request. + // kNavigationPreload = 18, // Deprecated. + // a main-frame service worker navigation preload request. + kNavigationPreloadMainFrame = 19, + // a sub-frame service worker navigation preload request. + kNavigationPreloadSubFrame = 20, };
diff --git a/content/public/common/resource_type_struct_traits.cc b/content/public/common/resource_type_struct_traits.cc index 239ba20..0bd5e23 100644 --- a/content/public/common/resource_type_struct_traits.cc +++ b/content/public/common/resource_type_struct_traits.cc
@@ -47,8 +47,10 @@ return content::mojom::ResourceType::kCspReport; case content::ResourceType::kPluginResource: return content::mojom::ResourceType::kPluginResource; - case content::ResourceType::kNavigationPreload: - return content::mojom::ResourceType::kNavigationPreload; + case content::ResourceType::kNavigationPreloadMainFrame: + return content::mojom::ResourceType::kNavigationPreloadMainFrame; + case content::ResourceType::kNavigationPreloadSubFrame: + return content::mojom::ResourceType::kNavigationPreloadSubFrame; } NOTREACHED(); @@ -114,8 +116,11 @@ case content::mojom::ResourceType::kPluginResource: *output = content::ResourceType::kPluginResource; return true; - case content::mojom::ResourceType::kNavigationPreload: - *output = content::ResourceType::kNavigationPreload; + case content::mojom::ResourceType::kNavigationPreloadMainFrame: + *output = content::ResourceType::kNavigationPreloadMainFrame; + return true; + case content::mojom::ResourceType::kNavigationPreloadSubFrame: + *output = content::ResourceType::kNavigationPreloadSubFrame; return true; } return false;
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h index 6677d8e..1198b65 100644 --- a/content/public/common/web_preferences.h +++ b/content/public/common/web_preferences.h
@@ -217,6 +217,15 @@ // Specifies the value for CSS font-variant property. std::string text_track_font_variant; + // These fields specify values for CSS properties used to style the window + // around WebVTT text tracks. + // Window color can be any legal CSS color descriptor. + std::string text_track_window_color; + // Window padding is in em. + std::string text_track_window_padding; + // Window radius is in pixels. + std::string text_track_window_radius; + // Specifies the margin for WebVTT text tracks as a percentage of media // element height/width (for horizontal/vertical text respectively). // Cues will not be placed in this margin area.
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index f93096e..f0427f28 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -409,8 +409,6 @@ "storage_util.h", "stream_texture_host_android.cc", "stream_texture_host_android.h", - "text_input_client_observer.cc", - "text_input_client_observer.h", "theme_helper_mac.h", "theme_helper_mac.mm", "top_level_blame_context.cc", @@ -656,6 +654,13 @@ ] } + if (is_mac) { + sources += [ + "text_input_client_observer.cc", + "text_input_client_observer.h", + ] + } + if (is_fuchsia) { sources += [ "render_view_fuchsia.cc",
diff --git a/content/renderer/media/android/OWNERS b/content/renderer/media/android/OWNERS deleted file mode 100644 index 5abf5a1..0000000 --- a/content/renderer/media/android/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -qinmin@chromium.org
diff --git a/content/renderer/media/stream/media_stream_audio_processor.cc b/content/renderer/media/stream/media_stream_audio_processor.cc index 437d207..57c858a9 100644 --- a/content/renderer/media/stream/media_stream_audio_processor.cc +++ b/content/renderer/media/stream/media_stream_audio_processor.cc
@@ -81,19 +81,6 @@ } } -// Used by UMA histograms and entries shouldn't be re-ordered or removed. -enum AudioTrackProcessingStates { - AUDIO_PROCESSING_ENABLED = 0, - AUDIO_PROCESSING_DISABLED, - AUDIO_PROCESSING_IN_WEBRTC, - AUDIO_PROCESSING_MAX -}; - -void RecordProcessingState(AudioTrackProcessingStates state) { - UMA_HISTOGRAM_ENUMERATION("Media.AudioTrackProcessingStates", - state, AUDIO_PROCESSING_MAX); -} - // Checks if the default minimum starting volume value for the AGC is overridden // on the command line. base::Optional<int> GetStartupMinVolumeForAgc() { @@ -547,7 +534,6 @@ // Sanity-check: WouldModifyAudio() should return true iff // |audio_mirroring_| is true. DCHECK_EQ(audio_mirroring_, WouldModifyAudio(properties)); - RecordProcessingState(AUDIO_PROCESSING_DISABLED); return; } @@ -639,8 +625,6 @@ } audio_processing_->ApplyConfig(apm_config); - - RecordProcessingState(AUDIO_PROCESSING_ENABLED); } void MediaStreamAudioProcessor::InitializeCaptureFifo(
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc index 0b4f4dc38..3a444f5 100644 --- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc +++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc
@@ -141,8 +141,7 @@ track_adapter_->webrtc_track()); } -// Flaky, see https://crbug.com/982200. -TEST_F(WebRtcMediaStreamTrackAdapterTest, DISABLED_LocalVideoTrack) { +TEST_F(WebRtcMediaStreamTrackAdapterTest, LocalVideoTrack) { track_adapter_ = WebRtcMediaStreamTrackAdapter::CreateLocalTrackAdapter( dependency_factory_.get(), main_thread_, CreateLocalVideoTrack()); EXPECT_TRUE(track_adapter_->is_initialized());
diff --git a/content/renderer/render_view_browsertest_mac.mm b/content/renderer/render_view_browsertest_mac.mm index 535c15a..d9b0e8f 100644 --- a/content/renderer/render_view_browsertest_mac.mm +++ b/content/renderer/render_view_browsertest_mac.mm
@@ -171,13 +171,13 @@ // RenderWidget which forwards them to the TextInputClientObserver using Range = gfx::Range; using Point = gfx::Point; - view->OnMessageReceived( + view->GetWidget()->OnMessageReceived( TextInputClientMsg_CharacterIndexForPoint(routing_id, Point())); - view->OnMessageReceived( + view->GetWidget()->OnMessageReceived( TextInputClientMsg_FirstRectForCharacterRange(routing_id, Range())); - view->OnMessageReceived( + view->GetWidget()->OnMessageReceived( TextInputClientMsg_StringForRange(routing_id, Range())); - view->OnMessageReceived( + view->GetWidget()->OnMessageReceived( TextInputClientMsg_CharacterIndexForPoint(routing_id, Point())); }
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 9e03aaf40..ed526425 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -812,6 +812,12 @@ settings->SetTextTrackFontVariant( WebString::FromASCII(prefs.text_track_font_variant)); settings->SetTextTrackMarginPercentage(prefs.text_track_margin_percentage); + settings->SetTextTrackWindowColor( + WebString::FromASCII(prefs.text_track_window_color)); + settings->SetTextTrackWindowPadding( + WebString::FromASCII(prefs.text_track_window_padding)); + settings->SetTextTrackWindowRadius( + WebString::FromASCII(prefs.text_track_window_radius)); // Needs to happen before SetDefaultPageScaleLimits below since that'll // recalculate the final page scale limits and that depends on this setting.
diff --git a/content/renderer/text_input_client_observer.cc b/content/renderer/text_input_client_observer.cc index 1cfa062..21c4924 100644 --- a/content/renderer/text_input_client_observer.cc +++ b/content/renderer/text_input_client_observer.cc
@@ -10,6 +10,7 @@ #include "build/build_config.h" #include "content/common/text_input_client_messages.h" +#include "content/public/renderer/render_thread.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_view_impl.h" @@ -39,8 +40,7 @@ TextInputClientObserver::TextInputClientObserver(RenderWidget* render_widget) : render_widget_(render_widget) {} -TextInputClientObserver::~TextInputClientObserver() { -} +TextInputClientObserver::~TextInputClientObserver() = default; bool TextInputClientObserver::OnMessageReceived(const IPC::Message& message) { bool handled = true; @@ -58,33 +58,39 @@ } bool TextInputClientObserver::Send(IPC::Message* message) { - return render_widget_->Send(message); + // This class is attached to the main frame RenderWidget, but sends and + // receives messages while the main frame is remote (and the RenderWidget is + // frozen). The messages are not received on RenderWidgetHostImpl, so there's + // no need to send through RenderWidget or use its routing id. We avoid this + // problem then by sending directly through RenderThread instead of through + // RenderWidget::Send(). + // TODO(crbug.com/669219): This class should not be used while the main frame + // is remote. + return RenderThread::Get()->Send(message); } blink::WebFrameWidget* TextInputClientObserver::GetWebFrameWidget() const { blink::WebWidget* widget = render_widget_->GetWebWidget(); - if (!widget->IsWebFrameWidget()) { - // When a page navigation occurs, for a brief period - // RenderViewImpl::GetWebWidget() will return a WebViewImpl instead of a - // WebViewFrameWidget. Therefore, casting to WebFrameWidget is invalid and - // could cause crashes. Also, WebView::mainFrame() could be a remote frame - // which will yield a nullptr for localRoot() (https://crbug.com/664890). + // While the main frame is remote, the WebWidget of the main frame's + // RenderWidget is not a WebFrameWidget. + // TODO(crbug.com/669219): The browser shouldn't be sending IPCs that land + // in this class when the main frame is remote. + // TODO(danakj): This should instead be checking: + // if (render_widget_->is_frozen()) + // But is_frozen() is currently true also for provisional frames, and in that + // case there is actually a WebFrameWidget to be used. In the future we should + // separate these states and then this can return null if frozen *and there is + // no provisional main frame attached to the RenderWidget*. + if (!widget->IsWebFrameWidget()) return nullptr; - } return static_cast<blink::WebFrameWidget*>(widget); } blink::WebLocalFrame* TextInputClientObserver::GetFocusedFrame() const { if (auto* frame_widget = GetWebFrameWidget()) { - blink::WebLocalFrame* localRoot = frame_widget->LocalRoot(); - RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(localRoot); - if (!render_frame) { - // TODO(ekaramad): Can this ever be nullptr? (https://crbug.com/664890). - return nullptr; - } - blink::WebLocalFrame* focused = - render_frame->render_view()->webview()->FocusedFrame(); - return focused->LocalRoot() == localRoot ? focused : nullptr; + blink::WebLocalFrame* local_root = frame_widget->LocalRoot(); + blink::WebLocalFrame* focused = local_root->View()->FocusedFrame(); + return focused->LocalRoot() == local_root ? focused : nullptr; } return nullptr; } @@ -92,28 +98,27 @@ #if BUILDFLAG(ENABLE_PLUGINS) PepperPluginInstanceImpl* TextInputClientObserver::GetFocusedPepperPlugin() const { - blink::WebLocalFrame* focusedFrame = GetFocusedFrame(); - return focusedFrame - ? RenderFrameImpl::FromWebFrame(focusedFrame) - ->focused_pepper_plugin() - : nullptr; + blink::WebLocalFrame* frame = GetFocusedFrame(); + if (!frame) + return nullptr; + return RenderFrameImpl::FromWebFrame(frame)->focused_pepper_plugin(); } #endif void TextInputClientObserver::OnStringAtPoint(gfx::Point point) { #if defined(OS_MACOSX) - blink::WebPoint baselinePoint; + blink::WebPoint baseline_point; NSAttributedString* string = nil; if (auto* frame_widget = GetWebFrameWidget()) { string = blink::WebSubstringUtil::AttributedWordAtPoint(frame_widget, point, - baselinePoint); + baseline_point); } std::unique_ptr<const mac::AttributedStringCoder::EncodedString> encoded( mac::AttributedStringCoder::Encode(string)); Send(new TextInputClientReplyMsg_GotStringAtPoint( - render_widget_->routing_id(), *encoded.get(), baselinePoint)); + MSG_ROUTING_NONE, *encoded.get(), baseline_point)); #else NOTIMPLEMENTED(); #endif @@ -125,8 +130,8 @@ if (auto* frame = GetFocusedFrame()) index = static_cast<uint32_t>(frame->CharacterIndexForPoint(web_point)); - Send(new TextInputClientReplyMsg_GotCharacterIndexForPoint( - render_widget_->routing_id(), index)); + Send(new TextInputClientReplyMsg_GotCharacterIndexForPoint(MSG_ROUTING_NONE, + index)); } void TextInputClientObserver::OnFirstRectForCharacterRange(gfx::Range range) { @@ -151,25 +156,25 @@ rect = web_rect; } } - Send(new TextInputClientReplyMsg_GotFirstRectForRange( - render_widget_->routing_id(), rect)); + Send( + new TextInputClientReplyMsg_GotFirstRectForRange(MSG_ROUTING_NONE, rect)); } void TextInputClientObserver::OnStringForRange(gfx::Range range) { #if defined(OS_MACOSX) - blink::WebPoint baselinePoint; + blink::WebPoint baseline_point; NSAttributedString* string = nil; blink::WebLocalFrame* frame = GetFocusedFrame(); // TODO(yabinh): Null check should not be necessary. // See crbug.com/304341 if (frame) { string = blink::WebSubstringUtil::AttributedSubstringInRange( - frame, range.start(), range.length(), &baselinePoint); + frame, range.start(), range.length(), &baseline_point); } std::unique_ptr<const mac::AttributedStringCoder::EncodedString> encoded( mac::AttributedStringCoder::Encode(string)); Send(new TextInputClientReplyMsg_GotStringForRange( - render_widget_->routing_id(), *encoded.get(), baselinePoint)); + MSG_ROUTING_NONE, *encoded.get(), baseline_point)); #else NOTIMPLEMENTED(); #endif
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 88ed64c..7a867e3 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -54,6 +54,8 @@ "../browser/media/session/mock_media_session_service_impl.h", "../browser/native_file_system/file_system_chooser_test_helpers.cc", "../browser/native_file_system/file_system_chooser_test_helpers.h", + "../browser/native_file_system/mock_native_file_system_permission_context.cc", + "../browser/native_file_system/mock_native_file_system_permission_context.h", "../browser/native_file_system/mock_native_file_system_permission_grant.cc", "../browser/native_file_system/mock_native_file_system_permission_grant.h", "../browser/renderer_host/input/mock_input_router.cc", @@ -983,7 +985,6 @@ "../browser/service_worker/service_worker_browsertest.cc", "../browser/service_worker/service_worker_clients_api_browsertest.cc", "../browser/service_worker/service_worker_file_upload_browsertest.cc", - "../browser/service_worker/service_worker_network_isolation_key_browsertest.cc", "../browser/service_worker/service_worker_no_best_effort_tasks_browsertest.cc", "../browser/session_history_browsertest.cc", "../browser/shape_detection/shape_detection_browsertest.cc", @@ -1036,6 +1037,7 @@ "../browser/webrtc/webrtc_webcam_browsertest.h", "../browser/webui/web_ui_mojo_browsertest.cc", "../browser/worker_host/worker_browsertest.cc", + "../browser/worker_network_isolation_key_browsertest.cc", "../renderer/accessibility/render_accessibility_impl_browsertest.cc", "../renderer/blink_platform_audio_hardware_browsertest.cc", "../renderer/gin_browsertest.cc",
diff --git a/content/test/data/accessibility/css/transform-expected-uia-win.txt b/content/test/data/accessibility/css/transform-expected-uia-win.txt new file mode 100644 index 0000000..22b62242 --- /dev/null +++ b/content/test/data/accessibility/css/transform-expected-uia-win.txt
@@ -0,0 +1,4 @@ +document +++group BoundingRectangle=(0, 50, 48, 18) +++++group BoundingRectangle=(0, 50, 48, 18) +++++++description BoundingRectangle=(0, 50, 48, 17) Name='content'
diff --git a/content/test/data/accessibility/css/transform-expected-win.txt b/content/test/data/accessibility/css/transform-expected-win.txt new file mode 100644 index 0000000..b270fecb --- /dev/null +++ b/content/test/data/accessibility/css/transform-expected-win.txt
@@ -0,0 +1,4 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0) +++IA2_ROLE_SECTION location=(0, 50) +++++IA2_ROLE_PARAGRAPH location=(0, 50) +++++++ROLE_SYSTEM_STATICTEXT name='content' location=(0, 50)
diff --git a/content/test/data/accessibility/css/transform.html b/content/test/data/accessibility/css/transform.html index 334f1f6..9c3a47a 100644 --- a/content/test/data/accessibility/css/transform.html +++ b/content/test/data/accessibility/css/transform.html
@@ -1,8 +1,12 @@ <!-- -@BLINK-ALLOW:pageLocation=(0, 0) -@BLINK-ALLOW:pageLocation=(0, 50) -@WAIT-FOR:(0, 50) +@BLINK-ALLOW:pageLocation=* +@WIN-ALLOW:location=* +@UIA-WIN-ALLOW:BoundingRectangle=(0, 50,* + +The closing parenthesis is intentionally omitted from WAIT-FOR because UIA +represents location as part of BoundingRectangle which has four coordinates. +@WAIT-FOR:(0, 50 --> <!DOCTYPE html> <html>
diff --git a/content/test/data/gpu/pixel_video_mp4.html b/content/test/data/gpu/pixel_video_mp4.html index fd842a2..574158f3 100644 --- a/content/test/data/gpu/pixel_video_mp4.html +++ b/content/test/data/gpu/pixel_video_mp4.html
@@ -8,6 +8,7 @@ <html> <head> +<meta name="viewport" content="initial-scale=1"> <title>MP4 Video test</title> <style type="text/css"> .nomargin {
diff --git a/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html b/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html index cc624f6..4cba526bb 100644 --- a/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html +++ b/content/test/data/gpu/pixel_video_mp4_four_colors_aspect_4x3.html
@@ -8,6 +8,7 @@ <html> <head> +<meta name="viewport" content="initial-scale=1"> <title>MP4 Video with Aspect 4x3 Test</title> <style type="text/css"> .nomargin {
diff --git a/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html b/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html index 37a0f97..eadd247 100644 --- a/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html +++ b/content/test/data/gpu/pixel_video_mp4_four_colors_rot_180.html
@@ -8,6 +8,7 @@ <html> <head> +<meta name="viewport" content="initial-scale=1"> <title>MP4 Video with 180 Degree Rotation Test</title> <style type="text/css"> .nomargin {
diff --git a/content/test/data/service_worker/empty2.html b/content/test/data/service_worker/empty2.html deleted file mode 100644 index e69de29..0000000 --- a/content/test/data/service_worker/empty2.html +++ /dev/null
diff --git a/content/test/data/service_worker/empty2.html.mock-http-headers b/content/test/data/workers/empty.html.mock-http-headers similarity index 100% rename from content/test/data/service_worker/empty2.html.mock-http-headers rename to content/test/data/workers/empty.html.mock-http-headers
diff --git a/content/test/data/service_worker/empty.js.mock-http-headers b/content/test/data/workers/empty.js.mock-http-headers similarity index 100% rename from content/test/data/service_worker/empty.js.mock-http-headers rename to content/test/data/workers/empty.js.mock-http-headers
diff --git a/content/test/data/service_worker/frame_factory.html b/content/test/data/workers/frame_factory.html similarity index 100% rename from content/test/data/service_worker/frame_factory.html rename to content/test/data/workers/frame_factory.html
diff --git a/content/test/data/workers/service_worker_setup.html b/content/test/data/workers/service_worker_setup.html index 5ead46f..bb334941 100644 --- a/content/test/data/workers/service_worker_setup.html +++ b/content/test/data/workers/service_worker_setup.html
@@ -2,8 +2,9 @@ <meta charset="utf-8"> <title>register a service worker</title> <script> -async function setup() { - await navigator.serviceWorker.register('service_worker.js'); +async function setup(script_file_arg) { + let script_file = script_file_arg || 'service_worker.js'; + await navigator.serviceWorker.register(script_file); await navigator.serviceWorker.ready; return 'ok'; }
diff --git a/content/test/data/service_worker/worker_with_import_and_fetch.js b/content/test/data/workers/worker_with_import_and_fetch.js similarity index 100% rename from content/test/data/service_worker/worker_with_import_and_fetch.js rename to content/test/data/workers/worker_with_import_and_fetch.js
diff --git a/content/test/data/service_worker/worker_with_import_and_fetch_2.js b/content/test/data/workers/worker_with_import_and_fetch_2.js similarity index 100% rename from content/test/data/service_worker/worker_with_import_and_fetch_2.js rename to content/test/data/workers/worker_with_import_and_fetch_2.js
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index d193d56..a847682 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -1,11 +1,11 @@ -# tags: [ android chromeos highsierra linux mac mojave win ] +# tags: [ android chromeos highsierra linux mac mojave win win7 ] # tags: [ android-chromium android-webview-instrumentation debug ] # tags: [ skia-renderer no-skia-renderer ] # tags: [ use-vulkan no-use-vulkan ] # tags: [ amd amd-0x6613 amd-0x679e amd-0x6821 intel intel-0xa2e intel-0x5912 -# nvidia nvidia-0xfe9 qualcomm-adreno-(tm)-330 qualcomm-adreno-(tm)-418 -# qualcomm-adreno-(tm)-420 qualcomm-adreno-(tm)-430 -# qualcomm-adreno-(tm)-540 +# nvidia nvidia-0xfe9 nvidia-0x1cb3 qualcomm-adreno-(tm)-330 +# qualcomm-adreno-(tm)-418 qualcomm-adreno-(tm)-420 +# qualcomm-adreno-(tm)-430 qualcomm-adreno-(tm)-540 # ] # results: [ Failure RetryOnFailure Skip ] @@ -151,9 +151,6 @@ crbug.com/927107 [ android ] Pixel_CSS3DBlueBox [ Failure ] # Fail on Nexus 5, 5X, 6, 6P, 9 and Shield TV. -crbug.com/925744 [ android ] Pixel_Video_MP4 [ Skip ] -crbug.com/925744 [ android ] Pixel_Video_MP4_FourColors_Aspect_4x3 [ Skip ] -crbug.com/925744 [ android ] Pixel_Video_MP4_FourColors_Rot_180 [ Skip ] crbug.com/925744 [ android ] Pixel_Video_MP4_FourColors_Rot_270 [ Skip ] crbug.com/925744 [ android ] Pixel_Video_MP4_FourColors_Rot_90 [ Skip ] crbug.com/925744 [ android ] Pixel_Video_VP9 [ Skip ] @@ -219,3 +216,14 @@ # Produces blank images on Intel HD 630 w/ Mesa 19.0.2 crbug.com/976861 [ linux intel-0x5912 ] Pixel_OffscreenCanvasTransferToImageBitmap [ Skip ] + +# For whatever reason, these configurations are more prone to running into the +# issue of producing valid images that haven't been seen for a long time, which +# hits a known issue with Gold. +crbug.com/983212 [ mac amd-0x679e ] Pixel_WebGLGreenTriangle_NonChromiumImage_AA_NoAlpha [ RetryOnFailure ] +crbug.com/983212 [ mac amd-0x679e ] Pixel_WebGLGreenTriangle_NonChromiumImage_NoAA_Alpha [ RetryOnFailure ] +crbug.com/983212 [ mac amd-0x679e ] Pixel_WebGLGreenTriangle_NonChromiumImage_NoAA_NoAlpha [ RetryOnFailure ] +crbug.com/983212 [ mac amd-0x679e ] Pixel_WebGLGreenTriangle_NonChromiumImage_AA_Alpha [ RetryOnFailure ] +crbug.com/983212 [ mac amd-0x679e ] Pixel_CSSFilterEffects_NoOverlays [ RetryOnFailure ] +crbug.com/983212 [ win7 amd-0x6613 ] Pixel_CSS3DBlueBox [ RetryOnFailure ] +crbug.com/983212 [ win7 nvidia-0x1cb3 ] Pixel_CSS3DBlueBox [ RetryOnFailure ]
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc index 320fd6c2..3c8a8158 100644 --- a/content/test/navigation_simulator_impl.cc +++ b/content/test/navigation_simulator_impl.cc
@@ -386,7 +386,7 @@ // has already been created. num_did_start_navigation_called_++; RegisterTestThrottle(handle); - PrepareCompleteCallbackOnHandle(handle); + PrepareCompleteCallbackOnRequest(); } void NavigationSimulatorImpl::RegisterTestThrottle(NavigationHandle* handle) { @@ -459,7 +459,7 @@ int previous_did_redirect_navigation_called = num_did_redirect_navigation_called_; - PrepareCompleteCallbackOnHandle(request_->navigation_handle()); + PrepareCompleteCallbackOnRequest(); NavigationRequest* request = frame_tree_node_->navigation_request(); CHECK(request) << "Trying to redirect a navigation that does not go to the " "network stack."; @@ -523,7 +523,7 @@ } } - PrepareCompleteCallbackOnHandle(request_->navigation_handle()); + PrepareCompleteCallbackOnRequest(); if (frame_tree_node_->navigation_request()) { static_cast<TestRenderFrameHost*>(frame_tree_node_->current_frame_host()) ->PrepareForCommitDeprecatedForNavigationSimulator( @@ -670,7 +670,7 @@ state_ = FAILED; - PrepareCompleteCallbackOnHandle(handle); + PrepareCompleteCallbackOnRequest(); CHECK(request_); TestNavigationURLLoader* url_loader = static_cast<TestNavigationURLLoader*>(request_->loader_for_testing()); @@ -980,7 +980,7 @@ // Add a throttle to count NavigationThrottle calls count. RegisterTestThrottle(handle); - PrepareCompleteCallbackOnHandle(handle); + PrepareCompleteCallbackOnRequest(); } void NavigationSimulatorImpl::DidRedirectNavigation( @@ -1166,10 +1166,9 @@ std::move(throttle_checks_complete_closure_).Run(); } -void NavigationSimulatorImpl::PrepareCompleteCallbackOnHandle( - NavigationHandleImpl* handle) { +void NavigationSimulatorImpl::PrepareCompleteCallbackOnRequest() { last_throttle_check_result_.reset(); - handle->set_complete_callback_for_testing( + request_->set_complete_callback_for_testing( base::BindOnce(&NavigationSimulatorImpl::OnThrottleChecksComplete, weak_factory_.GetWeakPtr())); }
diff --git a/content/test/navigation_simulator_impl.h b/content/test/navigation_simulator_impl.h index 6802ed4..4bade199 100644 --- a/content/test/navigation_simulator_impl.h +++ b/content/test/navigation_simulator_impl.h
@@ -209,8 +209,8 @@ void OnThrottleChecksComplete(NavigationThrottle::ThrottleCheckResult result); // Helper method to set the OnThrottleChecksComplete callback on the - // NavigationHandle. - void PrepareCompleteCallbackOnHandle(NavigationHandleImpl* handle); + // NavigationRequest. + void PrepareCompleteCallbackOnRequest(); // Check if the navigation corresponds to a same-document navigation. // Only use on renderer-initiated navigations.
diff --git a/device/udev_linux/udev_unittest.cc b/device/udev_linux/udev_unittest.cc index 244cd8e..80dd1c4 100644 --- a/device/udev_linux/udev_unittest.cc +++ b/device/udev_linux/udev_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "device/udev_linux/udev.h" +#include "device/udev_linux/udev_loader.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,4 +19,8 @@ ASSERT_EQ("E-MU Systems,Inc.", UdevDecodeString("E-MU\\x20Systems\\x2cInc.")); } +TEST(UdevTest, Loader) { + ASSERT_NE(nullptr, UdevLoader::Get()); +} + } // namespace device
diff --git a/device/vr/windows/compositor_base.cc b/device/vr/windows/compositor_base.cc index b2eafaf1..6eee1c3 100644 --- a/device/vr/windows/compositor_base.cc +++ b/device/vr/windows/compositor_base.cc
@@ -491,6 +491,9 @@ pending_frame_->frame_ready_time_ = base::TimeTicks::Now(); if (!SubmitCompositedFrame()) { ExitPresent(); + // ExitPresent() clears pending_frame_, so return here to avoid + // accessing it below. + return; } } }
diff --git a/docs/security/mojo.md b/docs/security/mojo.md index ead3ae9..ae7d84b9 100644 --- a/docs/security/mojo.md +++ b/docs/security/mojo.md
@@ -498,7 +498,7 @@ .AssignIfValid(&alloc_size)) { // Safe: avoids allocating with a bogus size that overflowed to a smaller than // expected value. - mojo::ReportBadMessge("Invalid allocation size"); + mojo::ReportBadMessage("Invalid allocation size"); } Element* array = CreateArray(alloc_size);
diff --git a/docs/speed/apk_size_regressions.md b/docs/speed/apk_size_regressions.md index 4b71107..cf0211b 100644 --- a/docs/speed/apk_size_regressions.md +++ b/docs/speed/apk_size_regressions.md
@@ -21,6 +21,8 @@ * Bisects [will not help you](https://bugs.chromium.org/p/chromium/issues/detail?id=678338). * For rolls, you can sometimes guess the commit(s) that caused the regression by looking at the `android-binary-size` trybot result for the roll commit. + * For V8 rolls, try checking the [V8 size graph](https://chromeperf.appspot.com/report?sid=59435a74c93b42599af4b02e2b3df765faef4685eb015f8aaaf2ecf7f4afb29c) + to see if any jumps correspond with a CL in the roll. * Otherwise, use [diagnose_bloat.py](https://chromium.googlesource.com/chromium/src/+/master/tools/binary_size/README.md#diagnose_bloat_py) in a [local Android checkout](https://chromium.googlesource.com/chromium/src/+/master/docs/android_build_instructions.md) to build all commits locally and find the culprit. @@ -42,7 +44,7 @@ * Check if the same increase happened in Monochrome.minimal.apks. * The goal is to ensure nothing creeps into webview unintentionally. - + ## Step 2: File Bug or Silence Alert * If the commit message's `Binary-Size:` footer clearly justifies the size @@ -60,7 +62,7 @@ > Commit: **abc123abc123abc123abc123abc123abc123abcd** > > Link to size graph: -> [https://chromeperf.appspot.com/report?sid=29a24f1d2b8b785551b26d945108889a5a5eed9a83848feb9f93ce8b58b1884d&num_points=10&rev=**$CRREV**](https://chromeperf.appspot.com/report?sid=29a24f1d2b8b785551b26d945108889a5a5eed9a83848feb9f93ce8b58b1884d&num_points=10&rev=480214)<br> +> [https://chromeperf.appspot.com/report?sid=6269078068c45a41e23f5ee257da65d3f02da342849cdf3bde6aed0d5c61e450&num_points=10&rev=**$CRREV**](https://chromeperf.appspot.com/report?sid=6269078068c45a41e23f5ee257da65d3f02da342849cdf3bde6aed0d5c61e450&num_points=10&rev=480214)<br> > Link to trybot result: > [https://ci.chromium.org/p/chromium/builders/luci.chromium.try/android-binary-size/**$TRYJOB_NUMBER**](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/android-binary-size/11111) > @@ -163,7 +165,7 @@ 3) Why your commit is "worth" the size increase. For new features, feel free to link to a design doc (which presumably includes the motivation for adding the feature). - + Close the bug as "Won't Fix". # For Binary Size Sheriffs @@ -180,6 +182,6 @@ * Check [alert page](https://chromeperf.appspot.com/alerts?sheriff=Binary%20Size%20Sheriff) regularly for new alerts. * Join [g/chrome-binary-size-alerts](https://goto.google.com/chrome-binary-size-alerts). * Deal with alerts as outlined above. - + ## Step 3: Ping / Clear out Old Regression Bugs * https://bugs.chromium.org/p/chromium/issues/list?can=2&q=label%3DPerformance-Size+type%3DBug-Regression+resource_sizes
diff --git a/extensions/browser/api/declarative_net_request/ruleset_matcher.cc b/extensions/browser/api/declarative_net_request/ruleset_matcher.cc index 780cae8..9c4d9de 100644 --- a/extensions/browser/api/declarative_net_request/ruleset_matcher.cc +++ b/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
@@ -37,9 +37,9 @@ switch (type) { case content::ResourceType::kPrefetch: case content::ResourceType::kSubResource: - case content::ResourceType::kNavigationPreload: return flat_rule::ElementType_OTHER; case content::ResourceType::kMainFrame: + case content::ResourceType::kNavigationPreloadMainFrame: return flat_rule::ElementType_MAIN_FRAME; case content::ResourceType::kCspReport: return flat_rule::ElementType_CSP_REPORT; @@ -59,6 +59,7 @@ case content::ResourceType::kXhr: return flat_rule::ElementType_XMLHTTPREQUEST; case content::ResourceType::kSubFrame: + case content::ResourceType::kNavigationPreloadSubFrame: return flat_rule::ElementType_SUBDOCUMENT; case content::ResourceType::kPing: return flat_rule::ElementType_PING;
diff --git a/extensions/browser/api/web_request/web_request_permissions.cc b/extensions/browser/api/web_request/web_request_permissions.cc index afcbdacb..f58f049 100644 --- a/extensions/browser/api/web_request/web_request_permissions.cc +++ b/extensions/browser/api/web_request/web_request_permissions.cc
@@ -249,14 +249,13 @@ if (is_request_from_browser) { // Hide all non-navigation requests made by the browser. crbug.com/884932. - if (!request.is_navigation_request && - request.type != content::ResourceType::kNavigationPreload) { + if (!request.is_navigation_request) return true; - } DCHECK(request.type == content::ResourceType::kMainFrame || request.type == content::ResourceType::kSubFrame || - request.type == content::ResourceType::kNavigationPreload); + request.type == content::ResourceType::kNavigationPreloadMainFrame || + request.type == content::ResourceType::kNavigationPreloadSubFrame); // Hide sub-frame requests to clientsX.google.com. // TODO(crbug.com/890006): Determine if the code here can be cleaned up
diff --git a/extensions/browser/api/web_request/web_request_resource_type.cc b/extensions/browser/api/web_request/web_request_resource_type.cc index 8a59ef2..d96632f 100644 --- a/extensions/browser/api/web_request/web_request_resource_type.cc +++ b/extensions/browser/api/web_request/web_request_resource_type.cc
@@ -44,8 +44,10 @@ WebRequestResourceType ToWebRequestResourceType(content::ResourceType type) { switch (type) { case content::ResourceType::kMainFrame: + case content::ResourceType::kNavigationPreloadMainFrame: return WebRequestResourceType::MAIN_FRAME; case content::ResourceType::kSubFrame: + case content::ResourceType::kNavigationPreloadSubFrame: return WebRequestResourceType::SUB_FRAME; case content::ResourceType::kStylesheet: return WebRequestResourceType::STYLESHEET; @@ -78,8 +80,6 @@ return WebRequestResourceType::CSP_REPORT; case content::ResourceType::kPluginResource: return WebRequestResourceType::OBJECT; - case content::ResourceType::kNavigationPreload: - return WebRequestResourceType::OTHER; } NOTREACHED(); return WebRequestResourceType::OTHER;
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 2d9b502..16a1a00 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -1167,13 +1167,6 @@ std::move(withheld)); UpdateOriginPermissions(*extension); - if (params.uses_default_policy_host_restrictions) { - extension->permissions_data()->SetUsesDefaultHostRestrictions(); - } else { - extension->permissions_data()->SetPolicyHostRestrictions( - params.policy_blocked_hosts, params.policy_allowed_hosts); - } - bindings_system_->OnExtensionPermissionsUpdated(params.extension_id); UpdateBindings(extension->id()); }
diff --git a/google_apis/gaia/oauth2_token_service_delegate.h b/google_apis/gaia/oauth2_token_service_delegate.h index 76fffa21..5f56ff2 100644 --- a/google_apis/gaia/oauth2_token_service_delegate.h +++ b/google_apis/gaia/oauth2_token_service_delegate.h
@@ -132,14 +132,18 @@ virtual bool FixRequestErrorIfPossible(); #if defined(OS_IOS) - // Triggers platform specific implementation for IOS to add a given account + // Triggers platform specific implementation for iOS to reload all accounts + // from system. + virtual void ReloadAllAccountsFromSystem() {} + + // Triggers platform specific implementation for iOS to add a given account // to the token service from a system account. - virtual void AddAccountFromSystem(const CoreAccountId& account_id) {} + virtual void ReloadAccountFromSystem(const CoreAccountId& account_id) {} #endif -#if defined(OS_ANDROID) || defined(OS_IOS) - // Triggers platform specific implementation for Android and IOS to reload - // accounts from system. +#if defined(OS_ANDROID) + // Triggers platform specific implementation for Android to reload accounts + // from system. virtual void ReloadAccountsFromSystem( const CoreAccountId& primary_account_id) {} #endif
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory.cc b/gpu/ipc/service/gpu_memory_buffer_factory.cc index 46f0560e..edec577 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory.cc +++ b/gpu/ipc/service/gpu_memory_buffer_factory.cc
@@ -44,4 +44,18 @@ #endif } +void GpuMemoryBufferFactory::CreateGpuMemoryBufferAsync( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + int client_id, + SurfaceHandle surface_handle, + CreateGpuMemoryBufferAsyncCallback callback) { + // By default, we assume it's ok to allocate GMBs synchronously on the IO + // thread. However, subclasses can override this assumption. + std::move(callback).Run(CreateGpuMemoryBuffer(id, size, format, usage, + client_id, surface_handle)); +} + } // namespace gpu
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory.h b/gpu/ipc/service/gpu_memory_buffer_factory.h index e603ff8..029ffb0 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory.h +++ b/gpu/ipc/service/gpu_memory_buffer_factory.h
@@ -33,7 +33,9 @@ viz::VulkanContextProvider* vulkan_context_provider); // Creates a new GPU memory buffer instance. A valid handle is returned on - // success. It can be called on any thread. + // success. This method is thread-safe but it should not be called on the IO + // thread as it can lead to deadlocks (see https://crbug.com/981721). Instead + // use the asynchronous version on the IO thread. virtual gfx::GpuMemoryBufferHandle CreateGpuMemoryBuffer( gfx::GpuMemoryBufferId id, const gfx::Size& size, @@ -42,6 +44,20 @@ int client_id, SurfaceHandle surface_handle) = 0; + // Same as above, but returns the result asynchrounously. Safe to use on the + // IO thread. |callback| will be called on the same thread that calls this + // method, and it might be called on the same call stack. + using CreateGpuMemoryBufferAsyncCallback = + base::OnceCallback<void(gfx::GpuMemoryBufferHandle)>; + virtual void CreateGpuMemoryBufferAsync( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + int client_id, + SurfaceHandle surface_handle, + CreateGpuMemoryBufferAsyncCallback callback); + // Destroys GPU memory buffer identified by |id|. It can be called on any // thread. virtual void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc index 70fb765..a86ac9a3 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc +++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
@@ -23,7 +23,7 @@ namespace gpu { GpuMemoryBufferFactoryNativePixmap::GpuMemoryBufferFactoryNativePixmap() - : vulkan_context_provider_(nullptr) {} + : GpuMemoryBufferFactoryNativePixmap(nullptr) {} GpuMemoryBufferFactoryNativePixmap::GpuMemoryBufferFactoryNativePixmap( viz::VulkanContextProvider* vulkan_context_provider) @@ -46,33 +46,37 @@ ->GetSurfaceFactoryOzone() ->CreateNativePixmap(surface_handle, GetVulkanDevice(), size, format, usage); - if (!pixmap.get()) { - DLOG(ERROR) << "Failed to create pixmap " << size.ToString() << ", " - << gfx::BufferFormatToString(format) << ", usage " - << static_cast<int>(usage); - return gfx::GpuMemoryBufferHandle(); - } - - gfx::GpuMemoryBufferHandle new_handle; - new_handle.type = gfx::NATIVE_PIXMAP; - new_handle.id = id; - new_handle.native_pixmap_handle = pixmap->ExportHandle(); - - // TODO(reveman): Remove this once crbug.com/628334 has been fixed. - { - base::AutoLock lock(native_pixmaps_lock_); - NativePixmapMapKey key(id.id, client_id); - DCHECK(native_pixmaps_.find(key) == native_pixmaps_.end()); - native_pixmaps_[key] = pixmap; - } - - return new_handle; + return CreateGpuMemoryBufferFromNativePixmap(id, size, format, usage, + client_id, std::move(pixmap)); #else NOTIMPLEMENTED(); return gfx::GpuMemoryBufferHandle(); #endif } +void GpuMemoryBufferFactoryNativePixmap::CreateGpuMemoryBufferAsync( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + int client_id, + SurfaceHandle surface_handle, + CreateGpuMemoryBufferAsyncCallback callback) { +#if defined(USE_OZONE) + ui::OzonePlatform::GetInstance() + ->GetSurfaceFactoryOzone() + ->CreateNativePixmapAsync( + surface_handle, GetVulkanDevice(), size, format, usage, + base::BindOnce( + &GpuMemoryBufferFactoryNativePixmap::OnNativePixmapCreated, id, + size, format, usage, client_id, std::move(callback), + weak_factory_.GetWeakPtr())); +#else + NOTIMPLEMENTED(); + std::move(callback).Run(gfx::GpuMemoryBufferHandle()); +#endif +} + void GpuMemoryBufferFactoryNativePixmap::DestroyGpuMemoryBuffer( gfx::GpuMemoryBufferId id, int client_id) { @@ -183,4 +187,53 @@ : VK_NULL_HANDLE; } +// static +void GpuMemoryBufferFactoryNativePixmap::OnNativePixmapCreated( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + int client_id, + CreateGpuMemoryBufferAsyncCallback callback, + base::WeakPtr<GpuMemoryBufferFactoryNativePixmap> weak_ptr, + scoped_refptr<gfx::NativePixmap> pixmap) { + if (weak_ptr) { + std::move(callback).Run(weak_ptr->CreateGpuMemoryBufferFromNativePixmap( + id, size, format, usage, client_id, pixmap)); + } else { + std::move(callback).Run(gfx::GpuMemoryBufferHandle()); + } +} + +gfx::GpuMemoryBufferHandle +GpuMemoryBufferFactoryNativePixmap::CreateGpuMemoryBufferFromNativePixmap( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + int client_id, + scoped_refptr<gfx::NativePixmap> pixmap) { + if (!pixmap.get()) { + DLOG(ERROR) << "Failed to create pixmap " << size.ToString() << ", " + << gfx::BufferFormatToString(format) << ", usage " + << static_cast<int>(usage); + return gfx::GpuMemoryBufferHandle(); + } + + gfx::GpuMemoryBufferHandle new_handle; + new_handle.type = gfx::NATIVE_PIXMAP; + new_handle.id = id; + new_handle.native_pixmap_handle = pixmap->ExportHandle(); + + // TODO(reveman): Remove this once crbug.com/628334 has been fixed. + { + base::AutoLock lock(native_pixmaps_lock_); + NativePixmapMapKey key(id.id, client_id); + DCHECK(native_pixmaps_.find(key) == native_pixmaps_.end()); + native_pixmaps_[key] = pixmap; + } + + return new_handle; +} + } // namespace gpu
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h index b3692aed..10aed05 100644 --- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h +++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
@@ -41,6 +41,14 @@ gfx::BufferUsage usage, int client_id, SurfaceHandle surface_handle) override; + void CreateGpuMemoryBufferAsync( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + int client_id, + SurfaceHandle surface_handle, + CreateGpuMemoryBufferAsyncCallback callback) override; void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, int client_id) override; ImageFactory* AsImageFactory() override; @@ -66,6 +74,24 @@ scoped_refptr<gfx::NativePixmap>, NativePixmapMapKeyHash>; + static void OnNativePixmapCreated( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + int client_id, + CreateGpuMemoryBufferAsyncCallback callback, + base::WeakPtr<GpuMemoryBufferFactoryNativePixmap> weak_ptr, + scoped_refptr<gfx::NativePixmap> pixmap); + + gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromNativePixmap( + gfx::GpuMemoryBufferId id, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + int client_id, + scoped_refptr<gfx::NativePixmap> pixmap); + VkDevice GetVulkanDevice(); scoped_refptr<viz::VulkanContextProvider> vulkan_context_provider_; @@ -73,6 +99,8 @@ NativePixmapMap native_pixmaps_; base::Lock native_pixmaps_lock_; + base::WeakPtrFactory<GpuMemoryBufferFactoryNativePixmap> weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryNativePixmap); };
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg index 87e1800..09ae1be3 100644 --- a/infra/config/cr-buildbucket.cfg +++ b/infra/config/cr-buildbucket.cfg
@@ -2308,11 +2308,9 @@ name: "GPU FYI Win x64 dEQP Builder" mixins: "win-gpu-fyi-ci" } - # Can't use builderless "win-gpu-fyi-ci" for perf bulder. crbug.com/977735 builders { name: "GPU FYI XR Win Builder" - mixins: "win" - mixins: "gpu-fyi-ci" + mixins: "win-gpu-fyi-ci" } builders { name: "Win10 FYI Debug (NVIDIA)" @@ -4408,6 +4406,10 @@ builders { mixins: "win-optional-gpu-try" + name: "gpu-fyi-try-win-xr-builder" + } + builders { + mixins: "win-optional-gpu-try" name: "gpu-fyi-try-win7-amd-dbg" } builders {
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg index e43da2d..8eadd0a 100644 --- a/infra/config/luci-milo.cfg +++ b/infra/config/luci-milo.cfg
@@ -3114,7 +3114,6 @@ category: "Linux" } builders { - name: "buildbot/chromium.gpu/Android Release (Nexus 5X)" name: "buildbucket/luci.chromium.ci/Android Release (Nexus 5X)" category: "Android" } @@ -4450,6 +4449,9 @@ refs: "refs/heads/master" manifest_name: "REVISION" builders { + name: "buildbucket/luci.chromium.try/gpu-fyi-try-win-xr-builder" + } + builders { name: "buildbucket/luci.chromium.try/gpu-fyi-try-win7-amd-dbg" } builders { @@ -4788,6 +4790,9 @@ name: "buildbucket/luci.chromium.try/gpu-fyi-try-linux-nvidia-tsn" } builders { + name: "buildbucket/luci.chromium.try/gpu-fyi-try-win-xr-builder" + } + builders { name: "buildbucket/luci.chromium.try/gpu-fyi-try-win7-amd-dbg" } builders {
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_finder.h b/ios/chrome/browser/payments/ios_payment_instrument_finder.h index d90170f..fc5bfa7 100644 --- a/ios/chrome/browser/payments/ios_payment_instrument_finder.h +++ b/ios/chrome/browser/payments/ios_payment_instrument_finder.h
@@ -108,7 +108,8 @@ // this manifest. void OnPaymentManifestDownloaded(const GURL& method, const GURL& method_url_after_redirects, - const std::string& content); + const std::string& content, + const std::string& error_message); // Parses a payment method manifest for its default applications and gets all // the valid ones. |input| is the json encoded payment method manifest to @@ -127,7 +128,8 @@ const GURL& method, const GURL& web_app_manifest_url, const GURL& web_app_manifest_url_after_redirects, - const std::string& content); + const std::string& content, + const std::string& error_message); // Parses a web app manifest for its name, icon, and universal link. |input| // is the json encoded web app manifest to parse. |web_app_manifest_url|
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_finder.mm b/ios/chrome/browser/payments/ios_payment_instrument_finder.mm index c45cd80..53f50ec 100644 --- a/ios/chrome/browser/payments/ios_payment_instrument_finder.mm +++ b/ios/chrome/browser/payments/ios_payment_instrument_finder.mm
@@ -126,7 +126,8 @@ void IOSPaymentInstrumentFinder::OnPaymentManifestDownloaded( const GURL& method, const GURL& method_url_after_redirects, - const std::string& content) { + const std::string& content, + const std::string& error_message) { // If |content| is empty then the download failed. if (content.empty()) { OnPaymentInstrumentProcessed(); @@ -212,7 +213,8 @@ const GURL& method, const GURL& web_app_manifest_url, const GURL& web_app_manifest_url_after_redirects, - const std::string& content) { + const std::string& content, + const std::string& error_message) { // If |content| is empty then the download failed. if (content.empty()) { OnPaymentInstrumentProcessed();
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_finder_unittest.mm b/ios/chrome/browser/payments/ios_payment_instrument_finder_unittest.mm index 743ef823..36905ede 100644 --- a/ios/chrome/browser/payments/ios_payment_instrument_finder_unittest.mm +++ b/ios/chrome/browser/payments/ios_payment_instrument_finder_unittest.mm
@@ -142,7 +142,8 @@ ios_payment_instrument_finder_->num_instruments_to_find_ = 1; GURL web_app_manifest_url("https://bobpay.xyz/bob/manifest.json"); ios_payment_instrument_finder_->OnWebAppManifestDownloaded( - method, web_app_manifest_url, web_app_manifest_url, content); + method, web_app_manifest_url, web_app_manifest_url, content, + /*error_message=*/""); } void RunLoop() {
diff --git a/ios/chrome/browser/signin/authentication_service.h b/ios/chrome/browser/signin/authentication_service.h index 695d3b774..45393ef 100644 --- a/ios/chrome/browser/signin/authentication_service.h +++ b/ios/chrome/browser/signin/authentication_service.h
@@ -86,11 +86,13 @@ virtual ChromeIdentity* GetAuthenticatedIdentity() const; // Signs |identity| in to Chrome with |hosted_domain| as its hosted domain, - // pauses sync and logs |identity| in to http://google.com. If |identity| has - // no hosted domain, |hosted_domain| should be empty. + // pauses sync and logs |identity| in to http://google.com. // Virtual for testing. - virtual void SignIn(ChromeIdentity* identity, - const std::string& hosted_domain); + virtual void SignIn(ChromeIdentity* identity); + + // Old and deprecated override of SignIn(ChromeIdentity* identity). Will be + // removed once all downstream code has been converted to use the new method. + void SignIn(ChromeIdentity* identity, const std::string&); // Signs the authenticated user out of Chrome. // Virtual for testing.
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm index 3a7a83f..59fb44b 100644 --- a/ios/chrome/browser/signin/authentication_service.mm +++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -292,9 +292,7 @@ ->GetIdentityWithGaiaID(authenticated_gaia_id); } -void AuthenticationService::SignIn(ChromeIdentity* identity, - const std::string& hosted_domain) { - DCHECK(!hosted_domain.empty()); +void AuthenticationService::SignIn(ChromeIdentity* identity) { DCHECK(ios::GetChromeBrowserProvider() ->GetChromeIdentityService() ->IsValidIdentity(identity)); @@ -312,12 +310,13 @@ ->ReloadAllAccountsFromSystem(); // Ensure that the account the user is trying to sign into has been loaded - // from the SSO library and that hosted_domain is set to the provided value. + // from the SSO library and that hosted_domain is set (should be the proper + // hosted domain or kNoHostedDomainFound that are both non-empty strings). const base::Optional<AccountInfo> account_info = identity_manager_->FindAccountInfoForAccountWithRefreshTokenByAccountId( account_id); CHECK(account_info.has_value()); - CHECK_EQ(hosted_domain, account_info->hosted_domain); + CHECK(!account_info->hosted_domain.empty()); // |PrimaryAccountManager::SetAuthenticatedAccountId| simply ignores the call // if there is already a signed in user. Check that there is no signed in @@ -345,6 +344,11 @@ breakpad_helper::SetCurrentlySignedIn(true); } +void AuthenticationService::SignIn(ChromeIdentity* identity, + const std::string&) { + SignIn(identity); +} + void AuthenticationService::SignOut( signin_metrics::ProfileSignout signout_source, ProceduralBlock completion) {
diff --git a/ios/chrome/browser/signin/authentication_service_fake.h b/ios/chrome/browser/signin/authentication_service_fake.h index 9361ac0..73247a0 100644 --- a/ios/chrome/browser/signin/authentication_service_fake.h +++ b/ios/chrome/browser/signin/authentication_service_fake.h
@@ -26,8 +26,7 @@ ~AuthenticationServiceFake() override; - void SignIn(ChromeIdentity* identity, - const std::string& hosted_domain) override; + void SignIn(ChromeIdentity* identity) override; void SignOut(signin_metrics::ProfileSignout signout_source, ProceduralBlock completion) override;
diff --git a/ios/chrome/browser/signin/authentication_service_fake.mm b/ios/chrome/browser/signin/authentication_service_fake.mm index 8265a46c..58ee9b3 100644 --- a/ios/chrome/browser/signin/authentication_service_fake.mm +++ b/ios/chrome/browser/signin/authentication_service_fake.mm
@@ -33,8 +33,7 @@ AuthenticationServiceFake::~AuthenticationServiceFake() {} -void AuthenticationServiceFake::SignIn(ChromeIdentity* identity, - const std::string& hosted_domain) { +void AuthenticationServiceFake::SignIn(ChromeIdentity* identity) { // Needs to call PrepareForFirstSyncSetup to behave like // AuthenticationService. sync_setup_service_->PrepareForFirstSyncSetup();
diff --git a/ios/chrome/browser/signin/authentication_service_unittest.mm b/ios/chrome/browser/signin/authentication_service_unittest.mm index 066b7956..5b768f1 100644 --- a/ios/chrome/browser/signin/authentication_service_unittest.mm +++ b/ios/chrome/browser/signin/authentication_service_unittest.mm
@@ -237,7 +237,7 @@ TEST_F(AuthenticationServiceTest, TestSignInAndGetAuthenticatedIdentity) { // Sign in. SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); EXPECT_NSEQ(identity(0), authentication_service()->GetAuthenticatedIdentity()); @@ -273,7 +273,7 @@ // Sign in. SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); EXPECT_CALL(*sync_setup_service_mock(), HasFinishedInitialSetup()) .WillOnce(Return(true)); @@ -293,7 +293,7 @@ // Sign in. SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); EXPECT_CALL(*sync_setup_service_mock(), HasFinishedInitialSetup()) .WillOnce(Invoke( @@ -317,7 +317,7 @@ // Sign in. SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); EXPECT_CALL(*sync_setup_service_mock(), HasFinishedInitialSetup()) .WillOnce(Return(false)); @@ -332,7 +332,7 @@ TEST_F(AuthenticationServiceTest, TestHandleForgottenIdentityNoPromptSignIn) { // Sign in. SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); // Set the authentication service as "In Foreground", remove identity and run // the loop. @@ -351,7 +351,7 @@ TEST_F(AuthenticationServiceTest, TestHandleForgottenIdentityPromptSignIn) { // Sign in. SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); // Set the authentication service as "In Background", remove identity and run // the loop. @@ -373,7 +373,7 @@ // Sign in. SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); // Store the accounts and get them back from the prefs. They should be the // same as the token service accounts. @@ -401,7 +401,7 @@ OnApplicationEnterForegroundReloadCredentials) { // Sign in. SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); identity_service()->AddIdentities(@[ @"foo3" ]); @@ -463,7 +463,7 @@ TEST_F(AuthenticationServiceTest, HaveAccountsNotChanged) { SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); identity_service()->AddIdentities(@[ @"foo3" ]); FireIdentityListChanged(); @@ -478,7 +478,7 @@ TEST_F(AuthenticationServiceTest, HaveAccountsChanged) { SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); identity_service()->AddIdentities(@[ @"foo3" ]); FireIdentityListChanged(); @@ -495,7 +495,7 @@ TEST_F(AuthenticationServiceTest, HaveAccountsChangedBackground) { SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); identity_service()->AddIdentities(@[ @"foo3" ]); FireIdentityListChanged(); @@ -513,7 +513,7 @@ TEST_F(AuthenticationServiceTest, IsAuthenticatedBackground) { // Sign in. SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); EXPECT_TRUE(authentication_service()->IsAuthenticated()); // Remove the signed in identity while in background, and check that @@ -542,7 +542,7 @@ // Sign in user emails as account ids. SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); std::vector<std::string> accounts_in_prefs = GetAccountsInPrefs(); ASSERT_EQ(2U, accounts_in_prefs.size()); EXPECT_EQ("foo2@foo.com", accounts_in_prefs[0]); @@ -582,7 +582,7 @@ TestIdentityManagerObserver observer(identity_manager()); SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); EXPECT_EQ(2, observer.refresh_token_available_count()); NSDictionary* user_info = [NSDictionary dictionary]; @@ -611,7 +611,7 @@ TestIdentityManagerObserver observer(identity_manager()); SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); NSDictionary* user_info = [NSDictionary dictionary]; SetCachedMDMInfo(identity(0), user_info); @@ -628,7 +628,7 @@ // to MDM service when necessary. TEST_F(AuthenticationServiceTest, HandleMDMNotification) { SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); GoogleServiceAuthError error( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); identity::UpdatePersistentErrorOfRefreshTokenForAccount( @@ -664,7 +664,7 @@ // the primary account is blocked. TEST_F(AuthenticationServiceTest, HandleMDMBlockedNotification) { SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); GoogleServiceAuthError error( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); identity::UpdatePersistentErrorOfRefreshTokenForAccount( @@ -722,7 +722,7 @@ // corresponding error for the account. TEST_F(AuthenticationServiceTest, ShowMDMErrorDialog) { SetExpectationsForSignIn(); - authentication_service()->SignIn(identity(0), kNoHostedDomainFound); + authentication_service()->SignIn(identity(0)); GoogleServiceAuthError error( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); identity::UpdatePersistentErrorOfRefreshTokenForAccount(
diff --git a/ios/chrome/browser/ui/activity_services/activity_service_controller_unittest.mm b/ios/chrome/browser/ui/activity_services/activity_service_controller_unittest.mm index 6b7664a..dfcd836 100644 --- a/ios/chrome/browser/ui/activity_services/activity_service_controller_unittest.mm +++ b/ios/chrome/browser/ui/activity_services/activity_service_controller_unittest.mm
@@ -34,6 +34,7 @@ #include "ios/chrome/browser/ui/util/ui_util.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h" +#import "ios/web/public/test/fakes/test_web_state.h" #include "ios/web/public/test/test_web_thread_bundle.h" #include "testing/gtest_mac.h" #include "testing/platform_test.h" @@ -192,6 +193,13 @@ [[UIViewController alloc] initWithNibName:nil bundle:nil]; [[UIApplication sharedApplication] keyWindow].rootViewController = parentController_; + // Setting the |test_web_state_| to incognito to avoid using the snapshot + // genrator to create a thumbnail via the |thumbnail_generator_|. + test_web_state_.SetBrowserState( + chrome_browser_state_->GetOffTheRecordChromeBrowserState()); + thumbnail_generator_ = [[ChromeActivityItemThumbnailGenerator alloc] + initWithWebState:&test_web_state_]; + shareData_ = [[ShareToData alloc] initWithShareURL:GURL("https://chromium.org") visibleURL:GURL("https://chromium.org") @@ -200,7 +208,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::MOBILE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; } void TearDown() override { @@ -208,10 +216,6 @@ PlatformTest::TearDown(); } - ThumbnailGeneratorBlock DummyThumbnailGeneratorBlock() { - return ^UIImage*(CGSize const& size) { return nil; }; - } - BOOL ArrayContainsImageSource(NSArray* array) { for (NSObject* item in array) { if ([item class] == [UIActivityImageSource class]) { @@ -319,6 +323,8 @@ ShareToData* shareData_; std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; bookmarks::BookmarkModel* bookmark_model_; + ChromeActivityItemThumbnailGenerator* thumbnail_generator_; + web::TestWebState test_web_state_; }; TEST_F(ActivityServiceControllerTest, PresentAndDismissController) { @@ -364,7 +370,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::DESKTOP - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; NSArray* items = [activityController activityItemsForData:data]; NSString* findLoginAction = (NSString*)activity_services::kUTTypeAppExtensionFindLoginAction; @@ -428,7 +434,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::DESKTOP - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; NSArray* items = [activityController activityItemsForData:data]; NSString* shareAction = @"com.apple.UIKit.activity.PostToFacebook"; NSArray* urlItems = @@ -532,7 +538,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::NONE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; NSArray* items = [activityController applicationActivitiesForData:data @@ -551,7 +557,7 @@ isPagePrintable:NO isPageSearchable:YES userAgent:web::UserAgentType::NONE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; items = [activityController applicationActivitiesForData:data dispatcher:nil bookmarkModel:bookmark_model_ @@ -575,7 +581,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::MOBILE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; NSArray* items = [activityController applicationActivitiesForData:data @@ -592,7 +598,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::MOBILE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; items = [activityController applicationActivitiesForData:data dispatcher:nil bookmarkModel:bookmark_model_ @@ -614,7 +620,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::NONE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; NSArray* items = [activityController applicationActivitiesForData:data @@ -642,7 +648,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::NONE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; items = [activityController applicationActivitiesForData:data dispatcher:nil bookmarkModel:bookmark_model_ @@ -672,7 +678,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::MOBILE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; id mockDispatcher = OCMProtocolMock(@protocol(BrowserCommands)); OCMExpect([mockDispatcher requestDesktopSite]); NSArray* items = @@ -698,7 +704,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::DESKTOP - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; mockDispatcher = OCMProtocolMock(@protocol(BrowserCommands)); OCMExpect([mockDispatcher requestMobileSite]); items = [activityController applicationActivitiesForData:data @@ -816,7 +822,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::NONE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; NSArray* items = [activityController applicationActivitiesForData:data @@ -835,7 +841,7 @@ isPagePrintable:YES isPageSearchable:NO userAgent:web::UserAgentType::NONE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; items = [activityController applicationActivitiesForData:data dispatcher:nil bookmarkModel:bookmark_model_ @@ -859,7 +865,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::NONE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; NSArray* items = [activityController applicationActivitiesForData:data @@ -882,7 +888,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::NONE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; items = [activityController applicationActivitiesForData:data dispatcher:nil @@ -900,7 +906,7 @@ isPagePrintable:YES isPageSearchable:YES userAgent:web::UserAgentType::NONE - thumbnailGenerator:DummyThumbnailGeneratorBlock()]; + thumbnailGenerator:thumbnail_generator_]; items = [activityController applicationActivitiesForData:data dispatcher:nil bookmarkModel:bookmark_model_
diff --git a/ios/chrome/browser/ui/activity_services/chrome_activity_item_source.h b/ios/chrome/browser/ui/activity_services/chrome_activity_item_source.h index e6aa5ab..f90c723 100644 --- a/ios/chrome/browser/ui/activity_services/chrome_activity_item_source.h +++ b/ios/chrome/browser/ui/activity_services/chrome_activity_item_source.h
@@ -33,7 +33,8 @@ - (instancetype)initWithShareURL:(NSURL*)shareURL passwordManagerURL:(NSURL*)passwordManagerURL subject:(NSString*)subject - thumbnailGenerator:(ThumbnailGeneratorBlock)thumbnailGenerator; + thumbnailGenerator: + (ChromeActivityItemThumbnailGenerator*)thumbnailGenerator; @end
diff --git a/ios/chrome/browser/ui/activity_services/chrome_activity_item_source.mm b/ios/chrome/browser/ui/activity_services/chrome_activity_item_source.mm index 42468f4..8529371 100644 --- a/ios/chrome/browser/ui/activity_services/chrome_activity_item_source.mm +++ b/ios/chrome/browser/ui/activity_services/chrome_activity_item_source.mm
@@ -52,7 +52,7 @@ @interface UIActivityURLSource () { NSString* _subject; - ThumbnailGeneratorBlock _thumbnailGenerator; + ChromeActivityItemThumbnailGenerator* _thumbnailGenerator; } // URL to be shared with share extensions. @@ -70,7 +70,8 @@ - (instancetype)initWithShareURL:(NSURL*)shareURL passwordManagerURL:(NSURL*)passwordManagerURL subject:(NSString*)subject - thumbnailGenerator:(ThumbnailGeneratorBlock)thumbnailGenerator { + thumbnailGenerator: + (ChromeActivityItemThumbnailGenerator*)thumbnailGenerator { DCHECK(shareURL); DCHECK(passwordManagerURL); DCHECK(subject); @@ -151,7 +152,7 @@ (UIActivityViewController*)activityViewController thumbnailImageForActivityType:(UIActivityType)activityType suggestedSize:(CGSize)size { - return _thumbnailGenerator(size); + return [_thumbnailGenerator thumbnailWithSize:size]; } @end
diff --git a/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator.h b/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator.h index 5c4d7c3..c5a0eaae 100644 --- a/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator.h +++ b/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator.h
@@ -8,16 +8,24 @@ #import <CoreGraphics/CoreGraphics.h> #import <UIKit/UIKit.h> -@class Tab; +namespace web { +class WebState; +} -// Block returning a thumbnail at the specified size. May return nil. -typedef UIImage* (^ThumbnailGeneratorBlock)(const CGSize&); +// ChromeActivityItemThumbnailGenerator will be used to retrieve activity items +// thumbnail given WebState. +@interface ChromeActivityItemThumbnailGenerator : NSObject -namespace activity_services { +// Default initializer. |webState| must not be nullptr. +- (instancetype)initWithWebState:(web::WebState*)webState + NS_DESIGNATED_INITIALIZER; -// Returns a thumbnail generator for the tab |tab|. |tab| must not be nil. -ThumbnailGeneratorBlock ThumbnailGeneratorForTab(Tab* tab); +// ChromeActivityItemThumbnailGenerator must be created with a WebState. +- (instancetype)init NS_UNAVAILABLE; -} // namespace activity_services +// Returns a thumbnail at the specified size. May return nil. +- (UIImage*)thumbnailWithSize:(const CGSize&)size; + +@end #endif // IOS_CHROME_BROWSER_UI_ACTIVITY_SERVICES_CHROME_ACTIVITY_ITEM_THUMBNAIL_GENERATOR_H_
diff --git a/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator.mm b/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator.mm index 9d936a9..e7e6285d 100644 --- a/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator.mm +++ b/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator.mm
@@ -6,38 +6,68 @@ #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h" -#import "ios/chrome/browser/tabs/tab.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" +#import "ios/web/public/web_state/web_state.h" +#include "ios/web/public/web_state/web_state_observer.h" +#import "ios/web/public/web_state/web_state_observer_bridge.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -namespace activity_services { +@interface ChromeActivityItemThumbnailGenerator () <CRWWebStateObserver> { + // WebState to be used for generating the snapshot. + web::WebState* _webState; + // Bridges WebStateObserver methods to this object. + std::unique_ptr<web::WebStateObserverBridge> _webStateObserver; +} +@end -ThumbnailGeneratorBlock ThumbnailGeneratorForTab(Tab* tab) { - DCHECK(tab); - DCHECK(tab.webState); - // Do not generate thumbnails for incognito tabs. - if (tab.webState->GetBrowserState()->IsOffTheRecord()) { - return ^UIImage*(CGSize const& size) { return nil; }; - } else { - __weak Tab* weakTab = tab; - return ^UIImage*(CGSize const& size) { - Tab* strongTab = weakTab; - if (!strongTab || !strongTab.webState) - return nil; +@implementation ChromeActivityItemThumbnailGenerator - UIImage* snapshot = SnapshotTabHelper::FromWebState(strongTab.webState) - ->GenerateSnapshotWithoutOverlays(); +#pragma mark - Initializers - if (!snapshot) - return nil; - - return ResizeImage(snapshot, size, ProjectionMode::kAspectFillAlignTop, - /*opaque=*/YES); - }; +- (instancetype)initWithWebState:(web::WebState*)webState { + DCHECK(webState); + self = [super init]; + if (self) { + // Thumbnail shouldn't be generated for incognito tabs. So there is no need + // to observe the webState. + if (webState->GetBrowserState()->IsOffTheRecord()) + return self; + _webState = webState; + _webStateObserver = std::make_unique<web::WebStateObserverBridge>(self); + _webState->AddObserver(_webStateObserver.get()); } + return self; } -} // namespace activity_services +- (void)dealloc { + if (_webState) + _webState->RemoveObserver(_webStateObserver.get()); +} + +#pragma mark - Public methods + +- (UIImage*)thumbnailWithSize:(const CGSize&)size { + if (!_webState) + return nil; + UIImage* snapshot = SnapshotTabHelper::FromWebState(_webState) + ->GenerateSnapshotWithoutOverlays(); + if (!snapshot) + return nil; + return ResizeImage(snapshot, size, ProjectionMode::kAspectFillAlignTop, + /*opaque=*/YES); +} + +#pragma mark - Private methods +#pragma mark - CRWWebStateObserver protocol + +- (void)webStateDestroyed:(web::WebState*)webState { + DCHECK_EQ(_webState, webState); + _webState->RemoveObserver(_webStateObserver.get()); + _webStateObserver.reset(); + _webState = nullptr; +} + +@end
diff --git a/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator_unittest.mm b/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator_unittest.mm index b4258ac5..6289d8ec 100644 --- a/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator_unittest.mm +++ b/ios/chrome/browser/ui/activity_services/chrome_activity_item_thumbnail_generator_unittest.mm
@@ -8,10 +8,8 @@ #import "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #import "ios/chrome/browser/snapshots/fake_snapshot_generator_delegate.h" #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h" -#include "ios/chrome/browser/tabs/tab.h" #import "ios/web/public/test/fakes/test_web_state.h" #include "testing/platform_test.h" -#import "third_party/ocmock/OCMock/OCMock.h" #include "ui/base/test/ios/ui_image_test_utils.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -34,15 +32,10 @@ SnapshotTabHelper::FromWebState(&test_web_state_)->SetDelegate(delegate_); } - Tab* CreateMockTabForThumbnail(bool incognito) { + void SetIncognito(bool incognito) { test_web_state_.SetBrowserState( incognito ? chrome_browser_state_->GetOffTheRecordChromeBrowserState() : chrome_browser_state_.get()); - - web::WebState* web_state = &test_web_state_; - id tab = [OCMockObject niceMockForClass:[Tab class]]; - OCMStub([tab webState]).andReturn(web_state); - return tab; } FakeSnapshotGeneratorDelegate* delegate_ = nil; @@ -51,26 +44,30 @@ web::TestWebState test_web_state_; }; -TEST_F(ChromeActivityItemThumbnailGeneratorTest, ThumbnailForNonIncognitoTab) { - Tab* tab = CreateMockTabForThumbnail(/*incognito=*/false); +TEST_F(ChromeActivityItemThumbnailGeneratorTest, + ThumbnailForNonIncognitoWebState) { + SetIncognito(/*incognito=*/false); CGSize size = CGSizeMake(50, 50); - ThumbnailGeneratorBlock generatorBlock = - activity_services::ThumbnailGeneratorForTab(tab); - EXPECT_TRUE(generatorBlock); - UIImage* thumbnail = generatorBlock(size); + ChromeActivityItemThumbnailGenerator* generator = + [[ChromeActivityItemThumbnailGenerator alloc] + initWithWebState:&test_web_state_]; + EXPECT_TRUE(generator); + UIImage* thumbnail = [generator thumbnailWithSize:size]; EXPECT_TRUE(thumbnail); EXPECT_TRUE(CGSizeEqualToSize(thumbnail.size, size)); } -TEST_F(ChromeActivityItemThumbnailGeneratorTest, NoThumbnailForIncognitoTab) { - Tab* tab = CreateMockTabForThumbnail(/*incognito=*/true); +TEST_F(ChromeActivityItemThumbnailGeneratorTest, + NoThumbnailForIncognitoWebState) { + SetIncognito(/*incognito=*/true); CGSize size = CGSizeMake(50, 50); - ThumbnailGeneratorBlock generatorBlock = - activity_services::ThumbnailGeneratorForTab(tab); - EXPECT_TRUE(generatorBlock); - UIImage* thumbnail = generatorBlock(size); + ChromeActivityItemThumbnailGenerator* generator = + [[ChromeActivityItemThumbnailGenerator alloc] + initWithWebState:&test_web_state_]; + EXPECT_TRUE(generator); + UIImage* thumbnail = [generator thumbnailWithSize:size]; EXPECT_FALSE(thumbnail); }
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data.h b/ios/chrome/browser/ui/activity_services/share_to_data.h index 1f439ec0..f94a617 100644 --- a/ios/chrome/browser/ui/activity_services/share_to_data.h +++ b/ios/chrome/browser/ui/activity_services/share_to_data.h
@@ -21,7 +21,8 @@ isPagePrintable:(BOOL)isPagePrintable isPageSearchable:(BOOL)isPageSearchable userAgent:(web::UserAgentType)userAgent - thumbnailGenerator:(ThumbnailGeneratorBlock)thumbnailGenerator; + thumbnailGenerator: + (ChromeActivityItemThumbnailGenerator*)thumbnailGenerator; // The URL to be shared with share extensions. This URL is the canonical URL of // the page. @@ -44,7 +45,8 @@ // Whether FindInPage can be enabled for this page. @property(nonatomic, readonly, assign) BOOL isPageSearchable; @property(nonatomic, readonly, assign) web::UserAgentType userAgent; -@property(nonatomic, copy) ThumbnailGeneratorBlock thumbnailGenerator; +@property(nonatomic, readonly) + ChromeActivityItemThumbnailGenerator* thumbnailGenerator; @end
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data.mm b/ios/chrome/browser/ui/activity_services/share_to_data.mm index ff3b3fe3..888c3352 100644 --- a/ios/chrome/browser/ui/activity_services/share_to_data.mm +++ b/ios/chrome/browser/ui/activity_services/share_to_data.mm
@@ -38,7 +38,8 @@ isPagePrintable:(BOOL)isPagePrintable isPageSearchable:(BOOL)isPageSearchable userAgent:(web::UserAgentType)userAgent - thumbnailGenerator:(ThumbnailGeneratorBlock)thumbnailGenerator { + thumbnailGenerator: + (ChromeActivityItemThumbnailGenerator*)thumbnailGenerator { DCHECK(shareURL.is_valid()); DCHECK(visibleURL.is_valid()); DCHECK(title);
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data_builder.h b/ios/chrome/browser/ui/activity_services/share_to_data_builder.h index 3d7dbb7..c0371c5 100644 --- a/ios/chrome/browser/ui/activity_services/share_to_data_builder.h +++ b/ios/chrome/browser/ui/activity_services/share_to_data_builder.h
@@ -8,11 +8,11 @@ class GURL; @class ShareToData; -@class Tab; namespace web { class WebState; } + namespace activity_services { // Returns a ShareToData object using data from |web_state|. |share_url| is the
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm b/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm index 186f9ce..4037e63 100644 --- a/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm +++ b/ios/chrome/browser/ui/activity_services/share_to_data_builder.mm
@@ -50,12 +50,10 @@ } BOOL is_page_printable = [web_state->GetView() viewPrintFormatter] != nil; - Tab* tab = LegacyTabHelper::GetTabForWebState(web_state); - ThumbnailGeneratorBlock thumbnail_generator = - activity_services::ThumbnailGeneratorForTab(tab); + ChromeActivityItemThumbnailGenerator* thumbnail_generator = + [[ChromeActivityItemThumbnailGenerator alloc] initWithWebState:web_state]; const GURL& finalURLToShare = !share_url.is_empty() ? share_url : web_state->GetVisibleURL(); - web::NavigationItem* visibleItem = web_state->GetNavigationManager()->GetVisibleItem(); web::UserAgentType userAgent = web::UserAgentType::NONE;
diff --git a/ios/chrome/browser/ui/activity_services/share_to_data_builder_unittest.mm b/ios/chrome/browser/ui/activity_services/share_to_data_builder_unittest.mm index 7c943f6..f7e016932 100644 --- a/ios/chrome/browser/ui/activity_services/share_to_data_builder_unittest.mm +++ b/ios/chrome/browser/ui/activity_services/share_to_data_builder_unittest.mm
@@ -13,7 +13,6 @@ #import "ios/chrome/browser/download/download_manager_tab_helper.h" #import "ios/chrome/browser/snapshots/fake_snapshot_generator_delegate.h" #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h" -#import "ios/chrome/browser/tabs/legacy_tab_helper.h" #import "ios/chrome/browser/ui/activity_services/share_to_data.h" #import "ios/testing/ocmock_complex_type_helper.h" #import "ios/web/public/test/fakes/test_navigation_manager.h" @@ -61,8 +60,6 @@ [[NSUUID UUID] UUIDString]); delegate_ = [[FakeSnapshotGeneratorDelegate alloc] init]; SnapshotTabHelper::FromWebState(web_state_.get())->SetDelegate(delegate_); - LegacyTabHelper::CreateForWebState(web_state_.get()); - // Needed by the ShareToDataForWebState to get the tab title. DownloadManagerTabHelper::CreateForWebState(web_state_.get(), /*delegate=*/nullptr); @@ -102,7 +99,7 @@ const CGSize size = CGSizeMake(40, 40); EXPECT_TRUE(UIImagesAreEqual( - actual_data.thumbnailGenerator(size), + [actual_data.thumbnailGenerator thumbnailWithSize:size], UIImageWithSizeAndSolidColor(size, [UIColor blueColor]))); } @@ -121,7 +118,7 @@ const CGSize size = CGSizeMake(40, 40); EXPECT_TRUE(UIImagesAreEqual( - actual_data.thumbnailGenerator(size), + [actual_data.thumbnailGenerator thumbnailWithSize:size], UIImageWithSizeAndSolidColor(size, [UIColor blueColor]))); }
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm index 961e944..bc4f47a 100644 --- a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm +++ b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
@@ -177,9 +177,7 @@ withHostedDomain:(NSString*)hostedDomain toBrowserState:(ios::ChromeBrowserState*)browserState { AuthenticationServiceFactory::GetForBrowserState(browserState) - ->SignIn(identity, [hostedDomain length] > 0 - ? base::SysNSStringToUTF8(hostedDomain) - : kNoHostedDomainFound); + ->SignIn(identity); } - (void)signOutBrowserState:(ios::ChromeBrowserState*)browserState {
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow_unittest.mm b/ios/chrome/browser/ui/authentication/authentication_flow_unittest.mm index 562ace8b..04ea3b8 100644 --- a/ios/chrome/browser/ui/authentication/authentication_flow_unittest.mm +++ b/ios/chrome/browser/ui/authentication/authentication_flow_unittest.mm
@@ -166,7 +166,7 @@ toBrowserState:browser_state_.get()]; AuthenticationServiceFactory::GetForBrowserState(browser_state_.get()) - ->SignIn(identity1_, kNoHostedDomainFound); + ->SignIn(identity1_); [authentication_flow_ startSignInWithCompletion:sign_in_completion_]; CheckSignInCompletion(true); @@ -211,7 +211,7 @@ [[performer_ expect] commitSyncForBrowserState:browser_state_.get()]; AuthenticationServiceFactory::GetForBrowserState(browser_state_.get()) - ->SignIn(identity2_, kNoHostedDomainFound); + ->SignIn(identity2_); [authentication_flow_ startSignInWithCompletion:sign_in_completion_]; CheckSignInCompletion(true);
diff --git a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm index d947c8b..6a90ee64 100644 --- a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm +++ b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm
@@ -59,7 +59,7 @@ AuthenticationService* authentication_service = AuthenticationServiceFactory::GetForBrowserState( chrome_browser_state_.get()); - authentication_service->SignIn(chrome_identity, kNoHostedDomainFound); + authentication_service->SignIn(chrome_identity); } web::TestWebThreadBundle thread_bundle_;
diff --git a/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm b/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm index ac77ce2..1d0a5c7 100644 --- a/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/authentication/signed_in_accounts_view_controller_unittest.mm
@@ -40,8 +40,7 @@ identity_service->AddIdentities( @[ @"identity1", @"identity2", @"identity3" ]); auth_service_->SignIn( - [identity_service->GetAllIdentitiesSortedForDisplay() objectAtIndex:0], - kNoHostedDomainFound); + [identity_service->GetAllIdentitiesSortedForDisplay() objectAtIndex:0]); } protected:
diff --git a/ios/chrome/browser/ui/fancy_ui/BUILD.gn b/ios/chrome/browser/ui/fancy_ui/BUILD.gn index bd2c82a..fe8377f 100644 --- a/ios/chrome/browser/ui/fancy_ui/BUILD.gn +++ b/ios/chrome/browser/ui/fancy_ui/BUILD.gn
@@ -14,6 +14,7 @@ "//base", "//base:i18n", "//ios/chrome/browser/ui/colors", + "//ios/chrome/common/colors", ] public_deps = [ "//ios/third_party/material_components_ios",
diff --git a/ios/chrome/browser/ui/fancy_ui/primary_action_button.mm b/ios/chrome/browser/ui/fancy_ui/primary_action_button.mm index 48347e12..ad20782 100644 --- a/ios/chrome/browser/ui/fancy_ui/primary_action_button.mm +++ b/ios/chrome/browser/ui/fancy_ui/primary_action_button.mm
@@ -5,6 +5,8 @@ #import "ios/chrome/browser/ui/fancy_ui/primary_action_button.h" #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" +#import "ios/chrome/common/colors/UIColor+cr_semantic_colors.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -15,32 +17,67 @@ - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) - [self initializeStyling]; + [self updateStyling]; return self; } - (id)initWithCoder:(NSCoder*)aDecoder { self = [super initWithCoder:aDecoder]; if (self) - [self initializeStyling]; + [self updateStyling]; return self; } - (void)awakeFromNib { [super awakeFromNib]; - [self initializeStyling]; + [self updateStyling]; } -- (void)initializeStyling { +- (void)updateStyling { self.hasOpaqueBackground = YES; - self.underlyingColorHint = [UIColor whiteColor]; - self.inkColor = - [[[MDCPalette cr_bluePalette] tint300] colorWithAlphaComponent:0.5f]; - [self setBackgroundColor:[[MDCPalette cr_bluePalette] tint500] - forState:UIControlStateNormal]; - [self setBackgroundColor:[UIColor colorWithWhite:0.6f alpha:1.0f] - forState:UIControlStateDisabled]; - [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + + UIColor* hintColor = UIColor.cr_systemBackgroundColor; + UIColor* inkColor = [UIColor colorWithWhite:1 alpha:0.2f]; + UIColor* backgroundColor = [UIColor colorNamed:kTintColor]; + UIColor* disabledColor = [UIColor colorNamed:kDisabledTintColor]; + UIColor* titleColor = [UIColor colorNamed:kSolidButtonTextColor]; + +#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) + if (@available(iOS 13, *)) { + // As of iOS 13 Beta 3, MDCFlatButton has a bug updating it's colors + // automatically. Here the colors are resolved and passed instead. + // TODO(crbug.com/983224): Clean up this once the bug is fixed. + hintColor = + [hintColor resolvedColorWithTraitCollection:self.traitCollection]; + inkColor = [inkColor resolvedColorWithTraitCollection:self.traitCollection]; + backgroundColor = + [backgroundColor resolvedColorWithTraitCollection:self.traitCollection]; + disabledColor = + [disabledColor resolvedColorWithTraitCollection:self.traitCollection]; + titleColor = + [titleColor resolvedColorWithTraitCollection:self.traitCollection]; + } +#endif + + self.underlyingColorHint = hintColor; + self.inkColor = inkColor; + [self setBackgroundColor:backgroundColor forState:UIControlStateNormal]; + [self setBackgroundColor:disabledColor forState:UIControlStateDisabled]; + [self setTitleColor:titleColor forState:UIControlStateNormal]; } +- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { + [super traitCollectionDidChange:previousTraitCollection]; +#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) + if (@available(iOS 13, *)) { + if ([self.traitCollection + hasDifferentColorAppearanceComparedToTraitCollection: + previousTraitCollection]) { + // As of iOS 13 Beta 3, MDCFlatButton doesn't update it's colors + // automatically. This line forces it. + [self updateStyling]; + } + } +#endif +} @end
diff --git a/ios/chrome/browser/ui/open_in/open_in_controller_egtest.mm b/ios/chrome/browser/ui/open_in/open_in_controller_egtest.mm index 69b83fbb..b8c76c0 100644 --- a/ios/chrome/browser/ui/open_in/open_in_controller_egtest.mm +++ b/ios/chrome/browser/ui/open_in/open_in_controller_egtest.mm
@@ -48,6 +48,12 @@ // Tests that open in button appears when opening a PDF, and that tapping on it // will open the activity view. - (void)testOpenIn { + // TODO(crbug.com/983135): The share menu displays in a popover on iPad, which + // causes this test to fail. + if ([ChromeEarlGrey isIPadIdiom]) { + EARL_GREY_TEST_DISABLED(@"Disabled on iPad"); + } + // TODO(crbug.com/982845): A bug is causing the "Open in" toolbar to disappear // after any VC is presented fullscreen over the BVC. The iOS 13 share menu // is presented fullscreen, but only when compiling with the iOS 12 SDK.
diff --git a/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm b/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm index 8263608..bafc984 100644 --- a/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm +++ b/ios/chrome/browser/ui/settings/passphrase_table_view_controller_test.mm
@@ -92,7 +92,7 @@ ChromeIdentity* identity = [identityService->GetAllIdentitiesSortedForDisplay() objectAtIndex:0]; AuthenticationServiceFactory::GetForBrowserState(chrome_browser_state_.get()) - ->SignIn(identity, kNoHostedDomainFound); + ->SignIn(identity); } void PassphraseTableViewControllerTest::SetUpNavigationController(
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index c1f6950..3ea0d1ac 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -219,14 +219,10 @@ @property(weak, nonatomic, readonly) CRWSessionController* sessionController; // The associated NavigationManagerImpl. @property(nonatomic, readonly) NavigationManagerImpl* navigationManagerImpl; -// Whether the associated WebState has an opener. -@property(nonatomic, readonly) BOOL hasOpener; // TODO(crbug.com/692871): Remove these functions and replace with more // appropriate NavigationItem getters. // Returns the navigation item for the current page. @property(nonatomic, readonly) web::NavigationItemImpl* currentNavItem; -// Returns the referrer for current navigation item. May be empty. -@property(nonatomic, readonly) web::Referrer currentNavItemReferrer; // Returns the current URL of the web view, and sets |trustLevel| accordingly // based on the confidence in the verification. @@ -280,8 +276,6 @@ // Updates SSL status for the current navigation item based on the information // provided by web view. - (void)updateSSLStatusForCurrentNavigationItem; -// Clears WebUI, if one exists. -- (void)clearWebUI; @end @@ -556,21 +550,12 @@ : nil; } -- (BOOL)hasOpener { - return self.webStateImpl ? self.webStateImpl->HasOpener() : NO; -} - - (web::NavigationItemImpl*)currentNavItem { return self.navigationManagerImpl ? self.navigationManagerImpl->GetCurrentItemImpl() : nullptr; } -- (web::Referrer)currentNavItemReferrer { - web::NavigationItem* currentItem = self.currentNavItem; - return currentItem ? currentItem->GetReferrer() : web::Referrer(); -} - #pragma mark - ** Public Methods ** #pragma mark - Header public methods @@ -617,6 +602,7 @@ _jsWindowErrorManager.reset(); self.swipeRecognizerProvider = nil; [self.legacyNativeController close]; + [self.requestController close]; // Mark the destruction sequence has started, in case someone else holds a // strong reference and tries to continue using the tab. @@ -687,67 +673,7 @@ // cancelled. _userInteractionState.SetLastUserInteraction(nullptr); base::RecordAction(base::UserMetricsAction("Reload")); - GURL URL = self.currentNavItem->GetURL(); - if ([self.legacyNativeController shouldLoadURLInNativeView:URL]) { - std::unique_ptr<web::NavigationContextImpl> navigationContext = - [_requestController - registerLoadRequestForURL:URL - referrer:self.currentNavItemReferrer - transition:ui::PageTransition::PAGE_TRANSITION_RELOAD - sameDocumentNavigation:NO - hasUserGesture:YES - rendererInitiated:rendererInitiated - placeholderNavigation:NO]; - self.webStateImpl->OnNavigationStarted(navigationContext.get()); - [self didStartLoading]; - self.navigationManagerImpl->CommitPendingItem( - navigationContext->ReleaseItem()); - [self.legacyNativeController reload]; - navigationContext->SetHasCommitted(true); - self.webStateImpl->OnNavigationFinished(navigationContext.get()); - [self loadCompleteWithSuccess:YES forContext:nullptr]; - } else { - web::NavigationItem* transientItem = - self.navigationManagerImpl->GetTransientItem(); - if (transientItem) { - // If there's a transient item, a reload is considered a new navigation to - // the transient item's URL (as on other platforms). - NavigationManager::WebLoadParams reloadParams(transientItem->GetURL()); - reloadParams.transition_type = ui::PAGE_TRANSITION_RELOAD; - reloadParams.extra_headers = - [transientItem->GetHttpRequestHeaders() copy]; - self.webState->GetNavigationManager()->LoadURLWithParams(reloadParams); - } else { - self.currentNavItem->SetTransitionType( - ui::PageTransition::PAGE_TRANSITION_RELOAD); - if (web::GetWebClient()->IsSlimNavigationManagerEnabled() && - !web::GetWebClient()->IsAppSpecificURL( - net::GURLWithNSURL(self.webView.URL))) { - // New navigation manager can delegate directly to WKWebView to reload - // for non-app-specific URLs. The necessary navigation states will be - // updated in WKNavigationDelegate callbacks. - WKNavigation* navigation = [self.webView reload]; - [self.navigationHandler.navigationStates - setState:web::WKNavigationState::REQUESTED - forNavigation:navigation]; - std::unique_ptr<web::NavigationContextImpl> navigationContext = - [_requestController - registerLoadRequestForURL:URL - referrer:self.currentNavItemReferrer - transition:ui::PageTransition:: - PAGE_TRANSITION_RELOAD - sameDocumentNavigation:NO - hasUserGesture:YES - rendererInitiated:rendererInitiated - placeholderNavigation:NO]; - [self.navigationHandler.navigationStates - setContext:std::move(navigationContext) - forNavigation:navigation]; - } else { - [self loadCurrentURLWithRendererInitiatedNavigation:rendererInitiated]; - } - } - } + [_requestController reloadWithRendererInitiatedNavigation:rendererInitiated]; } - (void)stopLoading { @@ -792,50 +718,8 @@ _currentURLLoadWasTrigerred = YES; - // Reset current WebUI if one exists. - [self clearWebUI]; - - // Abort any outstanding page load. This ensures the delegate gets informed - // about the outgoing page, and further messages from the page are suppressed. - if (self.navigationHandler.navigationState != - web::WKNavigationState::FINISHED) { - [self.webView stopLoading]; - [self.navigationHandler stopLoading]; - } - - self.webStateImpl->ClearTransientContent(); - - web::NavigationItem* item = self.currentNavItem; - const GURL currentURL = item ? item->GetURL() : GURL::EmptyGURL(); - const bool isCurrentURLAppSpecific = - web::GetWebClient()->IsAppSpecificURL(currentURL); - // If it's a chrome URL, but not a native one, create the WebUI instance. - if (isCurrentURLAppSpecific && - ![self.legacyNativeController shouldLoadURLInNativeView:currentURL]) { - if (!(item->GetTransitionType() & ui::PAGE_TRANSITION_TYPED || - item->GetTransitionType() & ui::PAGE_TRANSITION_AUTO_BOOKMARK) && - self.hasOpener) { - // WebUI URLs can not be opened by DOM to prevent cross-site scripting as - // they have increased power. WebUI URLs may only be opened when the user - // types in the URL or use bookmarks. - self.navigationManagerImpl->DiscardNonCommittedItems(); - return; - } else { - [self createWebUIForURL:currentURL]; - } - } - - // Loading a new url, must check here if it's a native chrome URL and - // replace the appropriate view if so, or transition back to a web view from - // a native view. - if ([self.legacyNativeController shouldLoadURLInNativeView:currentURL]) { - [self.legacyNativeController - loadCurrentURLInNativeViewWithRendererInitiatedNavigation: - rendererInitiated]; - } else if ([_requestController maybeLoadRequestForCurrentNavigationItem]) { - [self ensureWebViewCreated]; - [_requestController loadRequestForCurrentNavigationItem]; - } + [_requestController + loadCurrentURLWithRendererInitiatedNavigation:rendererInitiated]; } - (void)loadCurrentURLIfNecessary { @@ -863,12 +747,6 @@ // Loads the HTML into the page at the given URL. Only for testing purpose. - (void)loadHTML:(NSString*)HTML forURL:(const GURL&)URL { - // Web View should not be created for App Specific URLs. - if (!web::GetWebClient()->IsAppSpecificURL(URL)) { - [self ensureWebViewCreated]; - DCHECK(self.webView) << "self.webView null while trying to load HTML"; - } - [_requestController loadHTML:HTML forURL:URL]; } @@ -1420,19 +1298,6 @@ return NO; } -#pragma mark - WebUI - -// Sets up WebUI for URL. -- (void)createWebUIForURL:(const GURL&)URL { - // |CreateWebUI| will do nothing if |URL| is not a WebUI URL and then - // |HasWebUI| will return false. - self.webStateImpl->CreateWebUI(URL); -} - -- (void)clearWebUI { - self.webStateImpl->ClearWebUI(); -} - #pragma mark - CRWWebViewScrollViewProxyObserver - (void)webViewScrollViewDidZoom: @@ -2184,7 +2049,7 @@ - (void)navigationHandler:(CRWWKNavigationHandler*)navigationHandler createWebUIForURL:(const GURL&)URL { - [self createWebUIForURL:URL]; + [_requestController createWebUIForURL:URL]; } - (void)navigationHandler:(CRWWKNavigationHandler*)navigationHandler @@ -2277,6 +2142,22 @@ [self stopLoading]; } +- (void)webRequestControllerEnsureWebViewCreated: + (CRWWebRequestController*)requestController { + [self ensureWebViewCreated]; +} + +- (void)webRequestControllerDidStartLoading: + (CRWWebRequestController*)requestController { + [self didStartLoading]; +} + +- (void)webRequestController:(CRWWebRequestController*)requestController + didCompleteLoadWithSuccess:(BOOL)loadSuccess + forContext:(web::NavigationContextImpl*)context { + [self loadCompleteWithSuccess:loadSuccess forContext:context]; +} + - (void)webRequestControllerDisconnectScrollViewProxy: (CRWWebRequestController*)requestController { // Disable |allowsBackForwardNavigationGestures| during restore. Otherwise,
diff --git a/ios/web/web_state/ui/crw_web_request_controller.h b/ios/web/web_state/ui/crw_web_request_controller.h index fec8ea1c..48c1b9b 100644 --- a/ios/web/web_state/ui/crw_web_request_controller.h +++ b/ios/web/web_state/ui/crw_web_request_controller.h
@@ -28,6 +28,20 @@ - (void)webRequestControllerStopLoading: (CRWWebRequestController*)requestController; +// The delegate will create a web view if it's not yet created. +- (void)webRequestControllerEnsureWebViewCreated: + (CRWWebRequestController*)requestController; + +// The delegate is called when a page (native or web) has actually started +// loading. +- (void)webRequestControllerDidStartLoading: + (CRWWebRequestController*)requestController; + +// The delegate is called when a page is loaded. +- (void)webRequestController:(CRWWebRequestController*)requestController + didCompleteLoadWithSuccess:(BOOL)loadSuccess + forContext:(web::NavigationContextImpl*)context; + // Asks proxy to disconnect scroll proxy if needed. - (void)webRequestControllerDisconnectScrollViewProxy: (CRWWebRequestController*)requestController; @@ -61,7 +75,7 @@ @end // Controller in charge of preparing and handling web requests for the delegate, -// which should be |CrwWebController|. +// which should be |CRWWebController|. @interface CRWWebRequestController : NSObject @property(nonatomic, weak) id<CRWWebRequestControllerDelegate> delegate; @@ -82,12 +96,14 @@ // state to finished and call |didFinishWithURL| with failure. - (BOOL)maybeLoadRequestForCurrentNavigationItem; -// Loads request for the URL of the current navigation item. Subclasses may -// choose to build a new NSURLRequest and call -// |loadRequestForCurrentNavigationItem| on the underlying web view, or use -// native web view navigation where possible (for example, going back and -// forward through the history stack). -- (void)loadRequestForCurrentNavigationItem; +// Sets up WebUI for URL. +- (void)createWebUIForURL:(const GURL&)URL; + +// Clears WebUI, if one exists. +- (void)clearWebUI; + +// Loads the URL indicated by current session state. +- (void)loadCurrentURLWithRendererInitiatedNavigation:(BOOL)rendererInitiated; // Should be called by owner component after URL is finished loading and // self.navigationHandler.navigationState is set to FINISHED. |context| contains @@ -128,6 +144,10 @@ // document. - (void)loadHTML:(NSString*)HTML forURL:(const GURL&)URL; +// Reloads web view. |rendererInitiated| is YES for renderer-initiated +// navigation. |rendererInitiated| is NO for browser-initiated navigation. +- (void)reloadWithRendererInitiatedNavigation:(BOOL)rendererInitiated; + @end #endif // IOS_WEB_WEB_STATE_UI_CRW_WEB_REQUEST_CONTROLLER_H_
diff --git a/ios/web/web_state/ui/crw_web_request_controller.mm b/ios/web/web_state/ui/crw_web_request_controller.mm index 9cce397..7100b189 100644 --- a/ios/web/web_state/ui/crw_web_request_controller.mm +++ b/ios/web/web_state/ui/crw_web_request_controller.mm
@@ -69,6 +69,10 @@ // Set to YES when [self close] is called. @property(nonatomic, assign) BOOL beingDestroyed; +// Returns The CRWLegacyNativeContentController handler class from delegate. +@property(nonatomic, readonly) + CRWLegacyNativeContentController* legacyNativeController; + @end @implementation CRWWebRequestController @@ -83,8 +87,474 @@ - (void)close { self.beingDestroyed = YES; + _webState = nullptr; } +- (void)loadCurrentURLWithRendererInitiatedNavigation:(BOOL)rendererInitiated { + // Reset current WebUI if one exists. + [self clearWebUI]; + + // Abort any outstanding page load. This ensures the delegate gets informed + // about the outgoing page, and further messages from the page are suppressed. + if (self.navigationHandler.navigationState != + web::WKNavigationState::FINISHED) { + [self.webView stopLoading]; + [self.navigationHandler stopLoading]; + } + + self.webState->ClearTransientContent(); + + web::NavigationItem* item = self.currentNavItem; + const GURL currentURL = item ? item->GetURL() : GURL::EmptyGURL(); + const bool isCurrentURLAppSpecific = + web::GetWebClient()->IsAppSpecificURL(currentURL); + // If it's a chrome URL, but not a native one, create the WebUI instance. + if (isCurrentURLAppSpecific && + ![self.legacyNativeController shouldLoadURLInNativeView:currentURL]) { + if (!(item->GetTransitionType() & ui::PAGE_TRANSITION_TYPED || + item->GetTransitionType() & ui::PAGE_TRANSITION_AUTO_BOOKMARK) && + self.hasOpener) { + // WebUI URLs can not be opened by DOM to prevent cross-site scripting as + // they have increased power. WebUI URLs may only be opened when the user + // types in the URL or use bookmarks. + self.navigationManagerImpl->DiscardNonCommittedItems(); + return; + } else { + [self createWebUIForURL:currentURL]; + } + } + + // Loading a new url, must check here if it's a native chrome URL and + // replace the appropriate view if so, or transition back to a web view from + // a native view. + if ([self.legacyNativeController shouldLoadURLInNativeView:currentURL]) { + [self.legacyNativeController + loadCurrentURLInNativeViewWithRendererInitiatedNavigation: + rendererInitiated]; + } else if ([self maybeLoadRequestForCurrentNavigationItem]) { + [_delegate webRequestControllerEnsureWebViewCreated:self]; + [self loadRequestForCurrentNavigationItem]; + } +} + +- (void)loadData:(NSData*)data + MIMEType:(NSString*)MIMEType + forURL:(const GURL&)URL { + [_delegate webRequestControllerStopLoading:self]; + web::NavigationItemImpl* item = + self.navigationManagerImpl->GetLastCommittedItemImpl(); + auto navigationContext = web::NavigationContextImpl::CreateNavigationContext( + self.webState, URL, + /*has_user_gesture=*/true, item->GetTransitionType(), + /*is_renderer_initiated=*/false); + self.navigationHandler.navigationState = web::WKNavigationState::REQUESTED; + navigationContext->SetNavigationItemUniqueID(item->GetUniqueID()); + + item->SetNavigationInitiationType( + web::NavigationInitiationType::BROWSER_INITIATED); + // The error_retry_state_machine may still be in the + // |kDisplayingWebErrorForFailedNavigation| from the navigation that is being + // replaced. As the navigation is now successful, the error can be cleared. + item->error_retry_state_machine().SetNoNavigationError(); + // The load data call will replace the current navigation and the webView URL + // of the navigation will be replaced by |URL|. Set the URL of the + // navigationItem to keep them synced. + // Note: it is possible that the URL in item already match |url|. But item can + // also contain a placeholder URL intended to be replaced. + item->SetURL(URL); + navigationContext->SetMimeType(MIMEType); + if (item->GetUserAgentType() == web::UserAgentType::NONE && + URLNeedsUserAgentType(URL)) { + item->SetUserAgentType(web::UserAgentType::MOBILE); + } + + WKNavigation* navigation = + [self.webView loadData:data + MIMEType:MIMEType + characterEncodingName:base::SysUTF8ToNSString(base::kCodepageUTF8) + baseURL:net::NSURLWithGURL(URL)]; + + [self.navigationHandler.navigationStates + setContext:std::move(navigationContext) + forNavigation:navigation]; + [self.navigationHandler.navigationStates + setState:web::WKNavigationState::REQUESTED + forNavigation:navigation]; +} + +- (void)loadHTML:(NSString*)HTML forURL:(const GURL&)URL { + // Web View should not be created for App Specific URLs. + if (!web::GetWebClient()->IsAppSpecificURL(URL)) { + [_delegate webRequestControllerEnsureWebViewCreated:self]; + DCHECK(self.webView) << "self.webView null while trying to load HTML"; + } + + DCHECK(HTML.length); + // Remove the transient content view. + self.webState->ClearTransientContent(); + + self.navigationHandler.navigationState = web::WKNavigationState::REQUESTED; + + WKNavigation* navigation = + [self.webView loadHTMLString:HTML baseURL:net::NSURLWithGURL(URL)]; + [self.navigationHandler.navigationStates + setState:web::WKNavigationState::REQUESTED + forNavigation:navigation]; + std::unique_ptr<web::NavigationContextImpl> context; + const ui::PageTransition loadHTMLTransition = + ui::PageTransition::PAGE_TRANSITION_TYPED; + if (self.webState->HasWebUI()) { + // WebUI uses |loadHTML:forURL:| to feed the content to web view. This + // should not be treated as a navigation, but WKNavigationDelegate callbacks + // still expect a valid context. + context = web::NavigationContextImpl::CreateNavigationContext( + self.webState, URL, /*has_user_gesture=*/true, loadHTMLTransition, + /*is_renderer_initiated=*/false); + context->SetNavigationItemUniqueID(self.currentNavItem->GetUniqueID()); + // Transfer pending item ownership to NavigationContext. + // NavigationManager owns pending item after navigation is requested and + // until navigation context is created. + context->SetItem(self.navigationManagerImpl->ReleasePendingItem()); + } else { + context = [self registerLoadRequestForURL:URL + referrer:web::Referrer() + transition:loadHTMLTransition + sameDocumentNavigation:NO + hasUserGesture:YES + rendererInitiated:NO + placeholderNavigation:NO]; + } + context->SetLoadingHtmlString(true); + context->SetMimeType(@"text/html"); + [self.navigationHandler.navigationStates setContext:std::move(context) + forNavigation:navigation]; +} + +- (void)reloadWithRendererInitiatedNavigation:(BOOL)rendererInitiated { + GURL URL = self.currentNavItem->GetURL(); + if ([self.legacyNativeController shouldLoadURLInNativeView:URL]) { + std::unique_ptr<web::NavigationContextImpl> navigationContext = [self + registerLoadRequestForURL:URL + referrer:self.currentNavItemReferrer + transition:ui::PageTransition::PAGE_TRANSITION_RELOAD + sameDocumentNavigation:NO + hasUserGesture:YES + rendererInitiated:rendererInitiated + placeholderNavigation:NO]; + self.webState->OnNavigationStarted(navigationContext.get()); + [_delegate webRequestControllerDidStartLoading:self]; + self.navigationManagerImpl->CommitPendingItem( + navigationContext->ReleaseItem()); + [self.legacyNativeController reload]; + navigationContext->SetHasCommitted(true); + self.webState->OnNavigationFinished(navigationContext.get()); + [_delegate webRequestController:self + didCompleteLoadWithSuccess:(BOOL)YES + forContext:nullptr]; + } else { + web::NavigationItem* transientItem = + self.navigationManagerImpl->GetTransientItem(); + if (transientItem) { + // If there's a transient item, a reload is considered a new navigation to + // the transient item's URL (as on other platforms). + web::NavigationManager::WebLoadParams reloadParams( + transientItem->GetURL()); + reloadParams.transition_type = ui::PAGE_TRANSITION_RELOAD; + reloadParams.extra_headers = + [transientItem->GetHttpRequestHeaders() copy]; + self.webState->GetNavigationManager()->LoadURLWithParams(reloadParams); + } else { + self.currentNavItem->SetTransitionType( + ui::PageTransition::PAGE_TRANSITION_RELOAD); + if (web::GetWebClient()->IsSlimNavigationManagerEnabled() && + !web::GetWebClient()->IsAppSpecificURL( + net::GURLWithNSURL(self.webView.URL))) { + // New navigation manager can delegate directly to WKWebView to reload + // for non-app-specific URLs. The necessary navigation states will be + // updated in WKNavigationDelegate callbacks. + WKNavigation* navigation = [self.webView reload]; + [self.navigationHandler.navigationStates + setState:web::WKNavigationState::REQUESTED + forNavigation:navigation]; + std::unique_ptr<web::NavigationContextImpl> navigationContext = [self + registerLoadRequestForURL:URL + referrer:self.currentNavItemReferrer + transition:ui::PageTransition::PAGE_TRANSITION_RELOAD + sameDocumentNavigation:NO + hasUserGesture:YES + rendererInitiated:rendererInitiated + placeholderNavigation:NO]; + [self.navigationHandler.navigationStates + setContext:std::move(navigationContext) + forNavigation:navigation]; + } else { + [self loadCurrentURLWithRendererInitiatedNavigation:rendererInitiated]; + } + } + } +} + +- (std::unique_ptr<web::NavigationContextImpl>) + registerLoadRequestForURL:(const GURL&)URL + sameDocumentNavigation:(BOOL)sameDocumentNavigation + hasUserGesture:(BOOL)hasUserGesture + rendererInitiated:(BOOL)rendererInitiated + placeholderNavigation:(BOOL)placeholderNavigation { + // Get the navigation type from the last main frame load request, and try to + // map that to a PageTransition. + WKNavigationType navigationType = + self.navigationHandler.pendingNavigationInfo + ? self.navigationHandler.pendingNavigationInfo.navigationType + : WKNavigationTypeOther; + ui::PageTransition transition = + [self.navigationHandler pageTransitionFromNavigationType:navigationType]; + + if (web::GetWebClient()->IsSlimNavigationManagerEnabled() && + navigationType == WKNavigationTypeBackForward && + self.webView.backForwardList.currentItem) { + web::NavigationItem* currentItem = [[CRWNavigationItemHolder + holderForBackForwardListItem:self.webView.backForwardList.currentItem] + navigationItem]; + if (currentItem) { + transition = ui::PageTransitionFromInt(transition | + currentItem->GetTransitionType()); + } + } + + // The referrer is not known yet, and will be updated later. + const web::Referrer emptyReferrer; + std::unique_ptr<web::NavigationContextImpl> context = + [self registerLoadRequestForURL:URL + referrer:emptyReferrer + transition:transition + sameDocumentNavigation:sameDocumentNavigation + hasUserGesture:hasUserGesture + rendererInitiated:rendererInitiated + placeholderNavigation:placeholderNavigation]; + context->SetWKNavigationType(navigationType); + return context; +} + +- (std::unique_ptr<web::NavigationContextImpl>) + registerLoadRequestForURL:(const GURL&)requestURL + referrer:(const web::Referrer&)referrer + transition:(ui::PageTransition)transition + sameDocumentNavigation:(BOOL)sameDocumentNavigation + hasUserGesture:(BOOL)hasUserGesture + rendererInitiated:(BOOL)rendererInitiated + placeholderNavigation:(BOOL)placeholderNavigation { + // Transfer time is registered so that further transitions within the time + // envelope are not also registered as links. + [_delegate + webRequestControllerUserInteractionState:self] -> ResetLastTransferTime(); + + // Add or update pending item before any WebStateObserver callbacks. + // See https://crbug.com/842151 for a scenario where this is important. + web::NavigationItem* item = + self.navigationManagerImpl->GetPendingItemInCurrentOrRestoredSession(); + if (item) { + // Update the existing pending entry. + // Typically on PAGE_TRANSITION_CLIENT_REDIRECT. + // Don't update if request is a placeholder entry because the pending item + // should have the original target URL. + // Don't update if pending URL has a different origin, because client + // redirects can not change the origin. It is possible to have more than one + // pending navigations, so the redirect does not necesserily belong to the + // pending navigation item. + if (!placeholderNavigation && + item->GetURL().GetOrigin() == requestURL.GetOrigin()) { + self.navigationManagerImpl->UpdatePendingItemUrl(requestURL); + } + } else { + self.navigationManagerImpl->AddPendingItem( + requestURL, referrer, transition, + rendererInitiated ? web::NavigationInitiationType::RENDERER_INITIATED + : web::NavigationInitiationType::BROWSER_INITIATED, + web::NavigationManager::UserAgentOverrideOption::INHERIT); + item = + self.navigationManagerImpl->GetPendingItemInCurrentOrRestoredSession(); + } + + bool redirect = transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK; + if (!redirect) { + // Before changing navigation state, the delegate should be informed that + // any existing request is being cancelled before completion. + [self.navigationHandler loadCancelled]; + DCHECK_EQ(web::WKNavigationState::FINISHED, + self.navigationHandler.navigationState); + } + + self.navigationHandler.navigationState = web::WKNavigationState::REQUESTED; + + // Record the state of outgoing web view. Do nothing if native controller + // exists, because in that case recordStateInHistory will record the state + // of incoming page as native controller is already inserted. + // TODO(crbug.com/811770) Don't record state under WKBasedNavigationManager + // because it may incorrectly clobber the incoming page if this is a + // back/forward navigation. WKWebView restores page scroll state for web view + // pages anyways so this only impacts user if WKWebView is deleted. + if (!redirect && ![self.legacyNativeController hasController] && + !web::GetWebClient()->IsSlimNavigationManagerEnabled()) { + [_delegate webRequestControllerRecordStateInHistory:self]; + } + + std::unique_ptr<web::NavigationContextImpl> context = + web::NavigationContextImpl::CreateNavigationContext( + self.webState, requestURL, hasUserGesture, transition, + rendererInitiated); + context->SetPlaceholderNavigation(placeholderNavigation); + + // TODO(crbug.com/676129): LegacyNavigationManagerImpl::AddPendingItem does + // not create a pending item in case of reload. Remove this workaround once + // the bug is fixed or WKBasedNavigationManager is fully adopted. + if (!item) { + DCHECK(!web::GetWebClient()->IsSlimNavigationManagerEnabled()); + item = self.navigationManagerImpl->GetLastCommittedItem(); + } + + context->SetNavigationItemUniqueID(item->GetUniqueID()); + context->SetIsPost([self.navigationHandler isCurrentNavigationItemPOST]); + context->SetIsSameDocument(sameDocumentNavigation); + + if (!IsWKInternalUrl(requestURL) && !placeholderNavigation) { + self.webState->SetIsLoading(true); + } + + // WKWebView may have multiple pending items. Move pending item ownership from + // NavigationManager to NavigationContext. NavigationManager owns pending item + // after navigation was requested and until NavigationContext is created. + // No need to transfer the ownership for NativeContent URLs, because the + // load of NativeContent is synchronous. No need to transfer the ownership + // for WebUI navigations, because those navigation do not have access to + // NavigationContext. + if (![self.legacyNativeController + shouldLoadURLInNativeView:context->GetUrl()]) { + if (self.navigationManagerImpl->GetPendingItemIndex() == -1) { + context->SetItem(self.navigationManagerImpl->ReleasePendingItem()); + } + } + + return context; +} + +- (void)didFinishWithURL:(const GURL&)currentURL + loadSuccess:(BOOL)loadSuccess + context:(nullable const web::NavigationContextImpl*)context { + DCHECK_EQ(web::WKNavigationState::FINISHED, + self.navigationHandler.navigationState); + + [_delegate webRequestControllerRestoreStateFromHistory:self]; + + // Placeholder and restore session URLs are implementation details so should + // not notify WebStateObservers. If |context| is nullptr, don't skip + // placeholder URLs because this may be the only opportunity to update + // |isLoading| for native view reload. + + if (context && context->IsPlaceholderNavigation()) + return; + + if (context && IsRestoreSessionUrl(context->GetUrl())) + return; + + if (IsRestoreSessionUrl(net::GURLWithNSURL(self.webView.URL))) + return; + + if (context && context->IsLoadingErrorPage()) + return; + + if (!loadSuccess) { + // WebStateObserver callbacks will be called for load failure after + // loading placeholder URL. + return; + } + + if (![self.navigationHandler.navigationStates + lastNavigationWithPendingItemInNavigationContext]) { + self.webState->SetIsLoading(false); + } else { + // There is another pending navigation, so the state is still loading. + } + self.webState->OnPageLoaded(currentURL, YES); +} + +// Reports Navigation.IOSWKWebViewSlowFastBackForward UMA. No-op if pending +// navigation is not back forward navigation. +- (void)reportBackForwardNavigationTypeForFastNavigation:(BOOL)isFast { + web::NavigationManager* navigationManager = self.navigationManagerImpl; + int pendingIndex = navigationManager->GetPendingItemIndex(); + if (pendingIndex == -1) { + // Pending navigation is not a back forward navigation. + return; + } + + BOOL isBack = pendingIndex < navigationManager->GetLastCommittedItemIndex(); + BackForwardNavigationType type = BackForwardNavigationType::FAST_BACK; + if (isBack) { + type = isFast ? BackForwardNavigationType::FAST_BACK + : BackForwardNavigationType::SLOW_BACK; + } else { + type = isFast ? BackForwardNavigationType::FAST_FORWARD + : BackForwardNavigationType::SLOW_FORWARD; + } + + UMA_HISTOGRAM_ENUMERATION( + "Navigation.IOSWKWebViewSlowFastBackForward", type, + BackForwardNavigationType::BACK_FORWARD_NAVIGATION_TYPE_COUNT); +} + +#pragma mark Navigation and Session Information + +// Returns the associated NavigationManagerImpl. +- (web::NavigationManagerImpl*)navigationManagerImpl { + return self.webState ? &(self.webState->GetNavigationManagerImpl()) : nil; +} + +// Returns the navigation item for the current page. +- (web::NavigationItemImpl*)currentNavItem { + return self.navigationManagerImpl + ? self.navigationManagerImpl->GetCurrentItemImpl() + : nullptr; +} + +// Returns the current transition type. +- (ui::PageTransition)currentTransition { + if (self.currentNavItem) + return self.currentNavItem->GetTransitionType(); + else + return ui::PageTransitionFromInt(0); +} + +// Returns the referrer for current navigation item. May be empty. +- (web::Referrer)currentNavItemReferrer { + web::NavigationItem* currentItem = self.currentNavItem; + return currentItem ? currentItem->GetReferrer() : web::Referrer(); +} + +// The HTTP headers associated with the current navigation item. These are nil +// unless the request was a POST. +- (NSDictionary*)currentHTTPHeaders { + web::NavigationItem* currentItem = self.currentNavItem; + return currentItem ? currentItem->GetHttpRequestHeaders() : nil; +} + +#pragma mark - WebUI + +- (void)createWebUIForURL:(const GURL&)URL { + // |CreateWebUI| will do nothing if |URL| is not a WebUI URL and then + // |HasWebUI| will return false. + self.webState->CreateWebUI(URL); +} + +- (void)clearWebUI { + self.webState->ClearWebUI(); +} + +#pragma mark - Private methods + +// Checks if a load request of the current navigation item should proceed. If +// this returns |YES|, caller should create a webView and call +// |loadRequestForCurrentNavigationItem|. Otherwise this will set the request +// state to finished and call |didFinishWithURL| with failure. - (BOOL)maybeLoadRequestForCurrentNavigationItem { web::NavigationItem* item = self.currentNavItem; GURL targetURL = item ? item->GetVirtualURL() : GURL::EmptyGURL(); @@ -104,6 +574,11 @@ return YES; } +// Loads request for the URL of the current navigation item. Subclasses may +// choose to build a new NSURLRequest and call +// |loadRequestForCurrentNavigationItem| on the underlying web view, or use +// native web view navigation where possible (for example, going back and +// forward through the history stack). - (void)loadRequestForCurrentNavigationItem { DCHECK(self.webView); DCHECK(self.currentNavItem); @@ -292,303 +767,6 @@ })); } -- (void)loadData:(NSData*)data - MIMEType:(NSString*)MIMEType - forURL:(const GURL&)URL { - [_delegate webRequestControllerStopLoading:self]; - web::NavigationItemImpl* item = - self.navigationManagerImpl->GetLastCommittedItemImpl(); - auto navigationContext = web::NavigationContextImpl::CreateNavigationContext( - self.webState, URL, - /*has_user_gesture=*/true, item->GetTransitionType(), - /*is_renderer_initiated=*/false); - self.navigationHandler.navigationState = web::WKNavigationState::REQUESTED; - navigationContext->SetNavigationItemUniqueID(item->GetUniqueID()); - - item->SetNavigationInitiationType( - web::NavigationInitiationType::BROWSER_INITIATED); - // The error_retry_state_machine may still be in the - // |kDisplayingWebErrorForFailedNavigation| from the navigation that is being - // replaced. As the navigation is now successful, the error can be cleared. - item->error_retry_state_machine().SetNoNavigationError(); - // The load data call will replace the current navigation and the webView URL - // of the navigation will be replaced by |URL|. Set the URL of the - // navigationItem to keep them synced. - // Note: it is possible that the URL in item already match |url|. But item can - // also contain a placeholder URL intended to be replaced. - item->SetURL(URL); - navigationContext->SetMimeType(MIMEType); - if (item->GetUserAgentType() == web::UserAgentType::NONE && - URLNeedsUserAgentType(URL)) { - item->SetUserAgentType(web::UserAgentType::MOBILE); - } - - WKNavigation* navigation = - [self.webView loadData:data - MIMEType:MIMEType - characterEncodingName:base::SysUTF8ToNSString(base::kCodepageUTF8) - baseURL:net::NSURLWithGURL(URL)]; - - [self.navigationHandler.navigationStates - setContext:std::move(navigationContext) - forNavigation:navigation]; - [self.navigationHandler.navigationStates - setState:web::WKNavigationState::REQUESTED - forNavigation:navigation]; -} - -- (void)loadHTML:(NSString*)HTML forURL:(const GURL&)URL { - DCHECK(HTML.length); - // Remove the transient content view. - self.webState->ClearTransientContent(); - - self.navigationHandler.navigationState = web::WKNavigationState::REQUESTED; - - WKNavigation* navigation = - [self.webView loadHTMLString:HTML baseURL:net::NSURLWithGURL(URL)]; - [self.navigationHandler.navigationStates - setState:web::WKNavigationState::REQUESTED - forNavigation:navigation]; - std::unique_ptr<web::NavigationContextImpl> context; - const ui::PageTransition loadHTMLTransition = - ui::PageTransition::PAGE_TRANSITION_TYPED; - if (self.webState->HasWebUI()) { - // WebUI uses |loadHTML:forURL:| to feed the content to web view. This - // should not be treated as a navigation, but WKNavigationDelegate callbacks - // still expect a valid context. - context = web::NavigationContextImpl::CreateNavigationContext( - self.webState, URL, /*has_user_gesture=*/true, loadHTMLTransition, - /*is_renderer_initiated=*/false); - context->SetNavigationItemUniqueID(self.currentNavItem->GetUniqueID()); - // Transfer pending item ownership to NavigationContext. - // NavigationManager owns pending item after navigation is requested and - // until navigation context is created. - context->SetItem(self.navigationManagerImpl->ReleasePendingItem()); - } else { - context = [self registerLoadRequestForURL:URL - referrer:web::Referrer() - transition:loadHTMLTransition - sameDocumentNavigation:NO - hasUserGesture:YES - rendererInitiated:NO - placeholderNavigation:NO]; - } - context->SetLoadingHtmlString(true); - context->SetMimeType(@"text/html"); - [self.navigationHandler.navigationStates setContext:std::move(context) - forNavigation:navigation]; -} - -- (std::unique_ptr<web::NavigationContextImpl>) - registerLoadRequestForURL:(const GURL&)URL - sameDocumentNavigation:(BOOL)sameDocumentNavigation - hasUserGesture:(BOOL)hasUserGesture - rendererInitiated:(BOOL)rendererInitiated - placeholderNavigation:(BOOL)placeholderNavigation { - // Get the navigation type from the last main frame load request, and try to - // map that to a PageTransition. - WKNavigationType navigationType = - self.navigationHandler.pendingNavigationInfo - ? self.navigationHandler.pendingNavigationInfo.navigationType - : WKNavigationTypeOther; - ui::PageTransition transition = - [self.navigationHandler pageTransitionFromNavigationType:navigationType]; - - if (web::GetWebClient()->IsSlimNavigationManagerEnabled() && - navigationType == WKNavigationTypeBackForward && - self.webView.backForwardList.currentItem) { - web::NavigationItem* currentItem = [[CRWNavigationItemHolder - holderForBackForwardListItem:self.webView.backForwardList.currentItem] - navigationItem]; - if (currentItem) { - transition = ui::PageTransitionFromInt(transition | - currentItem->GetTransitionType()); - } - } - - // The referrer is not known yet, and will be updated later. - const web::Referrer emptyReferrer; - std::unique_ptr<web::NavigationContextImpl> context = - [self registerLoadRequestForURL:URL - referrer:emptyReferrer - transition:transition - sameDocumentNavigation:sameDocumentNavigation - hasUserGesture:hasUserGesture - rendererInitiated:rendererInitiated - placeholderNavigation:placeholderNavigation]; - context->SetWKNavigationType(navigationType); - return context; -} - -- (std::unique_ptr<web::NavigationContextImpl>) - registerLoadRequestForURL:(const GURL&)requestURL - referrer:(const web::Referrer&)referrer - transition:(ui::PageTransition)transition - sameDocumentNavigation:(BOOL)sameDocumentNavigation - hasUserGesture:(BOOL)hasUserGesture - rendererInitiated:(BOOL)rendererInitiated - placeholderNavigation:(BOOL)placeholderNavigation { - // Transfer time is registered so that further transitions within the time - // envelope are not also registered as links. - [_delegate - webRequestControllerUserInteractionState:self] -> ResetLastTransferTime(); - - // Add or update pending item before any WebStateObserver callbacks. - // See https://crbug.com/842151 for a scenario where this is important. - web::NavigationItem* item = - self.navigationManagerImpl->GetPendingItemInCurrentOrRestoredSession(); - if (item) { - // Update the existing pending entry. - // Typically on PAGE_TRANSITION_CLIENT_REDIRECT. - // Don't update if request is a placeholder entry because the pending item - // should have the original target URL. - // Don't update if pending URL has a different origin, because client - // redirects can not change the origin. It is possible to have more than one - // pending navigations, so the redirect does not necesserily belong to the - // pending navigation item. - if (!placeholderNavigation && - item->GetURL().GetOrigin() == requestURL.GetOrigin()) { - self.navigationManagerImpl->UpdatePendingItemUrl(requestURL); - } - } else { - self.navigationManagerImpl->AddPendingItem( - requestURL, referrer, transition, - rendererInitiated ? web::NavigationInitiationType::RENDERER_INITIATED - : web::NavigationInitiationType::BROWSER_INITIATED, - web::NavigationManager::UserAgentOverrideOption::INHERIT); - item = - self.navigationManagerImpl->GetPendingItemInCurrentOrRestoredSession(); - } - - bool redirect = transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK; - if (!redirect) { - // Before changing navigation state, the delegate should be informed that - // any existing request is being cancelled before completion. - [self.navigationHandler loadCancelled]; - DCHECK_EQ(web::WKNavigationState::FINISHED, - self.navigationHandler.navigationState); - } - - self.navigationHandler.navigationState = web::WKNavigationState::REQUESTED; - - // Record the state of outgoing web view. Do nothing if native controller - // exists, because in that case recordStateInHistory will record the state - // of incoming page as native controller is already inserted. - // TODO(crbug.com/811770) Don't record state under WKBasedNavigationManager - // because it may incorrectly clobber the incoming page if this is a - // back/forward navigation. WKWebView restores page scroll state for web view - // pages anyways so this only impacts user if WKWebView is deleted. - if (!redirect && - ![[_delegate webRequestControllerLegacyNativeContentController:self] - hasController] && - !web::GetWebClient()->IsSlimNavigationManagerEnabled()) { - [_delegate webRequestControllerRecordStateInHistory:self]; - } - - std::unique_ptr<web::NavigationContextImpl> context = - web::NavigationContextImpl::CreateNavigationContext( - self.webState, requestURL, hasUserGesture, transition, - rendererInitiated); - context->SetPlaceholderNavigation(placeholderNavigation); - - // TODO(crbug.com/676129): LegacyNavigationManagerImpl::AddPendingItem does - // not create a pending item in case of reload. Remove this workaround once - // the bug is fixed or WKBasedNavigationManager is fully adopted. - if (!item) { - DCHECK(!web::GetWebClient()->IsSlimNavigationManagerEnabled()); - item = self.navigationManagerImpl->GetLastCommittedItem(); - } - - context->SetNavigationItemUniqueID(item->GetUniqueID()); - context->SetIsPost([self.navigationHandler isCurrentNavigationItemPOST]); - context->SetIsSameDocument(sameDocumentNavigation); - - if (!IsWKInternalUrl(requestURL) && !placeholderNavigation) { - self.webState->SetIsLoading(true); - } - - // WKWebView may have multiple pending items. Move pending item ownership from - // NavigationManager to NavigationContext. NavigationManager owns pending item - // after navigation was requested and until NavigationContext is created. - // No need to transfer the ownership for NativeContent URLs, because the - // load of NativeContent is synchronous. No need to transfer the ownership - // for WebUI navigations, because those navigation do not have access to - // NavigationContext. - if (![[_delegate webRequestControllerLegacyNativeContentController:self] - shouldLoadURLInNativeView:context->GetUrl()]) { - if (self.navigationManagerImpl->GetPendingItemIndex() == -1) { - context->SetItem(self.navigationManagerImpl->ReleasePendingItem()); - } - } - - return context; -} - -- (void)didFinishWithURL:(const GURL&)currentURL - loadSuccess:(BOOL)loadSuccess - context:(nullable const web::NavigationContextImpl*)context { - DCHECK_EQ(web::WKNavigationState::FINISHED, - self.navigationHandler.navigationState); - - [_delegate webRequestControllerRestoreStateFromHistory:self]; - - // Placeholder and restore session URLs are implementation details so should - // not notify WebStateObservers. If |context| is nullptr, don't skip - // placeholder URLs because this may be the only opportunity to update - // |isLoading| for native view reload. - - if (context && context->IsPlaceholderNavigation()) - return; - - if (context && IsRestoreSessionUrl(context->GetUrl())) - return; - - if (IsRestoreSessionUrl(net::GURLWithNSURL(self.webView.URL))) - return; - - if (context && context->IsLoadingErrorPage()) - return; - - if (!loadSuccess) { - // WebStateObserver callbacks will be called for load failure after - // loading placeholder URL. - return; - } - - if (![self.navigationHandler.navigationStates - lastNavigationWithPendingItemInNavigationContext]) { - self.webState->SetIsLoading(false); - } else { - // There is another pending navigation, so the state is still loading. - } - self.webState->OnPageLoaded(currentURL, YES); -} - -// Reports Navigation.IOSWKWebViewSlowFastBackForward UMA. No-op if pending -// navigation is not back forward navigation. -- (void)reportBackForwardNavigationTypeForFastNavigation:(BOOL)isFast { - web::NavigationManager* navigationManager = self.navigationManagerImpl; - int pendingIndex = navigationManager->GetPendingItemIndex(); - if (pendingIndex == -1) { - // Pending navigation is not a back forward navigation. - return; - } - - BOOL isBack = pendingIndex < navigationManager->GetLastCommittedItemIndex(); - BackForwardNavigationType type = BackForwardNavigationType::FAST_BACK; - if (isBack) { - type = isFast ? BackForwardNavigationType::FAST_BACK - : BackForwardNavigationType::SLOW_BACK; - } else { - type = isFast ? BackForwardNavigationType::FAST_FORWARD - : BackForwardNavigationType::SLOW_FORWARD; - } - - UMA_HISTOGRAM_ENUMERATION( - "Navigation.IOSWKWebViewSlowFastBackForward", type, - BackForwardNavigationType::BACK_FORWARD_NAVIGATION_TYPE_COUNT); -} - // Returns a NSMutableURLRequest that represents the current NavigationItem. - (NSMutableURLRequest*)requestForCurrentNavigationItem { web::NavigationItem* item = self.currentNavItem; @@ -630,42 +808,7 @@ [list.backList indexOfObject:item] != NSNotFound; } -#pragma mark Navigation and Session Information - -// Returns the associated NavigationManagerImpl. -- (web::NavigationManagerImpl*)navigationManagerImpl { - return self.webState ? &(self.webState->GetNavigationManagerImpl()) : nil; -} - -// Returns the navigation item for the current page. -- (web::NavigationItemImpl*)currentNavItem { - return self.navigationManagerImpl - ? self.navigationManagerImpl->GetCurrentItemImpl() - : nullptr; -} - -// Returns the current transition type. -- (ui::PageTransition)currentTransition { - if (self.currentNavItem) - return self.currentNavItem->GetTransitionType(); - else - return ui::PageTransitionFromInt(0); -} - -// Returns the referrer for current navigation item. May be empty. -- (web::Referrer)currentNavItemReferrer { - web::NavigationItem* currentItem = self.currentNavItem; - return currentItem ? currentItem->GetReferrer() : web::Referrer(); -} - -// The HTTP headers associated with the current navigation item. These are nil -// unless the request was a POST. -- (NSDictionary*)currentHTTPHeaders { - web::NavigationItem* currentItem = self.currentNavItem; - return currentItem ? currentItem->GetHttpRequestHeaders() : nil; -} - -#pragma mark - Private methods +#pragma mark - Private properties - (WKWebView*)webView { return [_delegate webRequestControllerWebView:self]; @@ -675,4 +818,13 @@ return [_delegate webRequestControllerNavigationHandler:self]; } +- (CRWLegacyNativeContentController*)legacyNativeController { + return [_delegate webRequestControllerLegacyNativeContentController:self]; +} + +// Whether the associated WebState has an opener. +- (BOOL)hasOpener { + return self.webState ? self.webState->HasOpener() : NO; +} + @end
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc index b7ec367..be3b70c 100644 --- a/media/base/pipeline_impl.cc +++ b/media/base/pipeline_impl.cc
@@ -796,7 +796,10 @@ if (shared_state_.renderer && !renderer_ended_) return; - DCHECK_EQ(status_, PIPELINE_OK); + // Don't fire an ended event if we're already in an error state. + if (status_ != PIPELINE_OK) + return; + main_task_runner_->PostTask( FROM_HERE, base::BindOnce(&PipelineImpl::OnEnded, weak_pipeline_)); }
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index 3034da0e..09b3f26 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -678,15 +678,6 @@ ReportMetrics(load_type, loaded_url_, *frame_, media_log_.get()); - // Report poster availability for SRC=. - if (load_type == kLoadTypeURL) { - if (preload_ == MultibufferDataSource::METADATA) { - UMA_HISTOGRAM_BOOLEAN("Media.SRC.PreloadMetaDataHasPoster", has_poster_); - } else if (preload_ == MultibufferDataSource::AUTO) { - UMA_HISTOGRAM_BOOLEAN("Media.SRC.PreloadAutoHasPoster", has_poster_); - } - } - // Set subresource URL for crash reporting; will be truncated to 256 bytes. static base::debug::CrashKeyString* subresource_url = base::debug::AllocateCrashKeyString("subresource_url",
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index 843d4f54..94b782eb 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc
@@ -455,10 +455,7 @@ media_log_(media_log), duration_(kNoTimestamp), user_specified_duration_(-1), - liveness_(DemuxerStream::LIVENESS_UNKNOWN), - detected_audio_track_count_(0), - detected_video_track_count_(0), - detected_text_track_count_(0) { + liveness_(DemuxerStream::LIVENESS_UNKNOWN) { DCHECK(open_cb_); DCHECK(encrypted_media_init_data_cb_); MEDIA_LOG(INFO, media_log_) << GetDisplayName(); @@ -1265,24 +1262,11 @@ s->SetLiveness(params.liveness); } - detected_audio_track_count_ += params.detected_audio_track_count; - detected_video_track_count_ += params.detected_video_track_count; - detected_text_track_count_ += params.detected_text_track_count; - // Wait until all streams have initialized. pending_source_init_ids_.erase(source_id); if (!pending_source_init_ids_.empty()) return; - // Record detected track counts by type corresponding to an MSE playback. - // Counts are split into 50 buckets, capped into [0,100] range. - UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Audio", - detected_audio_track_count_); - UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Video", - detected_video_track_count_); - UMA_HISTOGRAM_COUNTS_100("Media.MSE.DetectedTrackCount.Text", - detected_text_track_count_); - for (const auto& s : video_streams_) { media_log_->RecordRapporWithSecurityOrigin( "Media.OriginUrl.MSE.VideoCodec." +
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h index f1951f01..4b4ac61 100644 --- a/media/filters/chunk_demuxer.h +++ b/media/filters/chunk_demuxer.h
@@ -523,11 +523,6 @@ // in a shut down state, so reading from them will return EOS. std::vector<std::unique_ptr<ChunkDemuxerStream>> removed_streams_; - // Accumulate, by type, detected track counts across the SourceBuffers. - int detected_audio_track_count_; - int detected_video_track_count_; - int detected_text_track_count_; - // Callback for reporting the number of bytes appended to this ChunkDemuxer. BytesReceivedCB bytes_received_cb_;
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 683a9c5a..7033eb4 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc
@@ -133,16 +133,6 @@ base::CustomHistogram::ArrayToCustomEnumRanges(kCommonAspectRatios100)); } -// Record detected track counts by type corresponding to a src= playback. -// Counts are split into 50 buckets, capped into [0,100] range. -static void RecordDetectedTrackTypeStats(int audio_count, - int video_count, - int text_count) { - UMA_HISTOGRAM_COUNTS_100("Media.DetectedTrackCount.Audio", audio_count); - UMA_HISTOGRAM_COUNTS_100("Media.DetectedTrackCount.Video", video_count); - UMA_HISTOGRAM_COUNTS_100("Media.DetectedTrackCount.Text", text_count); -} - // Record audio decoder config UMA stats corresponding to a src= playback. static void RecordAudioCodecStats(const AudioDecoderConfig& audio_config) { UMA_HISTOGRAM_ENUMERATION("Media.AudioCodec", audio_config.codec(), @@ -1300,9 +1290,6 @@ start_time_ = kInfiniteDuration; base::TimeDelta max_duration; - int detected_audio_track_count = 0; - int detected_video_track_count = 0; - int detected_text_track_count = 0; int supported_audio_track_count = 0; int supported_video_track_count = 0; bool has_opus_or_vorbis_audio = false; @@ -1327,8 +1314,6 @@ base::UmaHistogramSparse("Media.DetectedAudioCodecHash.Local", codec_hash); } - - detected_audio_track_count++; } else if (codec_type == AVMEDIA_TYPE_VIDEO) { // Log the codec detected, whether it is supported or not, and whether or // not we have already detected a supported codec in another stream. @@ -1338,7 +1323,6 @@ base::UmaHistogramSparse("Media.DetectedVideoCodecHash.Local", codec_hash); } - detected_video_track_count++; #if BUILDFLAG(ENABLE_HEVC_DEMUXING) if (codec_id == AV_CODEC_ID_HEVC) { @@ -1355,7 +1339,6 @@ } #endif } else if (codec_type == AVMEDIA_TYPE_SUBTITLE) { - detected_text_track_count++; stream->discard = AVDISCARD_ALL; continue; } else { @@ -1474,10 +1457,6 @@ streams_[i]->set_start_time(start_time); } - RecordDetectedTrackTypeStats(detected_audio_track_count, - detected_video_track_count, - detected_text_track_count); - if (media_tracks->tracks().empty()) { MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": no supported streams";
diff --git a/media/filters/stream_parser_factory.cc b/media/filters/stream_parser_factory.cc index 2f29cef3..9e29421 100644 --- a/media/filters/stream_parser_factory.cc +++ b/media/filters/stream_parser_factory.cc
@@ -524,8 +524,14 @@ if (CheckTypeAndCodecs(type, codecs, media_log, &factory_function, &audio_codecs, &video_codecs)) { - // Log the number of codecs specified, as well as the details on each one. - UMA_HISTOGRAM_COUNTS_100("Media.MSE.NumberOfTracks", codecs.size()); + // Log the expected codecs. + // TODO(wolenetz): Relocate the logging to the parser configuration + // callback. This creation method is called in AddId(), and also in + // CanChangeType() and ChangeType(), so potentially overlogs codecs leading + // to disproportion versus actually parsed codec configurations from + // initialization segments. For this work and also recording when implicit + // codec switching occurs (without explicit ChangeType), see + // https://crbug.com/535738. for (size_t i = 0; i < audio_codecs.size(); ++i) { UMA_HISTOGRAM_ENUMERATION("Media.MSE.AudioCodec", audio_codecs[i], CodecInfo::HISTOGRAM_MAX + 1);
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.cc b/media/gpu/v4l2/v4l2_slice_video_decoder.cc index ba40afef..29d94acb 100644 --- a/media/gpu/v4l2/v4l2_slice_video_decoder.cc +++ b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
@@ -12,6 +12,7 @@ #include "base/memory/ptr_util.h" #include "base/task/post_task.h" #include "media/base/scopedfd_helper.h" +#include "media/base/video_util.h" #include "media/gpu/accelerated_video_decoder.h" #include "media/gpu/chromeos/dmabuf_video_frame_pool.h" #include "media/gpu/gpu_video_decode_accelerator_helpers.h" @@ -377,9 +378,9 @@ base::BindOnce(std::move(init_cb), false)); return; } + pixel_aspect_ratio_ = config.GetPixelAspectRatio(); visible_rect_ = config.visible_rect(); - natural_size_ = config.natural_size(); - frame_pool_->SetFrameFormat(*frame_layout_, visible_rect_, natural_size_); + UpdateVideoFramePoolFormat(); // Create Input/Output V4L2Queue input_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); @@ -479,6 +480,11 @@ return true; } +void V4L2SliceVideoDecoder::UpdateVideoFramePoolFormat() { + gfx::Size natural_size = GetNaturalSize(visible_rect_, pixel_aspect_ratio_); + frame_pool_->SetFrameFormat(*frame_layout_, visible_rect_, natural_size); +} + void V4L2SliceVideoDecoder::Reset(base::OnceClosure closure) { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); DVLOGF(3); @@ -680,7 +686,8 @@ scoped_refptr<V4L2DecodeSurface> surface = std::move(request.surface); DCHECK(surface->video_frame()); - RunOutputCB(surface->video_frame(), request.timestamp); + RunOutputCB(surface->video_frame(), surface->visible_rect(), + request.timestamp); break; } } @@ -735,9 +742,14 @@ return false; } frame_layout_ = VideoFrameLayout::Create(frame_layout_->format(), coded_size); - frame_pool_->SetFrameFormat(*frame_layout_, visible_rect_, natural_size_); + DCHECK(frame_layout_); + + visible_rect_ = avd_->GetVisibleRect(); + UpdateVideoFramePoolFormat(); // Allocate new output buffers. + if (!output_queue_->DeallocateBuffers()) + return false; size_t num_output_frames = avd_->GetRequiredNumOfPictures(); DCHECK_GT(num_output_frames, 0u); if (output_queue_->AllocateBuffers(num_output_frames, V4L2_MEMORY_DMABUF) == @@ -868,14 +880,17 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); DVLOGF(3); + if (visible_rect_ != visible_rect) { + visible_rect_ = visible_rect; + UpdateVideoFramePoolFormat(); + } + auto it = bitstream_id_to_timestamp_.find(bitstream_id); DCHECK(it != bitstream_id_to_timestamp_.end()); base::TimeDelta timestamp = it->second; bitstream_id_to_timestamp_.erase(it); - // TODO(akahuang): Update visible_rect at the output frame. dec_surface->SetVisibleRect(visible_rect); - output_request_queue_.push( OutputRequest::Surface(std::move(dec_surface), timestamp)); PumpOutputSurfaces(); @@ -1057,14 +1072,20 @@ } void V4L2SliceVideoDecoder::RunOutputCB(scoped_refptr<VideoFrame> frame, + const gfx::Rect& visible_rect, base::TimeDelta timestamp) { DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); DVLOGF(4) << "timestamp: " << timestamp; - // The attribute of the frame is needed to update. Wrap the frame again. - if (frame->timestamp() != timestamp) { + // We need to update one or more attributes of the frame. Since we can't + // modify the attributes of the frame directly, we wrap the frame into a new + // frame with updated attributes. The old frame is bound to a destruction + // observer so it's not destroyed before the wrapped frame. + if (frame->visible_rect() != visible_rect || + frame->timestamp() != timestamp) { + gfx::Size natural_size = GetNaturalSize(visible_rect, pixel_aspect_ratio_); scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame( - *frame, frame->format(), frame->visible_rect(), frame->natural_size()); + *frame, frame->format(), visible_rect, natural_size); wrapped_frame->set_timestamp(timestamp); wrapped_frame->AddDestructionObserver(base::BindOnce( base::DoNothing::Once<scoped_refptr<VideoFrame>>(), std::move(frame)));
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.h b/media/gpu/v4l2/v4l2_slice_video_decoder.h index acb2d062..a024d99 100644 --- a/media/gpu/v4l2/v4l2_slice_video_decoder.h +++ b/media/gpu/v4l2/v4l2_slice_video_decoder.h
@@ -15,10 +15,12 @@ #include "base/containers/queue.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" #include "base/threading/thread.h" #include "media/base/video_decoder.h" +#include "media/base/video_frame_layout.h" #include "media/base/video_types.h" #include "media/gpu/media_gpu_export.h" #include "media/gpu/v4l2/v4l2_decode_surface_handler.h" @@ -143,6 +145,8 @@ uint32_t NegotiateOutputFormat(); // Setup format for V4L2 output buffers. bool SetupOutputFormat(uint32_t output_format_fourcc); + // Update the format of frames in |frame_pool_|. + void UpdateVideoFramePoolFormat(); // Destroy on decoder thread. void DestroyTask(); @@ -188,7 +192,9 @@ // Get the next bitsream ID. int32_t GetNextBitstreamId(); // Convert the frame and call the output callback. - void RunOutputCB(scoped_refptr<VideoFrame> frame, base::TimeDelta timestamp); + void RunOutputCB(scoped_refptr<VideoFrame> frame, + const gfx::Rect& visible_rect, + base::TimeDelta timestamp); // Call the decode callback and count the number of pending callbacks. void RunDecodeCB(DecodeCB cb, DecodeStatus status); // Change the state and check the state transition is valid. @@ -220,7 +226,9 @@ // Parameters for generating output VideoFrame. base::Optional<VideoFrameLayout> frame_layout_; gfx::Rect visible_rect_; - gfx::Size natural_size_; + // Ratio of natural_size to visible_rect of the output frame. + double pixel_aspect_ratio_; + // Callbacks passed from Initialize(). OutputCB output_cb_; // Callbacks of EOS buffer passed from Decode().
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc index e5ad316..d3be4e9 100644 --- a/media/gpu/vaapi/vaapi_video_decoder.cc +++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -12,6 +12,7 @@ #include "base/memory/ptr_util.h" #include "media/base/bind_to_current_loop.h" #include "media/base/video_frame.h" +#include "media/base/video_util.h" #include "media/gpu/chromeos/dmabuf_video_frame_pool.h" #include "media/gpu/chromeos/platform_video_frame_utils.h" #include "media/gpu/format_utils.h" @@ -231,7 +232,7 @@ needs_bitstream_conversion_ = (config.codec() == kCodecH264); visible_rect_ = config.visible_rect(); - natural_size_ = config.natural_size(); + pixel_aspect_ratio_ = config.GetPixelAspectRatio(); profile_ = profile; output_cb_ = std::move(output_cb); @@ -459,12 +460,20 @@ void VaapiVideoDecoder::SurfaceReady(const scoped_refptr<VASurface>& va_surface, int32_t /*buffer_id*/, - const gfx::Rect& /*visible_rect*/, + const gfx::Rect& visible_rect, const VideoColorSpace& /*color_space*/) { DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); DCHECK_EQ(state_, State::kDecoding); DVLOGF(3); + // In some rare cases it's possible the frame's visible rectangle is different + // from what the decoder asked us to create in the last resolution change. + if (visible_rect_ != visible_rect) { + visible_rect_ = visible_rect; + gfx::Size natural_size = GetNaturalSize(visible_rect_, pixel_aspect_ratio_); + frame_pool_->SetFrameFormat(*frame_layout_, visible_rect_, natural_size); + } + // Find the frame associated with the surface. We won't erase it from // |output_frames_| yet, as the decoder might still be using it for reference. DCHECK_EQ(output_frames_.count(va_surface->id()), 1u); @@ -477,6 +486,21 @@ DCHECK(video_frame); DVLOGF(4); + // We need to update one or more attributes of the frame. Since we can't + // modify the attributes of the frame directly, we wrap the frame into a new + // frame with updated attributes. The old frame is bound to a destruction + // observer so it's not destroyed before the wrapped frame. + if (video_frame->visible_rect() != visible_rect_) { + gfx::Size natural_size = GetNaturalSize(visible_rect_, pixel_aspect_ratio_); + scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame( + *video_frame, video_frame->format(), visible_rect_, natural_size); + wrapped_frame->AddDestructionObserver( + base::BindOnce(base::DoNothing::Once<scoped_refptr<VideoFrame>>(), + std::move(video_frame))); + + video_frame = std::move(wrapped_frame); + } + scoped_refptr<VideoFrame> converted_frame = frame_converter_->ConvertFrame(video_frame); if (!converted_frame) { @@ -499,14 +523,14 @@ VLOGF(2); // TODO(hiroh): Handle profile changes. - // TODO(dstaessens): Update natural size after submitting crrev.com/c/1657871. visible_rect_ = decoder_->GetVisibleRect(); - natural_size_ = visible_rect_.size(); + gfx::Size natural_size = GetNaturalSize(visible_rect_, pixel_aspect_ratio_); gfx::Size pic_size = decoder_->GetPicSize(); const VideoPixelFormat format = GfxBufferFormatToVideoPixelFormat(GetBufferFormat()); - auto frame_layout = VideoFrameLayout::Create(format, pic_size); - frame_pool_->SetFrameFormat(*frame_layout, visible_rect_, natural_size_); + frame_layout_ = VideoFrameLayout::Create(format, pic_size); + DCHECK(frame_layout_); + frame_pool_->SetFrameFormat(*frame_layout_, visible_rect_, natural_size); frame_pool_->SetMaxNumFrames(decoder_->GetRequiredNumOfPictures()); // All pending decode operations will be completed before triggering a
diff --git a/media/gpu/vaapi/vaapi_video_decoder.h b/media/gpu/vaapi/vaapi_video_decoder.h index 94bbc02..0028f5c 100644 --- a/media/gpu/vaapi/vaapi_video_decoder.h +++ b/media/gpu/vaapi/vaapi_video_decoder.h
@@ -17,10 +17,12 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "base/sequence_checker.h" #include "base/threading/thread.h" #include "media/base/video_codecs.h" #include "media/base/video_decoder.h" +#include "media/base/video_frame_layout.h" #include "media/gpu/decode_surface_handler.h" #include "media/video/supported_video_decoder_config.h" #include "ui/gfx/geometry/rect.h" @@ -165,8 +167,10 @@ bool needs_bitstream_conversion_ = false; // Output frame properties. + base::Optional<VideoFrameLayout> frame_layout_; gfx::Rect visible_rect_; - gfx::Size natural_size_; + // Ratio of natural size to |visible_rect_| of the output frames. + double pixel_aspect_ratio_ = 0.0; // Video frame pool used to allocate and recycle video frames. std::unique_ptr<DmabufVideoFramePool> frame_pool_;
diff --git a/media/gpu/windows/d3d11_texture_selector.cc b/media/gpu/windows/d3d11_texture_selector.cc index 3789d17..b248418 100644 --- a/media/gpu/windows/d3d11_texture_selector.cc +++ b/media/gpu/windows/d3d11_texture_selector.cc
@@ -6,6 +6,8 @@ #include <d3d11.h> +#include "base/feature_list.h" +#include "media/base/media_switches.h" #include "media/gpu/windows/d3d11_copying_texture_wrapper.h" #include "ui/gfx/geometry/size.h" @@ -27,35 +29,53 @@ SetUpTextureDescriptor(); } +bool SupportsZeroCopy(const gpu::GpuPreferences& preferences, + const gpu::GpuDriverBugWorkarounds& workarounds) { + if (!preferences.enable_zero_copy_dxgi_video) + return false; + + if (!base::FeatureList::IsEnabled(kD3D11VideoDecoderIgnoreWorkarounds)) + if (workarounds.disable_dxgi_zero_copy_video) + return false; + + return true; +} + // static std::unique_ptr<TextureSelector> TextureSelector::Create( + const gpu::GpuPreferences& gpu_preferences, + const gpu::GpuDriverBugWorkarounds& workarounds, const VideoDecoderConfig& config) { - // TODO(tmathmeyer) use a CopyTextureSelector - if (config.profile() == VP9PROFILE_PROFILE2) { - return std::make_unique<TextureSelector>( - PIXEL_FORMAT_YUV420P10, DXGI_FORMAT_P010, - D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2, config.coded_size(), - config.is_encrypted(), false); - } - bool supports_nv12_decode_swap_chain = base::FeatureList::IsEnabled( features::kDirectCompositionUseNV12DecodeSwapChain); + bool needs_texture_copy = !SupportsZeroCopy(gpu_preferences, workarounds); - if (config.profile() == VP9PROFILE_PROFILE0) { - return std::make_unique<TextureSelector>( - PIXEL_FORMAT_NV12, DXGI_FORMAT_NV12, - D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0, config.coded_size(), - config.is_encrypted(), supports_nv12_decode_swap_chain); - } - + DXGI_FORMAT input_dxgi_format = DXGI_FORMAT_NV12; + DXGI_FORMAT output_dxgi_format = DXGI_FORMAT_NV12; + GUID decoder_guid = {}; if (config.codec() == kCodecH264) { - return std::make_unique<TextureSelector>( - PIXEL_FORMAT_NV12, DXGI_FORMAT_NV12, - D3D11_DECODER_PROFILE_H264_VLD_NOFGT, config.coded_size(), - config.is_encrypted(), supports_nv12_decode_swap_chain); + decoder_guid = D3D11_DECODER_PROFILE_H264_VLD_NOFGT; + } else if (config.profile() == VP9PROFILE_PROFILE0) { + decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0; + } else if (config.profile() == VP9PROFILE_PROFILE2) { + decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2; + input_dxgi_format = DXGI_FORMAT_P010; + } else { + // TODO(tmathmeyer) support other profiles in the future. + return nullptr; } - return nullptr; + if ((input_dxgi_format != output_dxgi_format) || needs_texture_copy) { + return std::make_unique<CopyTextureSelector>( + PIXEL_FORMAT_NV12, input_dxgi_format, output_dxgi_format, decoder_guid, + config.coded_size(), config.is_encrypted(), + supports_nv12_decode_swap_chain); // TODO(tmathmeyer) false always? + } else { + return std::make_unique<TextureSelector>( + PIXEL_FORMAT_NV12, output_dxgi_format, decoder_guid, + config.coded_size(), config.is_encrypted(), + supports_nv12_decode_swap_chain); + } } bool TextureSelector::SupportsDevice( @@ -131,6 +151,7 @@ D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; texture_desc_.ArraySize = 1; texture_desc_.CPUAccessFlags = 0; + texture_desc_.Format = output_dxgifmt_; ComD3D11Texture2D out_texture = CreateOutputTexture(device, size); if (!out_texture)
diff --git a/media/gpu/windows/d3d11_texture_selector.h b/media/gpu/windows/d3d11_texture_selector.h index f54d52f0..c828bf7 100644 --- a/media/gpu/windows/d3d11_texture_selector.h +++ b/media/gpu/windows/d3d11_texture_selector.h
@@ -30,6 +30,8 @@ virtual ~TextureSelector() = default; static std::unique_ptr<TextureSelector> Create( + const gpu::GpuPreferences& gpu_preferences, + const gpu::GpuDriverBugWorkarounds& workarounds, const VideoDecoderConfig& config); bool SupportsDevice(Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device); @@ -67,17 +69,19 @@ class MEDIA_GPU_EXPORT CopyTextureSelector : public TextureSelector { public: CopyTextureSelector(VideoPixelFormat pixfmt, - DXGI_FORMAT dxgifmt, + DXGI_FORMAT input_dxgifmt, + DXGI_FORMAT output_dxgifmt, GUID decoder_guid, gfx::Size coded_size, bool is_encrypted, bool supports_swap_chain) : TextureSelector(pixfmt, - dxgifmt, + input_dxgifmt, decoder_guid, coded_size, is_encrypted, - supports_swap_chain) {} + supports_swap_chain), + output_dxgifmt_(output_dxgifmt) {} std::unique_ptr<Texture2DWrapper> CreateTextureWrapper( ComD3D11Device device, @@ -85,6 +89,9 @@ ComD3D11DeviceContext, ComD3D11Texture2D input_texture, gfx::Size size) override; + + private: + DXGI_FORMAT output_dxgifmt_; }; } // namespace media
diff --git a/media/gpu/windows/d3d11_texture_selector_unittest.cc b/media/gpu/windows/d3d11_texture_selector_unittest.cc index a132094..2679128c 100644 --- a/media/gpu/windows/d3d11_texture_selector_unittest.cc +++ b/media/gpu/windows/d3d11_texture_selector_unittest.cc
@@ -34,10 +34,20 @@ pattern)); return result; } + + std::unique_ptr<TextureSelector> CreateWithDefaultGPUInfo( + const VideoDecoderConfig& config, + bool zero_copy_enabled = true) { + gpu::GpuPreferences prefs; + prefs.enable_zero_copy_dxgi_video = zero_copy_enabled; + gpu::GpuDriverBugWorkarounds workarounds; + workarounds.disable_dxgi_zero_copy_video = false; + return TextureSelector::Create(prefs, workarounds, config); + } }; TEST_F(D3D11TextureSelectorUnittest, VP9Profile0RightFormats) { - auto tex_sel = TextureSelector::Create( + auto tex_sel = CreateWithDefaultGPUInfo( CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false)); EXPECT_EQ(tex_sel->DecoderGuid(), D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0); @@ -45,8 +55,18 @@ EXPECT_EQ(tex_sel->DecoderDescriptor()->OutputFormat, DXGI_FORMAT_NV12); } +TEST_F(D3D11TextureSelectorUnittest, VP9Profile2RightFormats) { + auto tex_sel = CreateWithDefaultGPUInfo( + CreateDecoderConfig(VP9PROFILE_PROFILE2, {0, 0}, false), false); + + EXPECT_EQ(tex_sel->DecoderGuid(), + D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2); + EXPECT_EQ(tex_sel->PixelFormat(), PIXEL_FORMAT_NV12); + EXPECT_EQ(tex_sel->DecoderDescriptor()->OutputFormat, DXGI_FORMAT_P010); +} + TEST_F(D3D11TextureSelectorUnittest, SupportsDeviceNoProfiles) { - auto tex_sel = TextureSelector::Create( + auto tex_sel = CreateWithDefaultGPUInfo( CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false)); auto vd_mock = CreateD3D11Mock<D3D11VideoDeviceMock>(); @@ -58,7 +78,7 @@ } TEST_F(D3D11TextureSelectorUnittest, SupportsDeviceWrongProfiles) { - auto tex_sel = TextureSelector::Create( + auto tex_sel = CreateWithDefaultGPUInfo( CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false)); auto vd_mock = CreateD3D11Mock<D3D11VideoDeviceMock>(); @@ -78,7 +98,7 @@ } TEST_F(D3D11TextureSelectorUnittest, SupportsDeviceCorrectProfile) { - auto tex_sel = TextureSelector::Create( + auto tex_sel = CreateWithDefaultGPUInfo( CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false)); auto vd_mock = CreateD3D11Mock<D3D11VideoDeviceMock>();
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc index 29cbc67..a14c0e1 100644 --- a/media/gpu/windows/d3d11_video_decoder.cc +++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -6,6 +6,7 @@ #include <d3d11_4.h> #include <memory> +#include <utility> #include "base/bind.h" #include "base/callback.h" @@ -243,7 +244,8 @@ return; } - texture_selector_ = TextureSelector::Create(config); + texture_selector_ = + TextureSelector::Create(gpu_preferences_, gpu_workarounds_, config); if (!texture_selector_) { NotifyError("D3DD11: Config provided unsupported profile"); return; @@ -711,16 +713,16 @@ GetD3D11DeviceCB get_d3d11_device_cb) { const std::string uma_name("Media.D3D11.WasVideoSupported"); - // Must allow zero-copy of nv12 textures. - if (!gpu_preferences.enable_zero_copy_dxgi_video) { - UMA_HISTOGRAM_ENUMERATION(uma_name, - NotSupportedReason::kZeroCopyNv12Required); - return {}; - } - // This workaround accounts for almost half of all startup results, and it's // unclear that it's relevant here. if (!base::FeatureList::IsEnabled(kD3D11VideoDecoderIgnoreWorkarounds)) { + // Must allow zero-copy of nv12 textures. + if (!gpu_preferences.enable_zero_copy_dxgi_video) { + UMA_HISTOGRAM_ENUMERATION(uma_name, + NotSupportedReason::kZeroCopyNv12Required); + return {}; + } + if (gpu_workarounds.disable_dxgi_zero_copy_video) { UMA_HISTOGRAM_ENUMERATION(uma_name, NotSupportedReason::kZeroCopyVideoRequired);
diff --git a/media/gpu/windows/d3d11_video_decoder_unittest.cc b/media/gpu/windows/d3d11_video_decoder_unittest.cc index b48e167..ba940fe 100644 --- a/media/gpu/windows/d3d11_video_decoder_unittest.cc +++ b/media/gpu/windows/d3d11_video_decoder_unittest.cc
@@ -16,6 +16,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/win/scoped_com_initializer.h" #include "media/base/decoder_buffer.h" #include "media/base/media_log.h" #include "media/base/media_switches.h" @@ -215,6 +216,7 @@ Microsoft::WRL::ComPtr<D3D11VideoContextMock> mock_d3d11_video_context_; base::Optional<base::test::ScopedFeatureList> scoped_feature_list_; + base::win::ScopedCOMInitializer com_initializer_; }; TEST_F(D3D11VideoDecoderTest, SupportsVP9Profile0WithDecoderEnabled) { @@ -272,22 +274,6 @@ InitializeDecoder(normal, kExpectFailure); } -TEST_F(D3D11VideoDecoderTest, RequiresZeroCopyPreference) { - gpu_preferences_.enable_zero_copy_dxgi_video = false; - CreateDecoder(); - InitializeDecoder( - TestVideoConfig::NormalCodecProfile(kCodecH264, H264PROFILE_MAIN), - kExpectFailure); -} - -TEST_F(D3D11VideoDecoderTest, FailsIfZeroCopyWorkaround) { - gpu_workarounds_.disable_dxgi_zero_copy_video = true; - CreateDecoder(); - InitializeDecoder( - TestVideoConfig::NormalCodecProfile(kCodecH264, H264PROFILE_MAIN), - kExpectFailure); -} - TEST_F(D3D11VideoDecoderTest, DoesNotSupportEncryptionWithoutFlag) { CreateDecoder(); VideoDecoderConfig encrypted_config = @@ -298,6 +284,40 @@ InitializeDecoder(encrypted_config, kExpectFailure); } +TEST_F(D3D11VideoDecoderTest, DoesNotSupportZeroCopyPreference) { + gpu_preferences_.enable_zero_copy_dxgi_video = false; + CreateDecoder(); + InitializeDecoder( + TestVideoConfig::NormalCodecProfile(kCodecH264, H264PROFILE_MAIN), + kExpectFailure); +} + +TEST_F(D3D11VideoDecoderTest, DoesNotSupportZeroCopyWorkaround) { + gpu_workarounds_.disable_dxgi_zero_copy_video = true; + CreateDecoder(); + InitializeDecoder( + TestVideoConfig::NormalCodecProfile(kCodecH264, H264PROFILE_MAIN), + kExpectFailure); +} + +TEST_F(D3D11VideoDecoderTest, SupportsZeroCopyPreferenceWithFlag) { + EnableFeature(kD3D11VideoDecoderIgnoreWorkarounds); + gpu_preferences_.enable_zero_copy_dxgi_video = false; + CreateDecoder(); + InitializeDecoder( + TestVideoConfig::NormalCodecProfile(kCodecH264, H264PROFILE_MAIN), + kExpectSuccess); +} + +TEST_F(D3D11VideoDecoderTest, SupportsZeroCopyWorkaroundWithFlag) { + EnableFeature(kD3D11VideoDecoderIgnoreWorkarounds); + gpu_workarounds_.disable_dxgi_zero_copy_video = true; + CreateDecoder(); + InitializeDecoder( + TestVideoConfig::NormalCodecProfile(kCodecH264, H264PROFILE_MAIN), + kExpectSuccess); +} + TEST_F(D3D11VideoDecoderTest, DoesNotSupportEncryptionWithFlagOn11_0) { CreateDecoder(); VideoDecoderConfig encrypted_config =
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc index ac19233f..91449c52 100644 --- a/media/renderers/paint_canvas_video_renderer.cc +++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -307,6 +307,9 @@ << mailbox_holder.texture_target; gpu::gles2::GLES2Interface* gl = context_provider->ContextGL(); + gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); + GLuint frame_texture = + gl->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name); unsigned source_texture = 0; gfx::ColorSpace color_space_for_skia; *wrapped_video_frame_texture = @@ -314,9 +317,7 @@ if (*wrapped_video_frame_texture) { // Fast path where we can avoid a copy, by having last_image_ directly wrap // the VideoFrame texture. - gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); - source_texture = - gl->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name); + source_texture = frame_texture; color_space_for_skia = video_frame->ColorSpace(); } else { // TODO(dcastagna): At the moment Skia doesn't support targets different @@ -326,9 +327,9 @@ gl->GenTextures(1, &source_texture); DCHECK(source_texture); gl->BindTexture(GL_TEXTURE_2D, source_texture); - PaintCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( - gl, video_frame, GL_TEXTURE_2D, source_texture, GL_RGBA, GL_RGBA, - GL_UNSIGNED_BYTE, 0, false, false); + gl->CopyTextureCHROMIUM(frame_texture, 0, GL_TEXTURE_2D, source_texture, 0, + GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); + gl->DeleteTextures(1, &frame_texture); } GrGLTextureInfo source_texture_info; source_texture_info.fID = source_texture;
diff --git a/media/renderers/paint_canvas_video_renderer_unittest.cc b/media/renderers/paint_canvas_video_renderer_unittest.cc index 35c5b757..e94736c 100644 --- a/media/renderers/paint_canvas_video_renderer_unittest.cc +++ b/media/renderers/paint_canvas_video_renderer_unittest.cc
@@ -18,6 +18,7 @@ #include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/gles2_interface_stub.h" #include "gpu/command_buffer/common/capabilities.h" +#include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/config/gpu_feature_info.h" #include "media/base/timestamp_constants.h" #include "media/base/video_frame.h" @@ -66,6 +67,274 @@ static_cast<uint8_t*>(external_memory), byte_size, timestamp); } +// Destroys a list of shared images after a sync token is passed. Also runs +// |callback|. +static void DestroySharedImages( + scoped_refptr<viz::ContextProvider> context_provider, + std::vector<gpu::Mailbox> mailboxes, + base::OnceClosure callback, + const gpu::SyncToken& sync_token) { + auto* sii = context_provider->SharedImageInterface(); + for (const auto& mailbox : mailboxes) + sii->DestroySharedImage(sync_token, mailbox); + std::move(callback).Run(); +} + +// Creates a video frame from a set of shared images with a common texture +// target and sync token. +static scoped_refptr<VideoFrame> CreateSharedImageFrame( + scoped_refptr<viz::ContextProvider> context_provider, + VideoPixelFormat format, + std::vector<gpu::Mailbox> mailboxes, + const gpu::SyncToken& sync_token, + GLenum texture_target, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size, + base::TimeDelta timestamp, + base::OnceClosure destroyed_callback) { + gpu::MailboxHolder mailboxes_for_frame[VideoFrame::kMaxPlanes] = {}; + size_t i = 0; + for (const auto& mailbox : mailboxes) { + mailboxes_for_frame[i++] = + gpu::MailboxHolder(mailbox, sync_token, texture_target); + } + auto callback = + base::BindOnce(&DestroySharedImages, std::move(context_provider), + std::move(mailboxes), std::move(destroyed_callback)); + return VideoFrame::WrapNativeTextures(format, mailboxes_for_frame, + std::move(callback), coded_size, + visible_rect, natural_size, timestamp); +} + +// Upload pixels to a shared image using GL. +static void UploadPixels(gpu::gles2::GLES2Interface* gl, + const gpu::Mailbox& mailbox, + const gfx::Size& size, + GLenum format, + GLenum type, + const uint8_t* data) { + GLuint texture = gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name); + gl->BeginSharedImageAccessDirectCHROMIUM( + texture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM); + gl->BindTexture(GL_TEXTURE_2D, texture); + gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(), format, + type, data); + gl->EndSharedImageAccessDirectCHROMIUM(texture); + gl->DeleteTextures(1, &texture); +} + +// Creates a shared image backed frame in RGBA format, with colors on the shared +// image mapped as follow. +// Bk | R | G | Y +// ---+---+---+--- +// Bl | M | C | W +static scoped_refptr<VideoFrame> CreateSharedImageRGBAFrame( + scoped_refptr<viz::ContextProvider> context_provider, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + base::OnceClosure destroyed_callback) { + DCHECK_EQ(coded_size.width() % 4, 0); + DCHECK_EQ(coded_size.height() % 2, 0); + size_t pixels_size = coded_size.GetArea() * 4; + auto pixels = std::make_unique<uint8_t[]>(pixels_size); + size_t i = 0; + for (size_t block_y = 0; block_y < 2u; ++block_y) { + for (int y = 0; y < coded_size.height() / 2; ++y) { + for (size_t block_x = 0; block_x < 4u; ++block_x) { + for (int x = 0; x < coded_size.width() / 4; ++x) { + pixels[i++] = 0xffu * (block_x % 2); // R + pixels[i++] = 0xffu * (block_x / 2); // G + pixels[i++] = 0xffu * block_y; // B + pixels[i++] = 0xffu; // A + } + } + } + } + DCHECK_EQ(i, pixels_size); + + auto* sii = context_provider->SharedImageInterface(); + gpu::Mailbox mailbox = + sii->CreateSharedImage(viz::ResourceFormat::RGBA_8888, coded_size, + gfx::ColorSpace(), gpu::SHARED_IMAGE_USAGE_GLES2); + auto* gl = context_provider->ContextGL(); + gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); + UploadPixels(gl, mailbox, coded_size, GL_RGBA, GL_UNSIGNED_BYTE, + pixels.get()); + gpu::SyncToken sync_token; + gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData()); + + return CreateSharedImageFrame( + std::move(context_provider), VideoPixelFormat::PIXEL_FORMAT_ABGR, + {mailbox}, sync_token, GL_TEXTURE_2D, coded_size, visible_rect, + visible_rect.size(), base::TimeDelta::FromSeconds(1), + std::move(destroyed_callback)); +} + +static constexpr const uint8_t kYuvColors[8][3] = { + {0x00, 0x80, 0x80}, // Black + {0x4c, 0x54, 0xff}, // Red + {0x95, 0x2b, 0x15}, // Green + {0xe1, 0x00, 0x94}, // Yellow + {0x1d, 0xff, 0x6b}, // Blue + {0x69, 0xd3, 0xec}, // Magenta + {0xb3, 0xaa, 0x00}, // Cyan + {0xff, 0x80, 0x80}, // White +}; + +// Creates a shared image backed frame in I420 format, with colors mapped +// exactly like CreateSharedImageRGBAFrame above, noting that subsamples may get +// interpolated leading to inconsistent colors around the "seams". +static scoped_refptr<VideoFrame> CreateSharedImageI420Frame( + scoped_refptr<viz::ContextProvider> context_provider, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + base::OnceClosure destroyed_callback) { + DCHECK_EQ(coded_size.width() % 8, 0); + DCHECK_EQ(coded_size.height() % 4, 0); + gfx::Size uv_size(coded_size.width() / 2, coded_size.height() / 2); + size_t y_pixels_size = coded_size.GetArea(); + size_t uv_pixels_size = uv_size.GetArea(); + auto y_pixels = std::make_unique<uint8_t[]>(y_pixels_size); + auto u_pixels = std::make_unique<uint8_t[]>(uv_pixels_size); + auto v_pixels = std::make_unique<uint8_t[]>(uv_pixels_size); + size_t y_i = 0; + size_t uv_i = 0; + for (size_t block_y = 0; block_y < 2u; ++block_y) { + for (int y = 0; y < coded_size.height() / 2; ++y) { + for (size_t block_x = 0; block_x < 4u; ++block_x) { + size_t color_index = block_x + block_y * 4; + const uint8_t* yuv = kYuvColors[color_index]; + for (int x = 0; x < coded_size.width() / 4; ++x) { + y_pixels[y_i++] = yuv[0]; + if ((x % 2) && (y % 2)) { + u_pixels[uv_i] = yuv[1]; + v_pixels[uv_i++] = yuv[2]; + } + } + } + } + } + DCHECK_EQ(y_i, y_pixels_size); + DCHECK_EQ(uv_i, uv_pixels_size); + + auto* sii = context_provider->SharedImageInterface(); + gpu::Mailbox y_mailbox = + sii->CreateSharedImage(viz::ResourceFormat::LUMINANCE_8, coded_size, + gfx::ColorSpace(), gpu::SHARED_IMAGE_USAGE_GLES2); + gpu::Mailbox u_mailbox = + sii->CreateSharedImage(viz::ResourceFormat::LUMINANCE_8, uv_size, + gfx::ColorSpace(), gpu::SHARED_IMAGE_USAGE_GLES2); + gpu::Mailbox v_mailbox = + sii->CreateSharedImage(viz::ResourceFormat::LUMINANCE_8, uv_size, + gfx::ColorSpace(), gpu::SHARED_IMAGE_USAGE_GLES2); + auto* gl = context_provider->ContextGL(); + gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); + UploadPixels(gl, y_mailbox, coded_size, GL_LUMINANCE, GL_UNSIGNED_BYTE, + y_pixels.get()); + UploadPixels(gl, u_mailbox, uv_size, GL_LUMINANCE, GL_UNSIGNED_BYTE, + u_pixels.get()); + UploadPixels(gl, v_mailbox, uv_size, GL_LUMINANCE, GL_UNSIGNED_BYTE, + v_pixels.get()); + gpu::SyncToken sync_token; + gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData()); + + return CreateSharedImageFrame( + std::move(context_provider), VideoPixelFormat::PIXEL_FORMAT_I420, + {y_mailbox, u_mailbox, v_mailbox}, sync_token, GL_TEXTURE_2D, coded_size, + visible_rect, visible_rect.size(), base::TimeDelta::FromSeconds(1), + std::move(destroyed_callback)); +} + +// Creates a shared image backed frame in NV12 format, with colors mapped +// exactly like CreateSharedImageRGBAFrame above. +// This will return nullptr if the necessary extension is not available for NV12 +// support. +static scoped_refptr<VideoFrame> CreateSharedImageNV12Frame( + scoped_refptr<viz::ContextProvider> context_provider, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + base::OnceClosure destroyed_callback) { + DCHECK_EQ(coded_size.width() % 8, 0); + DCHECK_EQ(coded_size.height() % 4, 0); + if (!context_provider->ContextCapabilities().texture_rg) + return {}; + gfx::Size uv_size(coded_size.width() / 2, coded_size.height() / 2); + size_t y_pixels_size = coded_size.GetArea(); + size_t uv_pixels_size = uv_size.GetArea() * 2; + auto y_pixels = std::make_unique<uint8_t[]>(y_pixels_size); + auto uv_pixels = std::make_unique<uint8_t[]>(uv_pixels_size); + size_t y_i = 0; + size_t uv_i = 0; + for (size_t block_y = 0; block_y < 2u; ++block_y) { + for (int y = 0; y < coded_size.height() / 2; ++y) { + for (size_t block_x = 0; block_x < 4u; ++block_x) { + size_t color_index = block_x + block_y * 4; + const uint8_t* yuv = kYuvColors[color_index]; + for (int x = 0; x < coded_size.width() / 4; ++x) { + y_pixels[y_i++] = yuv[0]; + if ((x % 2) && (y % 2)) { + uv_pixels[uv_i++] = yuv[1]; + uv_pixels[uv_i++] = yuv[2]; + } + } + } + } + } + DCHECK_EQ(y_i, y_pixels_size); + DCHECK_EQ(uv_i, uv_pixels_size); + + auto* sii = context_provider->SharedImageInterface(); + gpu::Mailbox y_mailbox = + sii->CreateSharedImage(viz::ResourceFormat::LUMINANCE_8, coded_size, + gfx::ColorSpace(), gpu::SHARED_IMAGE_USAGE_GLES2); + gpu::Mailbox uv_mailbox = + sii->CreateSharedImage(viz::ResourceFormat::RG_88, uv_size, + gfx::ColorSpace(), gpu::SHARED_IMAGE_USAGE_GLES2); + auto* gl = context_provider->ContextGL(); + gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); + UploadPixels(gl, y_mailbox, coded_size, GL_LUMINANCE, GL_UNSIGNED_BYTE, + y_pixels.get()); + UploadPixels(gl, uv_mailbox, uv_size, GL_RG, GL_UNSIGNED_BYTE, + uv_pixels.get()); + gpu::SyncToken sync_token; + gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData()); + + return CreateSharedImageFrame( + std::move(context_provider), VideoPixelFormat::PIXEL_FORMAT_NV12, + {y_mailbox, uv_mailbox}, sync_token, GL_TEXTURE_2D, coded_size, + visible_rect, visible_rect.size(), base::TimeDelta::FromSeconds(1), + std::move(destroyed_callback)); +} + +// Readback the contents of a RGBA texture into an array of RGBA values. +static std::unique_ptr<uint8_t[]> ReadbackTexture( + gpu::gles2::GLES2Interface* gl, + GLuint texture, + const gfx::Size& size) { + size_t pixel_count = size.width() * size.height(); + GLuint fbo = 0; + gl->GenFramebuffers(1, &fbo); + gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); + gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + texture, 0); + auto pixels = std::make_unique<uint8_t[]>(pixel_count * 4); + uint8_t* raw_pixels = pixels.get(); + gl->ReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_BYTE, + raw_pixels); + gl->DeleteFramebuffers(1, &fbo); + return pixels; +} + +// Returns a functor that retrieves a SkColor for a given pixel, from raw RGBA +// data. +static auto ColorGetter(uint8_t* pixels, const gfx::Size& size) { + return [pixels, size](size_t x, size_t y) { + uint8_t* p = pixels + (size.width() * y + x) * 4; + return SkColorSetARGB(p[3], p[0], p[1], p[2]); + }; +} + class PaintCanvasVideoRendererTest : public testing::Test { public: enum Color { @@ -78,14 +347,6 @@ PaintCanvasVideoRendererTest(); ~PaintCanvasVideoRendererTest() override; - void SetUp() override { gl::GLSurfaceTestSupport::InitializeOneOff(); } - - void TearDown() override { - renderer_.ResetCache(); - viz::TestGpuServiceHolder::ResetInstance(); - gl::GLSurfaceTestSupport::ShutdownGL(); - } - // Paints to |canvas| using |renderer_| without any frame data. void PaintWithoutFrame(cc::PaintCanvas* canvas); @@ -795,21 +1056,167 @@ 2 /*xoffset*/, 1 /*yoffset*/, false /*flip_y*/, true); } -TEST_F(PaintCanvasVideoRendererTest, CopyVideoFrameYUVDataToGLTexture) { - gl::DisableNullDrawGLBindings enable_pixels; +// Fixture for tests that require a GL context. +class PaintCanvasVideoRendererWithGLTest : public PaintCanvasVideoRendererTest { + public: + using GetColorCallback = base::RepeatingCallback<SkColor(int, int)>; - auto media_context = base::MakeRefCounted<viz::TestInProcessContextProvider>( - false /* enable_oop_rasterization */, false /* support_locking */); - gpu::ContextResult result = media_context->BindToCurrentThread(); - ASSERT_EQ(result, gpu::ContextResult::kSuccess); + void SetUp() override { + gl::GLSurfaceTestSupport::InitializeOneOff(); + enable_pixels_.emplace(); + media_context_ = base::MakeRefCounted<viz::TestInProcessContextProvider>( + false /* enable_oop_rasterization */, false /* support_locking */); + gpu::ContextResult result = media_context_->BindToCurrentThread(); + ASSERT_EQ(result, gpu::ContextResult::kSuccess); - auto destination_context = - base::MakeRefCounted<viz::TestInProcessContextProvider>( - false /* enable_oop_rasterization */, false /* support_locking */); - result = destination_context->BindToCurrentThread(); - ASSERT_EQ(result, gpu::ContextResult::kSuccess); + destination_context_ = + base::MakeRefCounted<viz::TestInProcessContextProvider>( + false /* enable_oop_rasterization */, false /* support_locking */); + result = destination_context_->BindToCurrentThread(); + ASSERT_EQ(result, gpu::ContextResult::kSuccess); + } - gpu::gles2::GLES2Interface* destination_gl = destination_context->ContextGL(); + void TearDown() override { + renderer_.ResetCache(); + destination_context_.reset(); + media_context_.reset(); + enable_pixels_.reset(); + viz::TestGpuServiceHolder::ResetInstance(); + gl::GLSurfaceTestSupport::ShutdownGL(); + } + + // Uses CopyVideoFrameTexturesToGLTexture to copy |frame| into a GL texture, + // reads back its contents, and runs |check_pixels| to validate it. + template <class CheckPixels> + void CopyVideoFrameTexturesAndCheckPixels(scoped_refptr<VideoFrame> frame, + CheckPixels check_pixels) { + auto* destination_gl = destination_context_->ContextGL(); + DCHECK(destination_gl); + GLenum target = GL_TEXTURE_2D; + GLuint texture = 0; + destination_gl->GenTextures(1, &texture); + destination_gl->BindTexture(target, texture); + + renderer_.CopyVideoFrameTexturesToGLTexture( + media_context_.get(), destination_gl, frame, target, texture, GL_RGBA, + GL_RGBA, GL_UNSIGNED_BYTE, 0, false /* premultiply_alpha */, + false /* flip_y */); + + gfx::Size expected_size = frame->visible_rect().size(); + + std::unique_ptr<uint8_t[]> pixels = + ReadbackTexture(destination_gl, texture, expected_size); + destination_gl->DeleteTextures(1, &texture); + + auto get_color = base::BindRepeating( + [](uint8_t* pixels, const gfx::Size& size, int x, int y) { + uint8_t* p = pixels + (size.width() * y + x) * 4; + return SkColorSetARGB(p[3], p[0], p[1], p[2]); + }, + pixels.get(), expected_size); + check_pixels(get_color); + } + + // Uses Copy to paint |frame| into a bitmap-backed canvas, then + // runs |check_pixels| to validate the contents of the canvas. + template <class CheckPixels> + void PaintVideoFrameAndCheckPixels(scoped_refptr<VideoFrame> frame, + CheckPixels check_pixels) { + gfx::Size expected_size = frame->visible_rect().size(); + SkBitmap bitmap = + AllocBitmap(expected_size.width(), expected_size.height()); + cc::SkiaPaintCanvas canvas(bitmap); + canvas.clear(SK_ColorGRAY); + renderer_.Copy(frame, &canvas, media_context_.get()); + + auto get_color = base::BindRepeating( + [](SkBitmap* bitmap, int x, int y) { return bitmap->getColor(x, y); }, + &bitmap); + check_pixels(get_color); + } + + // Creates a cropped RGBA VideoFrame. |closure| is run once the shared images + // backing the VideoFrame have been destroyed. + scoped_refptr<VideoFrame> CreateTestRGBAFrame(base::OnceClosure closure) { + return CreateSharedImageRGBAFrame(media_context_, gfx::Size(16, 8), + gfx::Rect(3, 3, 12, 4), + std::move(closure)); + } + + // Checks that the contents of a texture/canvas match the expectations for the + // cropped RGBA frame above. |get_color| is a callback that returns the actual + // color at a given pixel location. + static void CheckRGBAFramePixels(GetColorCallback get_color) { + EXPECT_EQ(SK_ColorBLACK, get_color.Run(0, 0)); + EXPECT_EQ(SK_ColorRED, get_color.Run(1, 0)); + EXPECT_EQ(SK_ColorRED, get_color.Run(4, 0)); + EXPECT_EQ(SK_ColorGREEN, get_color.Run(5, 0)); + EXPECT_EQ(SK_ColorYELLOW, get_color.Run(9, 0)); + EXPECT_EQ(SK_ColorYELLOW, get_color.Run(11, 0)); + EXPECT_EQ(SK_ColorBLUE, get_color.Run(0, 1)); + EXPECT_EQ(SK_ColorBLUE, get_color.Run(0, 3)); + EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(1, 1)); + EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(4, 1)); + EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(1, 3)); + EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(4, 3)); + EXPECT_EQ(SK_ColorCYAN, get_color.Run(5, 1)); + EXPECT_EQ(SK_ColorCYAN, get_color.Run(5, 3)); + EXPECT_EQ(SK_ColorWHITE, get_color.Run(9, 1)); + EXPECT_EQ(SK_ColorWHITE, get_color.Run(11, 1)); + EXPECT_EQ(SK_ColorWHITE, get_color.Run(9, 3)); + EXPECT_EQ(SK_ColorWHITE, get_color.Run(11, 3)); + } + + // Creates a cropped I420 VideoFrame. |closure| is run once the shared images + // backing the VideoFrame have been destroyed. + scoped_refptr<VideoFrame> CreateTestI420Frame(base::OnceClosure closure) { + return CreateSharedImageI420Frame(media_context_, gfx::Size(16, 8), + gfx::Rect(2, 2, 12, 4), + std::move(closure)); + } + + // Checks that the contents of a texture/canvas match the expectations for the + // cropped I420 frame above. |get_color| is a callback that returns the actual + // color at a given pixel location. + static void CheckI420FramePixels(GetColorCallback get_color) { + // Avoid checking around the "seams" where subsamples may be interpolated. + EXPECT_EQ(SK_ColorBLACK, get_color.Run(0, 0)); + EXPECT_EQ(SK_ColorRED, get_color.Run(3, 0)); + EXPECT_EQ(SK_ColorRED, get_color.Run(4, 0)); + EXPECT_EQ(SK_ColorGREEN, get_color.Run(7, 0)); + EXPECT_EQ(SK_ColorGREEN, get_color.Run(8, 0)); + EXPECT_EQ(SK_ColorYELLOW, get_color.Run(11, 0)); + EXPECT_EQ(SK_ColorBLUE, get_color.Run(0, 3)); + EXPECT_EQ(SK_ColorMAGENTA, get_color.Run(3, 3)); + EXPECT_EQ(SK_ColorCYAN, get_color.Run(7, 3)); + EXPECT_EQ(SK_ColorWHITE, get_color.Run(11, 3)); + } + + // Creates a cropped NV12 VideoFrame, or nullptr if the needed extension is + // not available. |closure| is run once the shared images backing the + // VideoFrame have been destroyed. + scoped_refptr<VideoFrame> CreateTestNV12Frame(base::OnceClosure closure) { + return CreateSharedImageNV12Frame(media_context_, gfx::Size(16, 8), + gfx::Rect(2, 2, 12, 4), + std::move(closure)); + } + + // Checks that the contents of a texture/canvas match the expectations for the + // cropped NV12 frame above. |get_color| is a callback that returns the actual + // color at a given pixel location. Note that the expectations are the same as + // for the I420 frame. + static void CheckNV12FramePixels(GetColorCallback get_color) { + CheckI420FramePixels(std::move(get_color)); + } + + protected: + base::Optional<gl::DisableNullDrawGLBindings> enable_pixels_; + scoped_refptr<viz::TestInProcessContextProvider> media_context_; + scoped_refptr<viz::TestInProcessContextProvider> destination_context_; +}; + +TEST_F(PaintCanvasVideoRendererWithGLTest, CopyVideoFrameYUVDataToGLTexture) { + auto* destination_gl = destination_context_->ContextGL(); DCHECK(destination_gl); GLenum target = GL_TEXTURE_2D; GLuint texture = 0; @@ -817,29 +1224,15 @@ destination_gl->BindTexture(target, texture); renderer_.CopyVideoFrameYUVDataToGLTexture( - media_context.get(), destination_gl, *cropped_frame(), target, texture, + media_context_.get(), destination_gl, *cropped_frame(), target, texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 0, false /* premultiply_alpha */, false /* flip_y */); gfx::Size expected_size = cropped_frame()->visible_rect().size(); - size_t pixel_count = expected_size.width() * expected_size.height(); - GLuint fbo = 0; - destination_gl->GenFramebuffers(1, &fbo); - destination_gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); - destination_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, texture, 0); - auto pixels = std::make_unique<uint8_t[]>(pixel_count * 4); - uint8_t* raw_pixels = pixels.get(); - destination_gl->ReadPixels(0, 0, expected_size.width(), - expected_size.height(), GL_RGBA, GL_UNSIGNED_BYTE, - raw_pixels); - destination_gl->DeleteFramebuffers(1, &fbo); - - auto get_color = [raw_pixels, expected_size](size_t x, size_t y) { - uint8_t* p = raw_pixels + (expected_size.width() * y + x) * 4; - return SkColorSetARGB(p[3], p[0], p[1], p[2]); - }; + std::unique_ptr<uint8_t[]> pixels = + ReadbackTexture(destination_gl, texture, expected_size); + auto get_color = ColorGetter(pixels.get(), expected_size); // Avoid checking around the seams. EXPECT_EQ(SK_ColorBLACK, get_color(0, 0)); @@ -853,21 +1246,9 @@ destination_gl->DeleteTextures(1, &texture); } -TEST_F(PaintCanvasVideoRendererTest, CopyVideoFrameYUVDataToGLTexture_FlipY) { - gl::DisableNullDrawGLBindings enable_pixels; - - auto media_context = base::MakeRefCounted<viz::TestInProcessContextProvider>( - false /* enable_oop_rasterization */, false /* support_locking */); - gpu::ContextResult result = media_context->BindToCurrentThread(); - ASSERT_EQ(result, gpu::ContextResult::kSuccess); - - auto destination_context = - base::MakeRefCounted<viz::TestInProcessContextProvider>( - false /* enable_oop_rasterization */, false /* support_locking */); - result = destination_context->BindToCurrentThread(); - ASSERT_EQ(result, gpu::ContextResult::kSuccess); - - gpu::gles2::GLES2Interface* destination_gl = destination_context->ContextGL(); +TEST_F(PaintCanvasVideoRendererWithGLTest, + CopyVideoFrameYUVDataToGLTexture_FlipY) { + auto* destination_gl = destination_context_->ContextGL(); DCHECK(destination_gl); GLenum target = GL_TEXTURE_2D; GLuint texture = 0; @@ -875,29 +1256,15 @@ destination_gl->BindTexture(target, texture); renderer_.CopyVideoFrameYUVDataToGLTexture( - media_context.get(), destination_gl, *cropped_frame(), target, texture, + media_context_.get(), destination_gl, *cropped_frame(), target, texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 0, false /* premultiply_alpha */, true /* flip_y */); gfx::Size expected_size = cropped_frame()->visible_rect().size(); - size_t pixel_count = expected_size.width() * expected_size.height(); - GLuint fbo = 0; - destination_gl->GenFramebuffers(1, &fbo); - destination_gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); - destination_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, texture, 0); - auto pixels = std::make_unique<uint8_t[]>(pixel_count * 4); - uint8_t* raw_pixels = pixels.get(); - destination_gl->ReadPixels(0, 0, expected_size.width(), - expected_size.height(), GL_RGBA, GL_UNSIGNED_BYTE, - raw_pixels); - destination_gl->DeleteFramebuffers(1, &fbo); - - auto get_color = [raw_pixels, expected_size](size_t x, size_t y) { - uint8_t* p = raw_pixels + (expected_size.width() * y + x) * 4; - return SkColorSetARGB(p[3], p[0], p[1], p[2]); - }; + std::unique_ptr<uint8_t[]> pixels = + ReadbackTexture(destination_gl, texture, expected_size); + auto get_color = ColorGetter(pixels.get(), expected_size); // Avoid checking around the seams. EXPECT_EQ(SK_ColorBLACK, get_color(0, 5)); @@ -911,4 +1278,103 @@ destination_gl->DeleteTextures(1, &texture); } +// Checks that we correctly copy a RGBA shared image VideoFrame when using +// CopyVideoFrameYUVDataToGLTexture, including correct cropping. +TEST_F(PaintCanvasVideoRendererWithGLTest, + CopyVideoFrameTexturesToGLTextureRGBA) { + base::RunLoop run_loop; + scoped_refptr<VideoFrame> frame = CreateTestRGBAFrame(run_loop.QuitClosure()); + + CopyVideoFrameTexturesAndCheckPixels(frame, &CheckRGBAFramePixels); + + frame.reset(); + run_loop.Run(); +} + +// Checks that we correctly copy a RGBA shared image VideoFrame that needs read +// lock fences, when using CopyVideoFrameYUVDataToGLTexture, including correct +// cropping. +TEST_F(PaintCanvasVideoRendererWithGLTest, + CopyVideoFrameTexturesToGLTextureRGBA_ReadLockFence) { + base::RunLoop run_loop; + scoped_refptr<VideoFrame> frame = CreateTestRGBAFrame(run_loop.QuitClosure()); + frame->metadata()->SetBoolean(VideoFrameMetadata::READ_LOCK_FENCES_ENABLED, + true); + + CopyVideoFrameTexturesAndCheckPixels(frame, &CheckRGBAFramePixels); + + frame.reset(); + run_loop.Run(); +} + +// Checks that we correctly paint a RGBA shared image VideoFrame, including +// correct cropping. +TEST_F(PaintCanvasVideoRendererWithGLTest, PaintRGBA) { + base::RunLoop run_loop; + scoped_refptr<VideoFrame> frame = CreateTestRGBAFrame(run_loop.QuitClosure()); + + PaintVideoFrameAndCheckPixels(frame, &CheckRGBAFramePixels); + + frame.reset(); + run_loop.Run(); +} + +// Checks that we correctly copy an I420 shared image VideoFrame when using +// CopyVideoFrameYUVDataToGLTexture, including correct cropping. +TEST_F(PaintCanvasVideoRendererWithGLTest, + CopyVideoFrameTexturesToGLTextureI420) { + base::RunLoop run_loop; + scoped_refptr<VideoFrame> frame = CreateTestI420Frame(run_loop.QuitClosure()); + + CopyVideoFrameTexturesAndCheckPixels(frame, &CheckI420FramePixels); + + frame.reset(); + run_loop.Run(); +} + +// Checks that we correctly paint a I420 shared image VideoFrame, including +// correct cropping. +TEST_F(PaintCanvasVideoRendererWithGLTest, PaintI420) { + base::RunLoop run_loop; + scoped_refptr<VideoFrame> frame = CreateTestI420Frame(run_loop.QuitClosure()); + + PaintVideoFrameAndCheckPixels(frame, &CheckI420FramePixels); + + frame.reset(); + run_loop.Run(); +} + +// Checks that we correctly copy a NV12 shared image VideoFrame when using +// CopyVideoFrameYUVDataToGLTexture, including correct cropping. +TEST_F(PaintCanvasVideoRendererWithGLTest, + CopyVideoFrameTexturesToGLTextureNV12) { + base::RunLoop run_loop; + scoped_refptr<VideoFrame> frame = CreateTestNV12Frame(run_loop.QuitClosure()); + if (!frame) { + LOG(ERROR) << "GL_EXT_texture_rg not supported, skipping NV12 test"; + return; + } + + CopyVideoFrameTexturesAndCheckPixels(frame, &CheckNV12FramePixels); + + frame.reset(); + run_loop.Run(); +} + +// Checks that we correctly paint a NV12 shared image VideoFrame, including +// correct cropping. +TEST_F(PaintCanvasVideoRendererWithGLTest, PaintNV12) { + base::RunLoop run_loop; + scoped_refptr<VideoFrame> frame = CreateTestNV12Frame(run_loop.QuitClosure()); + if (!frame) { + LOG(ERROR) << "GL_EXT_texture_rg not supported, skipping NV12 test"; + return; + } + + PaintVideoFrameAndCheckPixels(frame, &CheckNV12FramePixels); + + frame.reset(); + run_loop.Run(); +} + } // namespace media
diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc index e81d485..c39f67c 100644 --- a/net/cert/internal/path_builder.cc +++ b/net/cert/internal/path_builder.cc
@@ -9,6 +9,7 @@ #include <unordered_set> #include "base/logging.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/string_number_conversions.h" #include "crypto/sha2.h" #include "net/base/net_errors.h" @@ -55,6 +56,11 @@ return s; } +void RecordIterationCountHistogram(uint32_t iteration_count) { + base::UmaHistogramCounts10000("Net.CertVerifier.PathBuilderIterationCount", + iteration_count); +} + // This structure describes a certificate and its trust level. Note that |cert| // may be null to indicate an "empty" entry. struct IssuerEntry { @@ -591,6 +597,7 @@ if (!deadline_.is_null() && base::TimeTicks::Now() > deadline_) { out_result_->exceeded_deadline = true; } + RecordIterationCountHistogram(iteration_count); return; } @@ -612,6 +619,7 @@ AddResultPath(std::move(result_path)); if (path_is_good) { + RecordIterationCountHistogram(iteration_count); // Found a valid path, return immediately. // TODO(mattm): add debug/test mode that tries all possible paths. return;
diff --git a/net/cert/internal/path_builder_unittest.cc b/net/cert/internal/path_builder_unittest.cc index 87840cd..1a954a7 100644 --- a/net/cert/internal/path_builder_unittest.cc +++ b/net/cert/internal/path_builder_unittest.cc
@@ -7,6 +7,7 @@ #include "base/base_paths.h" #include "base/files/file_util.h" #include "base/path_service.h" +#include "base/test/metrics/histogram_tester.h" #include "net/cert/internal/cert_error_params.h" #include "net/cert/internal/cert_issuer_source_static.h" #include "net/cert/internal/common_cert_errors.h" @@ -30,6 +31,7 @@ namespace { using ::testing::_; +using ::testing::ElementsAre; using ::testing::Invoke; using ::testing::NiceMock; using ::testing::Return; @@ -450,12 +452,11 @@ } TEST_F(PathBuilderMultiRootTest, TestIterationLimit) { - // Both D(D) and C(D) are trusted roots. + // D(D) is the trust root. TrustStoreInMemory trust_store; trust_store.AddTrustAnchor(d_by_d_); - trust_store.AddTrustAnchor(c_by_d_); - // Certs B(C), and C(D) are all supplied. + // Certs B(C) and C(D) are supplied. CertIssuerSourceStatic sync_certs; sync_certs.AddCert(b_by_c_); sync_certs.AddCert(c_by_d_); @@ -481,10 +482,21 @@ path_builder.SetIterationLimit(5); } + base::HistogramTester histogram_tester; path_builder.Run(); EXPECT_EQ(!insufficient_limit, result.HasValidPath()); EXPECT_EQ(insufficient_limit, result.exceeded_iteration_limit); + + if (insufficient_limit) { + EXPECT_THAT(histogram_tester.GetAllSamples( + "Net.CertVerifier.PathBuilderIterationCount"), + ElementsAre(base::Bucket(/*sample=*/2, /*count=*/1))); + } else { + EXPECT_THAT(histogram_tester.GetAllSamples( + "Net.CertVerifier.PathBuilderIterationCount"), + ElementsAre(base::Bucket(/*sample=*/3, /*count=*/1))); + } } }
diff --git a/net/quic/OWNERS b/net/quic/OWNERS index 1835f5b..6fd222f 100644 --- a/net/quic/OWNERS +++ b/net/quic/OWNERS
@@ -1,3 +1,4 @@ +nharper@chromium.org rch@chromium.org zhongyi@chromium.org
diff --git a/pdf/BUILD.gn b/pdf/BUILD.gn index 7b69a8c9..7d6bd3f 100644 --- a/pdf/BUILD.gn +++ b/pdf/BUILD.gn
@@ -53,8 +53,10 @@ "document_loader.h", "document_loader_impl.cc", "document_loader_impl.h", - "draw_utils.cc", - "draw_utils.h", + "draw_utils/coordinates.cc", + "draw_utils/coordinates.h", + "draw_utils/shadow.cc", + "draw_utils/shadow.h", "out_of_process_instance.cc", "out_of_process_instance.h", "paint_aggregator.cc", @@ -150,6 +152,7 @@ sources = [ "chunk_stream_unittest.cc", "document_loader_impl_unittest.cc", + "draw_utils/coordinates_unittest.cc", "out_of_process_instance_unittest.cc", "pdf_transform_unittest.cc", "range_set_unittest.cc",
diff --git a/pdf/draw_utils/coordinates.cc b/pdf/draw_utils/coordinates.cc new file mode 100644 index 0000000..d3ed045 --- /dev/null +++ b/pdf/draw_utils/coordinates.cc
@@ -0,0 +1,28 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/draw_utils/coordinates.h" + +#include <math.h> + +#include "base/logging.h" +#include "ppapi/cpp/point.h" + +namespace chrome_pdf { +namespace draw_utils { + +pp::Rect GetScreenRect(const pp::Rect& rect, + const pp::Point& position, + double zoom) { + DCHECK_GT(zoom, 0); + + int x = static_cast<int>(rect.x() * zoom - position.x()); + int y = static_cast<int>(rect.y() * zoom - position.y()); + int right = static_cast<int>(ceil(rect.right() * zoom - position.x())); + int bottom = static_cast<int>(ceil(rect.bottom() * zoom - position.y())); + return pp::Rect(x, y, right - x, bottom - y); +} + +} // namespace draw_utils +} // namespace chrome_pdf
diff --git a/pdf/draw_utils/coordinates.h b/pdf/draw_utils/coordinates.h new file mode 100644 index 0000000..a11424f --- /dev/null +++ b/pdf/draw_utils/coordinates.h
@@ -0,0 +1,29 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PDF_DRAW_UTILS_COORDINATES_H_ +#define PDF_DRAW_UTILS_COORDINATES_H_ + +#include "ppapi/cpp/rect.h" + +namespace pp { +class Point; +} + +namespace chrome_pdf { +namespace draw_utils { + +// Given |rect| in document coordinates, a |position| in screen coordinates, and +// a |zoom| factor, returns the rectangle in screen coordinates (i.e. 0,0 is top +// left corner of plugin area). +// An empty |rect| will always result in an empty output rect. +// For |zoom|, a value of 1 means 100%. |zoom| is never less than or equal to 0. +pp::Rect GetScreenRect(const pp::Rect& rect, + const pp::Point& position, + double zoom); + +} // namespace draw_utils +} // namespace chrome_pdf + +#endif // PDF_DRAW_UTILS_COORDINATES_H_
diff --git a/pdf/draw_utils/coordinates_unittest.cc b/pdf/draw_utils/coordinates_unittest.cc new file mode 100644 index 0000000..af4424a5 --- /dev/null +++ b/pdf/draw_utils/coordinates_unittest.cc
@@ -0,0 +1,96 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/draw_utils/coordinates.h" + +#include "ppapi/cpp/point.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chrome_pdf { +namespace draw_utils { + +TEST(CoordinateTest, GetScreenRect) { + pp::Rect screen_rect; + const pp::Rect rect(10, 20, 200, 300); + + // Test various zooms with the position at the origin. + screen_rect = GetScreenRect(rect, {0, 0}, 1); + EXPECT_EQ(10, screen_rect.x()); + EXPECT_EQ(20, screen_rect.y()); + EXPECT_EQ(200, screen_rect.width()); + EXPECT_EQ(300, screen_rect.height()); + + screen_rect = GetScreenRect(rect, {0, 0}, 1.5); + EXPECT_EQ(15, screen_rect.x()); + EXPECT_EQ(30, screen_rect.y()); + EXPECT_EQ(300, screen_rect.width()); + EXPECT_EQ(450, screen_rect.height()); + + screen_rect = GetScreenRect(rect, {0, 0}, 0.5); + EXPECT_EQ(5, screen_rect.x()); + EXPECT_EQ(10, screen_rect.y()); + EXPECT_EQ(100, screen_rect.width()); + EXPECT_EQ(150, screen_rect.height()); + + // Test various zooms with the position elsewhere. + screen_rect = GetScreenRect(rect, {400, 30}, 1); + EXPECT_EQ(-390, screen_rect.x()); + EXPECT_EQ(-10, screen_rect.y()); + EXPECT_EQ(200, screen_rect.width()); + EXPECT_EQ(300, screen_rect.height()); + + screen_rect = GetScreenRect(rect, {400, 30}, 1.5); + EXPECT_EQ(-385, screen_rect.x()); + EXPECT_EQ(0, screen_rect.y()); + EXPECT_EQ(300, screen_rect.width()); + EXPECT_EQ(450, screen_rect.height()); + + screen_rect = GetScreenRect(rect, {400, 30}, 0.5); + EXPECT_EQ(-395, screen_rect.x()); + EXPECT_EQ(-20, screen_rect.y()); + EXPECT_EQ(100, screen_rect.width()); + EXPECT_EQ(150, screen_rect.height()); + + // Test various zooms with a negative position. + screen_rect = GetScreenRect(rect, {100, -50}, 1); + EXPECT_EQ(-90, screen_rect.x()); + EXPECT_EQ(70, screen_rect.y()); + EXPECT_EQ(200, screen_rect.width()); + EXPECT_EQ(300, screen_rect.height()); + + screen_rect = GetScreenRect(rect, {100, -50}, 1.5); + EXPECT_EQ(-85, screen_rect.x()); + EXPECT_EQ(80, screen_rect.y()); + EXPECT_EQ(300, screen_rect.width()); + EXPECT_EQ(450, screen_rect.height()); + + screen_rect = GetScreenRect(rect, {100, -50}, 0.5); + EXPECT_EQ(-95, screen_rect.x()); + EXPECT_EQ(60, screen_rect.y()); + EXPECT_EQ(100, screen_rect.width()); + EXPECT_EQ(150, screen_rect.height()); + + // Test an empty rect always outputs an empty rect. + const pp::Rect empty_rect; + screen_rect = GetScreenRect(empty_rect, {20, 500}, 1); + EXPECT_EQ(-20, screen_rect.x()); + EXPECT_EQ(-500, screen_rect.y()); + EXPECT_EQ(0, screen_rect.width()); + EXPECT_EQ(0, screen_rect.height()); + + screen_rect = GetScreenRect(empty_rect, {20, 500}, 1.5); + EXPECT_EQ(-20, screen_rect.x()); + EXPECT_EQ(-500, screen_rect.y()); + EXPECT_EQ(0, screen_rect.width()); + EXPECT_EQ(0, screen_rect.height()); + + screen_rect = GetScreenRect(empty_rect, {20, 500}, 0.5); + EXPECT_EQ(-20, screen_rect.x()); + EXPECT_EQ(-500, screen_rect.y()); + EXPECT_EQ(0, screen_rect.width()); + EXPECT_EQ(0, screen_rect.height()); +} + +} // namespace draw_utils +} // namespace chrome_pdf
diff --git a/pdf/draw_utils.cc b/pdf/draw_utils/shadow.cc similarity index 95% rename from pdf/draw_utils.cc rename to pdf/draw_utils/shadow.cc index adb2ceb..c17b757 100644 --- a/pdf/draw_utils.cc +++ b/pdf/draw_utils/shadow.cc
@@ -2,18 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "pdf/draw_utils.h" +#include "pdf/draw_utils/shadow.h" #include <math.h> #include <stddef.h> -#include <stdint.h> + #include <algorithm> -#include <vector> #include "base/logging.h" -#include "base/numerics/safe_math.h" +#include "ppapi/cpp/image_data.h" +#include "ppapi/cpp/rect.h" namespace chrome_pdf { +namespace draw_utils { + +constexpr uint8_t kOpaqueAlpha = 0xFF; +constexpr uint8_t kTransparentAlpha = 0x00; inline uint8_t GetBlue(const uint32_t& pixel) { return static_cast<uint8_t>(pixel & 0xFF); @@ -169,4 +173,5 @@ PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix); } +} // namespace draw_utils } // namespace chrome_pdf
diff --git a/pdf/draw_utils.h b/pdf/draw_utils/shadow.h similarity index 86% rename from pdf/draw_utils.h rename to pdf/draw_utils/shadow.h index 93c769ee..91f0b168ab 100644 --- a/pdf/draw_utils.h +++ b/pdf/draw_utils/shadow.h
@@ -2,20 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef PDF_DRAW_UTILS_H_ -#define PDF_DRAW_UTILS_H_ +#ifndef PDF_DRAW_UTILS_SHADOW_H_ +#define PDF_DRAW_UTILS_SHADOW_H_ #include <stdint.h> #include <vector> -#include "ppapi/cpp/image_data.h" -#include "ppapi/cpp/rect.h" +namespace pp { +class ImageData; +class Rect; +} // namespace pp namespace chrome_pdf { - -const uint8_t kOpaqueAlpha = 0xFF; -const uint8_t kTransparentAlpha = 0x00; +namespace draw_utils { // Shadow Matrix contains matrix for shadow rendering. To reduce amount of // calculations user may choose to cache matrix and reuse it if nothing changed. @@ -52,6 +52,7 @@ const pp::Rect& clip_rc, const ShadowMatrix& matrix); +} // namespace draw_utils } // namespace chrome_pdf -#endif // PDF_DRAW_UTILS_H_ +#endif // PDF_DRAW_UTILS_SHADOW_H_
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index 1267d692..1533ceb 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -29,7 +29,8 @@ #include "gin/public/gin_embedders.h" #include "gin/public/isolate_holder.h" #include "pdf/document_loader_impl.h" -#include "pdf/draw_utils.h" +#include "pdf/draw_utils/coordinates.h" +#include "pdf/draw_utils/shadow.h" #include "pdf/pdf_transform.h" #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h" #include "pdf/pdfium/pdfium_document.h" @@ -3133,17 +3134,7 @@ } pp::Rect PDFiumEngine::GetScreenRect(const pp::Rect& rect) const { - pp::Rect rv; - int right = - static_cast<int>(ceil(rect.right() * current_zoom_ - position_.x())); - int bottom = - static_cast<int>(ceil(rect.bottom() * current_zoom_ - position_.y())); - - rv.set_x(static_cast<int>(rect.x() * current_zoom_ - position_.x())); - rv.set_y(static_cast<int>(rect.y() * current_zoom_ - position_.y())); - rv.set_width(right - rv.x()); - rv.set_height(bottom - rv.y()); - return rv; + return draw_utils::GetScreenRect(rect, position_, current_zoom_); } void PDFiumEngine::Highlight(void* buffer, @@ -3367,8 +3358,8 @@ depth = static_cast<uint32_t>(depth * 1.5) + 1; // We need to check depth only to verify our copy of shadow matrix is correct. - if (!page_shadow_.get() || page_shadow_->depth() != depth) { - page_shadow_ = std::make_unique<ShadowMatrix>( + if (!page_shadow_ || page_shadow_->depth() != depth) { + page_shadow_ = std::make_unique<draw_utils::ShadowMatrix>( depth, factor, client_->GetBackgroundColor()); }
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h index 7d36979..6880eb5 100644 --- a/pdf/pdfium/pdfium_engine.h +++ b/pdf/pdfium/pdfium_engine.h
@@ -38,7 +38,10 @@ namespace chrome_pdf { class PDFiumDocument; + +namespace draw_utils { class ShadowMatrix; +} class PDFiumEngine : public PDFEngine, public DocumentLoader::Client, @@ -394,9 +397,8 @@ // Returns the currently visible rectangle in document coordinates. pp::Rect GetVisibleRect() const; - // Given a rectangle in document coordinates, returns the rectange into screen - // coordinates (i.e. 0,0 is top left corner of plugin area). If it's not - // visible, an empty rectangle is returned. + // Given |rect| in document coordinates, returns the rectangle in screen + // coordinates. (i.e. 0,0 is top left corner of plugin area) pp::Rect GetScreenRect(const pp::Rect& rect) const; // Given an image |buffer| with |stride|, highlights |rect|. @@ -649,7 +651,7 @@ base::TimeDelta progressive_paint_timeout_; // Shadow matrix for generating the page shadow bitmap. - std::unique_ptr<ShadowMatrix> page_shadow_; + std::unique_ptr<draw_utils::ShadowMatrix> page_shadow_; // While true, the document try to be opened and parsed after download each // part. Else the document will be opened and parsed only on finish of
diff --git a/sandbox/win/src/target_interceptions.cc b/sandbox/win/src/target_interceptions.cc index 7ea741c6..2dc2fd1 100644 --- a/sandbox/win/src/target_interceptions.cc +++ b/sandbox/win/src/target_interceptions.cc
@@ -7,7 +7,6 @@ #include "sandbox/win/src/interception_agent.h" #include "sandbox/win/src/sandbox_factory.h" #include "sandbox/win/src/sandbox_nt_util.h" -#include "sandbox/win/src/target_services.h" namespace sandbox { @@ -68,7 +67,6 @@ if (ansi_module_name && (g_nt._strnicmp(ansi_module_name, KERNEL32_DLL_NAME, sizeof(KERNEL32_DLL_NAME)) == 0)) { - SandboxFactory::GetTargetServices()->GetState()->SetKernel32Loaded(); s_state = kAfterKernel32; } } __except (EXCEPTION_EXECUTE_HANDLER) {
diff --git a/sandbox/win/src/target_services.cc b/sandbox/win/src/target_services.cc index c946783..f35dc39d 100644 --- a/sandbox/win/src/target_services.cc +++ b/sandbox/win/src/target_services.cc
@@ -215,37 +215,29 @@ return true; } -ProcessState::ProcessState() : process_state_(0), csrss_connected_(true) {} - -bool ProcessState::IsKernel32Loaded() const { - return process_state_ != 0; -} +ProcessState::ProcessState() + : process_state_(ProcessStateInternal::NONE), csrss_connected_(true) {} bool ProcessState::InitCalled() const { - return process_state_ > 1; + return process_state_ >= ProcessStateInternal::INIT_CALLED; } bool ProcessState::RevertedToSelf() const { - return process_state_ > 2; + return process_state_ >= ProcessStateInternal::REVERTED_TO_SELF; } bool ProcessState::IsCsrssConnected() const { return csrss_connected_; } -void ProcessState::SetKernel32Loaded() { - if (!process_state_) - process_state_ = 1; -} - void ProcessState::SetInitCalled() { - if (process_state_ < 2) - process_state_ = 2; + if (process_state_ < ProcessStateInternal::INIT_CALLED) + process_state_ = ProcessStateInternal::INIT_CALLED; } void ProcessState::SetRevertedToSelf() { - if (process_state_ < 3) - process_state_ = 3; + if (process_state_ < ProcessStateInternal::REVERTED_TO_SELF) + process_state_ = ProcessStateInternal::REVERTED_TO_SELF; } void ProcessState::SetCsrssConnected(bool csrss_connected) {
diff --git a/sandbox/win/src/target_services.h b/sandbox/win/src/target_services.h index a33c9201..e50b7fb 100644 --- a/sandbox/win/src/target_services.h +++ b/sandbox/win/src/target_services.h
@@ -14,8 +14,6 @@ class ProcessState { public: ProcessState(); - // Returns true if kernel32.dll has been loaded. - bool IsKernel32Loaded() const; // Returns true if main has been called. bool InitCalled() const; // Returns true if LowerToken has been called. @@ -23,13 +21,14 @@ // Returns true if Csrss is connected. bool IsCsrssConnected() const; // Set the current state. - void SetKernel32Loaded(); void SetInitCalled(); void SetRevertedToSelf(); void SetCsrssConnected(bool csrss_connected); private: - int process_state_; + enum class ProcessStateInternal { NONE = 0, INIT_CALLED, REVERTED_TO_SELF }; + + ProcessStateInternal process_state_; bool csrss_connected_; DISALLOW_COPY_AND_ASSIGN(ProcessState); };
diff --git a/services/device/BUILD.gn b/services/device/BUILD.gn index 64d14fa..f0605c8 100644 --- a/services/device/BUILD.gn +++ b/services/device/BUILD.gn
@@ -271,6 +271,8 @@ } if (is_win) { + sources += [ "generic_sensor/platform_sensor_provider_winrt_unittest.cc" ] + # Needed for "generic_sensor/platform_sensor_and_provider_unittest_win.cc" libs = [ "propsys.lib",
diff --git a/services/device/generic_sensor/BUILD.gn b/services/device/generic_sensor/BUILD.gn index fc50c56..9caa1e58 100644 --- a/services/device/generic_sensor/BUILD.gn +++ b/services/device/generic_sensor/BUILD.gn
@@ -104,6 +104,11 @@ } if (is_win) { + sources += [ + "platform_sensor_provider_winrt.cc", + "platform_sensor_provider_winrt.h", + ] + libs = [ "portabledeviceguids.lib", "sensorsapi.lib",
diff --git a/services/device/generic_sensor/platform_sensor_provider.cc b/services/device/generic_sensor/platform_sensor_provider.cc index aeb0f32..8b8c6916 100644 --- a/services/device/generic_sensor/platform_sensor_provider.cc +++ b/services/device/generic_sensor/platform_sensor_provider.cc
@@ -9,7 +9,12 @@ #elif defined(OS_ANDROID) #include "services/device/generic_sensor/platform_sensor_provider_android.h" #elif defined(OS_WIN) +#include "base/feature_list.h" +#include "base/win/windows_version.h" +#include "build/build_config.h" #include "services/device/generic_sensor/platform_sensor_provider_win.h" +#include "services/device/generic_sensor/platform_sensor_provider_winrt.h" +#include "services/device/public/cpp/device_features.h" #elif defined(OS_LINUX) && defined(USE_UDEV) #include "services/device/generic_sensor/platform_sensor_provider_linux.h" #endif @@ -23,7 +28,11 @@ #elif defined(OS_ANDROID) return std::make_unique<PlatformSensorProviderAndroid>(); #elif defined(OS_WIN) - return std::make_unique<PlatformSensorProviderWin>(); + if (PlatformSensorProvider::UseWindowsWinrt()) { + return std::make_unique<PlatformSensorProviderWinrt>(); + } else { + return std::make_unique<PlatformSensorProviderWin>(); + } #elif defined(OS_LINUX) && defined(USE_UDEV) return std::make_unique<PlatformSensorProviderLinux>(); #else @@ -31,4 +40,17 @@ #endif } +#if defined(OS_WIN) +// static +bool PlatformSensorProvider::UseWindowsWinrt() { + // TODO: Windows version dependency should eventually be updated to + // a future version which supports WinRT sensor thresholding. Since + // this Windows version has yet to be released, Win10 is being + // provisionally used for testing. This also means sensors will + // stream if this implementation path is enabled. + return base::FeatureList::IsEnabled(features::kWinrtSensorsImplementation) && + base::win::GetVersion() >= base::win::Version::WIN10; +} +#endif + } // namespace device
diff --git a/services/device/generic_sensor/platform_sensor_provider.h b/services/device/generic_sensor/platform_sensor_provider.h index 525d81f..9e2c5e5 100644 --- a/services/device/generic_sensor/platform_sensor_provider.h +++ b/services/device/generic_sensor/platform_sensor_provider.h
@@ -25,6 +25,10 @@ protected: PlatformSensorProvider() = default; + // Determines if the ISensor or Windows.Devices.Sensors implementation + // should be used on Windows. + static bool UseWindowsWinrt(); + DISALLOW_COPY_AND_ASSIGN(PlatformSensorProvider); };
diff --git a/services/device/generic_sensor/platform_sensor_provider_winrt.cc b/services/device/generic_sensor/platform_sensor_provider_winrt.cc new file mode 100644 index 0000000..2d3e5087 --- /dev/null +++ b/services/device/generic_sensor/platform_sensor_provider_winrt.cc
@@ -0,0 +1,24 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/device/generic_sensor/platform_sensor_provider_winrt.h" + +#include <comdef.h> + +#include "base/memory/singleton.h" + +namespace device { + +PlatformSensorProviderWinrt::PlatformSensorProviderWinrt() = default; + +PlatformSensorProviderWinrt::~PlatformSensorProviderWinrt() = default; + +void PlatformSensorProviderWinrt::CreateSensorInternal( + mojom::SensorType type, + SensorReadingSharedBuffer* reading_buffer, + const CreateSensorCallback& callback) { + callback.Run(nullptr); +} + +} // namespace device \ No newline at end of file
diff --git a/services/device/generic_sensor/platform_sensor_provider_winrt.h b/services/device/generic_sensor/platform_sensor_provider_winrt.h new file mode 100644 index 0000000..01a07b0 --- /dev/null +++ b/services/device/generic_sensor/platform_sensor_provider_winrt.h
@@ -0,0 +1,52 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_PROVIDER_WINRT_H_ +#define SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_PROVIDER_WINRT_H_ + +#include "services/device/generic_sensor/platform_sensor_provider.h" + +namespace base { +template <typename T> +struct DefaultSingletonTraits; +} // namespace base + +namespace device { + +class PlatformSensorReaderWin; + +// Implementation of PlatformSensorProvider for Windows platform using the +// Windows.Devices.Sensors WinRT API. PlatformSensorProviderWinrt is +// responsible for the following tasks: +// - Starts sensor thread and stops it when there are no active sensors. +// - Creates sensor reader. +// - Constructs PlatformSensorWin on IPC thread and returns it to requester. +class PlatformSensorProviderWinrt final : public PlatformSensorProvider { + public: + PlatformSensorProviderWinrt(); + ~PlatformSensorProviderWinrt() override; + + protected: + // PlatformSensorProvider interface implementation. + void CreateSensorInternal(mojom::SensorType type, + SensorReadingSharedBuffer* reading_buffer, + const CreateSensorCallback& callback) override; + + private: + friend struct base::DefaultSingletonTraits<PlatformSensorProviderWinrt>; + + void SensorReaderCreated( + mojom::SensorType type, + SensorReadingSharedBuffer* reading_buffer, + const CreateSensorCallback& callback, + std::unique_ptr<PlatformSensorReaderWin> sensor_reader); + + PlatformSensorProviderWinrt(const PlatformSensorProviderWinrt&) = delete; + PlatformSensorProviderWinrt& operator=(const PlatformSensorProviderWinrt&) = + delete; +}; + +} // namespace device + +#endif // SERVICES_DEVICE_GENERIC_SENSOR_PLATFORM_SENSOR_PROVIDER_WINRT_H_ \ No newline at end of file
diff --git a/services/device/generic_sensor/platform_sensor_provider_winrt_unittest.cc b/services/device/generic_sensor/platform_sensor_provider_winrt_unittest.cc new file mode 100644 index 0000000..27a79470 --- /dev/null +++ b/services/device/generic_sensor/platform_sensor_provider_winrt_unittest.cc
@@ -0,0 +1,38 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/device/generic_sensor/platform_sensor_provider_winrt.h" + +#include "base/run_loop.h" +#include "base/test/bind_test_util.h" +#include "base/test/scoped_task_environment.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace device { + +// Tests that PlatformSensorProviderWinrt can successfully be instantiated +// and passes the correct result to the CreateSensor callback. +TEST(PlatformSensorProviderTestWinrt, SensorCreationReturnCheck) { + base::test::ScopedTaskEnvironment scoped_task_environment; + + auto provider = std::make_unique<PlatformSensorProviderWinrt>(); + + // CreateSensor is async so create a RunLoop to wait for completion. + base::RunLoop run_loop; + + base::Callback<void(scoped_refptr<PlatformSensor> sensor)> + CreateSensorCallback = + base::BindLambdaForTesting([&](scoped_refptr<PlatformSensor> sensor) { + EXPECT_FALSE(sensor); + run_loop.Quit(); + }); + + // PlatformSensorProviderWinrt is not implemented so it should always + // return nullptr. + provider->CreateSensor(mojom::SensorType::AMBIENT_LIGHT, + CreateSensorCallback); + run_loop.Run(); +} + +} // namespace device \ No newline at end of file
diff --git a/services/device/generic_sensor/windows/README.md b/services/device/generic_sensor/windows/README.md index 9207450..8772437 100644 --- a/services/device/generic_sensor/windows/README.md +++ b/services/device/generic_sensor/windows/README.md
@@ -125,46 +125,7 @@ ### 4.1 Support For Adapting Between ISensor and Windows.Devices.Sensors Sensor Implementations -The `PlatformSensorProvider::GetInstance()` function decides which -PlatformSensorProvider implementation to use. A new branch will be -added for the Windows.Devices.Sensors path: - -```cpp -PlatformSensorProvider* PlatformSensorProvider::GetInstance() { - if (g_provider_for_testing) - return g_provider_for_testing; -#if defined(OS_MACOSX) - return PlatformSensorProviderMac::GetInstance(); -#elif defined(OS_ANDROID) - return PlatformSensorProviderAndroid::GetInstance(); -#elif defined(OS_WIN) - if (PlatformSensorProvider::UseWindowsWinrt()) { - // Windows.Devices.Sensors Windows implementation - return PlatformSensorProviderWinrt::GetInstance(); - } else { - // ISensor Windows implementation - return PlatformSensorProviderWin::GetInstance(); - } -#elif defined(OS_LINUX) && defined(USE_UDEV) - return PlatformSensorProviderLinux::GetInstance(); -#else - return nullptr; -#endif -} -``` - -With `PlatformSensorProvider::UseWindowsWinrt()` being: - -```cpp -bool PlatformSensorProvider::UseWindowsWinrt() { - return base::FeatureList::IsEnabled(kWinrtSensorsImplementation) && - (base::win::GetVersion() >= base::win::Version::WIN10); -} -``` - -The Windows.Devices.Sensors path is also decided on the -`kWinrtSensorsImplementation` feature flag, which is explained further in -section 5 below. +Please refer to [platform_sensor_provider.cc](platform_sensor_provider.cc ). ### 4.2 Proposed Windows.Devices.Sensors Sensor Implementation @@ -454,21 +415,6 @@ The modernization changes will be broken down into several incremental changes to keep change lists to a reviewable size: -#### Change list 1: Define the interface for PlatformSensorProviderWinrt and consume it - -- Feature Work: - - Create the PlatformSensorProviderWinrt header as defined in - Section 8.1. - - Create the Chromium feature flag as defined in Section 5 following - these [steps](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/how_to_add_your_feature_flag.md). - - Modify `PlatformSensorProvider::GetInstance()` to conditionally - create PlatformSensorProviderWinrt as defined in section 4.1. -- Testing: - - Add a simple test to validate that PlatformSensorProviderWinrt - can be instantiated without errors. - - Run feature flag unit test as defined - [here](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/how_to_add_your_feature_flag.md). - #### Change list 2: Implement PlatformSensorProviderWinrt - Feature Work:
diff --git a/services/device/public/cpp/device_features.cc b/services/device/public/cpp/device_features.cc index c3d99f8..ea3a47c 100644 --- a/services/device/public/cpp/device_features.cc +++ b/services/device/public/cpp/device_features.cc
@@ -18,5 +18,9 @@ // (Generic Sensor and Device Orientation). const base::Feature kSensorContentSetting{"SensorContentSetting", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enables usage of the Windows.Devices.Sensors WinRT API for the sensor +// backend instead of the ISensor API on Windows. +const base::Feature kWinrtSensorsImplementation{ + "WinrtSensorsImplementation", base::FEATURE_DISABLED_BY_DEFAULT}; } // namespace features
diff --git a/services/device/public/cpp/device_features.h b/services/device/public/cpp/device_features.h index 6696ed63..1650f549 100644 --- a/services/device/public/cpp/device_features.h +++ b/services/device/public/cpp/device_features.h
@@ -18,6 +18,7 @@ DEVICE_FEATURES_EXPORT extern const base::Feature kGenericSensor; DEVICE_FEATURES_EXPORT extern const base::Feature kGenericSensorExtraClasses; DEVICE_FEATURES_EXPORT extern const base::Feature kSensorContentSetting; +DEVICE_FEATURES_EXPORT extern const base::Feature kWinrtSensorsImplementation; } // namespace features
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc index c4c3a32..e774d58 100644 --- a/services/network/public/cpp/features.cc +++ b/services/network/public/cpp/features.cc
@@ -66,6 +66,16 @@ const base::Feature kRequestInitiatorSiteLock{"RequestInitiatorSiteLock", base::FEATURE_ENABLED_BY_DEFAULT}; +// When kPauseBrowserInitiatedHeavyTrafficForP2P is enabled, then a subset of +// the browser initiated traffic may be paused if there is at least one active +// P2P connection and the network is estimated to be congested. This feature is +// intended to throttle only the browser initiated traffic that is expected to +// be heavy (has large request/response sizes) when real time content might be +// streaming over an active P2P connection. +const base::Feature kPauseBrowserInitiatedHeavyTrafficForP2P{ + "PauseBrowserInitiatedHeavyTrafficForP2P", + base::FEATURE_DISABLED_BY_DEFAULT}; + bool ShouldEnableOutOfBlinkCors() { // OOR-CORS requires NetworkService. if (!base::FeatureList::IsEnabled(features::kNetworkService))
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h index c4fa3e8..2685828 100644 --- a/services/network/public/cpp/features.h +++ b/services/network/public/cpp/features.h
@@ -31,6 +31,8 @@ extern const base::Feature kFetchMetadataDestination; COMPONENT_EXPORT(NETWORK_CPP) extern const base::Feature kRequestInitiatorSiteLock; +COMPONENT_EXPORT(NETWORK_CPP) +extern const base::Feature kPauseBrowserInitiatedHeavyTrafficForP2P; COMPONENT_EXPORT(NETWORK_CPP) bool ShouldEnableOutOfBlinkCors();
diff --git a/services/network/resource_scheduler.cc b/services/network/resource_scheduler.cc index 8359ac4..e1b24954 100644 --- a/services/network/resource_scheduler.cc +++ b/services/network/resource_scheduler.cc
@@ -31,6 +31,7 @@ #include "net/log/net_log.h" #include "net/nqe/effective_connection_type_observer.h" #include "net/nqe/network_quality_estimator.h" +#include "net/nqe/peer_to_peer_connections_count_observer.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" #include "services/network/public/cpp/features.h" @@ -62,6 +63,7 @@ REQUEST_REPRIORITIZED, LONG_QUEUED_REQUESTS_TIMER_FIRED, EFFECTIVE_CONNECTION_TYPE_CHANGED, + PEER_TO_PEER_CONNECTIONS_COUNT_CHANGED, }; const char* RequestStartTriggerString(RequestStartTrigger trigger) { @@ -84,6 +86,8 @@ return "LONG_QUEUED_REQUESTS_TIMER_FIRED"; case RequestStartTrigger::EFFECTIVE_CONNECTION_TYPE_CHANGED: return "EFFECTIVE_CONNECTION_TYPE_CHANGED"; + case RequestStartTrigger::PEER_TO_PEER_CONNECTIONS_COUNT_CHANGED: + return "PEER_TO_PEER_CONNECTIONS_COUNT_CHANGED"; } } @@ -363,7 +367,9 @@ } // Each client represents a tab. -class ResourceScheduler::Client : public net::EffectiveConnectionTypeObserver { +class ResourceScheduler::Client + : public net::EffectiveConnectionTypeObserver, + public net::PeerToPeerConnectionsCountObserver { public: Client(bool is_browser_client, net::NetworkQualityEstimator* network_quality_estimator, @@ -383,13 +389,17 @@ network_quality_estimator_->GetEffectiveConnectionType(); UpdateParamsForNetworkQuality(); network_quality_estimator_->AddEffectiveConnectionTypeObserver(this); + network_quality_estimator_->AddPeerToPeerConnectionsCountObserver(this); } } ~Client() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (network_quality_estimator_) + if (network_quality_estimator_) { network_quality_estimator_->RemoveEffectiveConnectionTypeObserver(this); + network_quality_estimator_->RemovePeerToPeerConnectionsCountObserver( + this); + } } void ScheduleRequest(const net::URLRequest& url_request, @@ -525,6 +535,29 @@ RequestStartTrigger::EFFECTIVE_CONNECTION_TYPE_CHANGED); } + // net::PeerToPeerConnectionsCountObserver: + void OnPeerToPeerConnectionsCountChange(uint32_t count) override { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (p2p_connections_count_ == count) + return; + + p2p_connections_count_ = count; + + if (p2p_connections_count_ > 0 && + !p2p_connections_count_active_timestamp_.has_value()) { + p2p_connections_count_active_timestamp_ = base::TimeTicks::Now(); + } + + if (p2p_connections_count_ == 0 && + p2p_connections_count_active_timestamp_.has_value()) { + p2p_connections_count_active_timestamp_ = base::nullopt; + } + + LoadAnyStartablePendingRequests( + RequestStartTrigger::PEER_TO_PEER_CONNECTIONS_COUNT_CHANGED); + } + // Records the metrics related to number of requests in flight. void RecordRequestCountMetrics() const { UMA_HISTOGRAM_COUNTS_100("ResourceScheduler.RequestsCount.All", @@ -800,6 +833,77 @@ request->Start(start_mode); } + // Returns true if |request| should be throttled to avoid network contention + // with active P2P connections. + bool ShouldThrottleBrowserInitiatedRequestDueToP2PConnections( + const ScheduledResourceRequestImpl& request) const { + DCHECK(is_browser_client_); + + if (!base::FeatureList::IsEnabled( + features::kPauseBrowserInitiatedHeavyTrafficForP2P)) { + return false; + } + + if (p2p_connections_count_ == 0) + return false; + + // Only throttle when effective connection type is between Slow2G and 3G. + if (effective_connection_type_ <= net::EFFECTIVE_CONNECTION_TYPE_OFFLINE || + effective_connection_type_ >= net::EFFECTIVE_CONNECTION_TYPE_4G) { + return false; + } + + if (request.url_request()->priority() == net::HIGHEST) + return false; + + base::TimeDelta time_since_p2p_connections_active = + tick_clock_->NowTicks() - + p2p_connections_count_active_timestamp_.value(); + + base::Optional<base::TimeDelta> max_wait_time_p2p_connections = + resource_scheduler_->resource_scheduler_params_manager_ + .max_wait_time_p2p_connections(); + + if (time_since_p2p_connections_active > + max_wait_time_p2p_connections.value()) { + return false; + } + + // Check other request specific constraints. + const net::NetworkTrafficAnnotationTag& traffic_annotation = + request.url_request()->traffic_annotation(); + const int32_t unique_id_hash_code = traffic_annotation.unique_id_hash_code; + + if (!resource_scheduler_->resource_scheduler_params_manager_ + .CanThrottleNetworkTrafficAnnotationHash(unique_id_hash_code)) { + return false; + } + + return true; + } + + // Records metrics on browser initiated requests. Called when the request is + // dispatched to the network. + void RecordMetricsForBrowserInitiatedRequestsOnNetworkDispatch( + const ScheduledResourceRequestImpl& request) const { + const net::NetworkTrafficAnnotationTag& traffic_annotation = + request.url_request()->traffic_annotation(); + const int32_t unique_id_hash_code = traffic_annotation.unique_id_hash_code; + + // Metrics are recorded only for browser initiated requests that are + // eligible for throttling. + if (!resource_scheduler_->resource_scheduler_params_manager_ + .CanThrottleNetworkTrafficAnnotationHash(unique_id_hash_code)) { + return; + } + + base::TimeDelta queuing_duration = + tick_clock_->NowTicks() - request.url_request()->creation_time(); + UMA_HISTOGRAM_LONG_TIMES( + "ResourceScheduler.BrowserInitiatedHeavyRequest.QueuingDuration", + queuing_duration); + } + // ShouldStartRequest is the main scheduling algorithm. // // Requests are evaluated on five attributes: @@ -839,8 +943,13 @@ if (!resource_scheduler_->enabled()) return START_REQUEST; - // Currently, browser initiated requests are not throttled. + // Browser requests are treated differently since they are not user-facing. if (is_browser_client_) { + if (ShouldThrottleBrowserInitiatedRequestDueToP2PConnections(*request)) { + return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; + } + + RecordMetricsForBrowserInitiatedRequestsOnNetworkDispatch(*request); return START_REQUEST; } @@ -1068,6 +1177,15 @@ net::EffectiveConnectionType effective_connection_type_ = net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN; + // Current count of active peer to peer connections. + uint32_t p2p_connections_count_ = 0u; + + // Earliest timestamp since when there is at least one active peer to peer + // connection. Set to current timestamp when |p2p_connections_count_| + // changes from 0 to a non-zero value. Reset to null when + // |p2p_connections_count_| becomes 0. + base::Optional<base::TimeTicks> p2p_connections_count_active_timestamp_; + SEQUENCE_CHECKER(sequence_checker_); base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_{this};
diff --git a/services/network/resource_scheduler_params_manager.cc b/services/network/resource_scheduler_params_manager.cc index 17dd66b..15dc7de 100644 --- a/services/network/resource_scheduler_params_manager.cc +++ b/services/network/resource_scheduler_params_manager.cc
@@ -9,14 +9,52 @@ #include "base/metrics/field_trial_params.h" #include "base/optional.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" #include "net/nqe/network_quality_estimator.h" #include "net/nqe/network_quality_estimator_params.h" +#include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/cpp/features.h" namespace network { namespace { +base::Optional<base::TimeDelta> GetMaxWaitTimeP2PConnections() { + if (!base::FeatureList::IsEnabled( + features::kPauseBrowserInitiatedHeavyTrafficForP2P)) { + return base::nullopt; + } + + int max_wait_time_p2p_connections_in_minutes = + base::GetFieldTrialParamByFeatureAsInt( + features::kPauseBrowserInitiatedHeavyTrafficForP2P, + "max_wait_time_p2p_connections_in_minutes", 60); + + return base::TimeDelta::FromMinutes(max_wait_time_p2p_connections_in_minutes); +} + +std::set<int32_t> GetThrottledHashes() { + std::set<int32_t> throttled_hashes; + + const std::string& throttled_traffic_annotation_tags = + base::GetFieldTrialParamValueByFeature( + features::kPauseBrowserInitiatedHeavyTrafficForP2P, + "throttled_traffic_annotation_tags"); + + const std::vector<std::string>& tokens = + base::SplitString(throttled_traffic_annotation_tags, ",", + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + + for (const std::string& token : tokens) { + int int_token; + bool successful = base::StringToInt(token, &int_token); + if (!successful) + continue; + throttled_hashes.insert(int_token); + } + return throttled_hashes; +} + // The maximum number of delayable requests to allow to be in-flight at any // point in time (across all hosts). constexpr size_t kDefaultMaxNumDelayableRequestsPerClient = 10; @@ -216,12 +254,17 @@ const ParamsForNetworkQualityContainer& params_for_network_quality_container) : params_for_network_quality_container_( - params_for_network_quality_container) {} + params_for_network_quality_container), + max_wait_time_p2p_connections_(GetMaxWaitTimeP2PConnections()), + throttled_traffic_annotation_hashes_(GetThrottledHashes()) {} ResourceSchedulerParamsManager::ResourceSchedulerParamsManager( const ResourceSchedulerParamsManager& other) : params_for_network_quality_container_( - other.params_for_network_quality_container_) {} + other.params_for_network_quality_container_), + max_wait_time_p2p_connections_(other.max_wait_time_p2p_connections_), + throttled_traffic_annotation_hashes_( + other.throttled_traffic_annotation_hashes_) {} ResourceSchedulerParamsManager::~ResourceSchedulerParamsManager() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -239,4 +282,15 @@ false, base::nullopt); } +bool ResourceSchedulerParamsManager::CanThrottleNetworkTrafficAnnotationHash( + const int32_t unique_id_hash_code) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // TODO(tbansal): Replace this check by an algorithm that builds history + // locally, records exponential weighted moving average of request size per + // tag. Next, using this database, the algorithm throttles requests whose tag + // cause the most traffic. + return throttled_traffic_annotation_hashes_.find(unique_id_hash_code) != + throttled_traffic_annotation_hashes_.end(); +} + } // namespace network
diff --git a/services/network/resource_scheduler_params_manager.h b/services/network/resource_scheduler_params_manager.h index ab866e2..99ec21b 100644 --- a/services/network/resource_scheduler_params_manager.h +++ b/services/network/resource_scheduler_params_manager.h
@@ -9,6 +9,8 @@ #include <stdint.h> #include <map> +#include <set> +#include <unordered_set> #include "base/component_export.h" #include "base/optional.h" @@ -80,12 +82,29 @@ Reset(other.params_for_network_quality_container_); } + // Returns the maximum time for which the browser initiated traffic can be + // paused when there are active P2P connections. + const base::Optional<base::TimeDelta>& max_wait_time_p2p_connections() const { + return max_wait_time_p2p_connections_; + } + + // Returns true if the browser initiated traffic with traffic annotation + // |unique_id_hash_code| can be paused when there are active P2P connections. + bool CanThrottleNetworkTrafficAnnotationHash( + const int32_t unique_id_hash_code) const; + private: // The number of delayable requests in-flight for different ranges of the // network quality. ParamsForNetworkQualityContainer params_for_network_quality_container_; + const base::Optional<base::TimeDelta> max_wait_time_p2p_connections_; + + const std::set<int32_t> throttled_traffic_annotation_hashes_; + SEQUENCE_CHECKER(sequence_checker_); + + DISALLOW_ASSIGN(ResourceSchedulerParamsManager); }; } // namespace network
diff --git a/services/network/resource_scheduler_unittest.cc b/services/network/resource_scheduler_unittest.cc index 9f30a37..2705168d 100644 --- a/services/network/resource_scheduler_unittest.cc +++ b/services/network/resource_scheduler_unittest.cc
@@ -216,17 +216,19 @@ std::unique_ptr<net::URLRequest> NewURLRequestWithChildAndRoute( const char* url, net::RequestPriority priority, + const net::NetworkTrafficAnnotationTag& traffic_annotation, int child_id, int route_id) { std::unique_ptr<net::URLRequest> url_request(context_.CreateRequest( - GURL(url), priority, nullptr, TRAFFIC_ANNOTATION_FOR_TESTS)); + GURL(url), priority, nullptr, traffic_annotation)); return url_request; } std::unique_ptr<net::URLRequest> NewURLRequest( const char* url, net::RequestPriority priority) { - return NewURLRequestWithChildAndRoute(url, priority, kChildId, kRouteId); + return NewURLRequestWithChildAndRoute( + url, priority, TRAFFIC_ANNOTATION_FOR_TESTS, kChildId, kRouteId); } std::unique_ptr<TestRequest> NewRequestWithRoute( @@ -241,7 +243,8 @@ net::RequestPriority priority, int child_id, int route_id) { - return GetNewTestRequest(url, priority, child_id, route_id, true); + return GetNewTestRequest(url, priority, TRAFFIC_ANNOTATION_FOR_TESTS, + child_id, route_id, true); } std::unique_ptr<TestRequest> NewRequest(const char* url, @@ -263,6 +266,14 @@ kBrowserRouteId); } + std::unique_ptr<TestRequest> NewBrowserRequestWithAnnotationTag( + const char* url, + net::RequestPriority priority, + const net::NetworkTrafficAnnotationTag& traffic_annotation) { + return GetNewTestRequest(url, priority, traffic_annotation, kBrowserChildId, + kBrowserRouteId, true); + } + std::unique_ptr<TestRequest> NewSyncRequest(const char* url, net::RequestPriority priority) { return NewSyncRequestWithChildAndRoute(url, priority, kChildId, kRouteId); @@ -280,16 +291,19 @@ net::RequestPriority priority, int child_id, int route_id) { - return GetNewTestRequest(url, priority, child_id, route_id, false); + return GetNewTestRequest(url, priority, TRAFFIC_ANNOTATION_FOR_TESTS, + child_id, route_id, false); } - std::unique_ptr<TestRequest> GetNewTestRequest(const char* url, - net::RequestPriority priority, - int child_id, - int route_id, - bool is_async) { - std::unique_ptr<net::URLRequest> url_request( - NewURLRequestWithChildAndRoute(url, priority, child_id, route_id)); + std::unique_ptr<TestRequest> GetNewTestRequest( + const char* url, + net::RequestPriority priority, + const net::NetworkTrafficAnnotationTag& traffic_annotation, + int child_id, + int route_id, + bool is_async) { + std::unique_ptr<net::URLRequest> url_request(NewURLRequestWithChildAndRoute( + url, priority, traffic_annotation, child_id, route_id)); auto scheduled_request = scheduler_->ScheduleRequest( child_id, route_id, is_async, url_request.get()); auto request = std::make_unique<TestRequest>( @@ -731,6 +745,173 @@ } } +// Verify that browser requests are throttled by the resource scheduler only +// when all the conditions are met. +TEST_F(ResourceSchedulerTest, + LowerPriorityBrowserRequestsThrottleP2PConnections) { + const struct { + std::string test_case; + size_t p2p_active_connections; + net::EffectiveConnectionType effective_connection_type; + bool enable_pausing_behavior; + bool set_field_trial_param; + bool expected_browser_initiated_traffic_started; + } tests[] = { + { + "Field trial set", + 1u, + net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, + true, + true, + false, + }, + { + "Field trial not set", + 1u, + net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, + false, + true, + true, + }, + { + "Network fast", + 1u, + net::EFFECTIVE_CONNECTION_TYPE_4G, + true, + true, + true, + }, + { + "No active p2p connections", + 0u, + net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, + true, + true, + true, + }, + { + "Field trial param not set", + 1u, + net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G, + true, + false, + true, + }, + }; + + for (const auto& test : tests) { + base::test::ScopedFeatureList scoped_feature_list; + if (test.enable_pausing_behavior) { + base::FieldTrialParams field_trial_params; + if (test.set_field_trial_param) { + field_trial_params["throttled_traffic_annotation_tags"] = "727528"; + } + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kPauseBrowserInitiatedHeavyTrafficForP2P, + field_trial_params); + } else { + scoped_feature_list.InitAndDisableFeature( + features::kPauseBrowserInitiatedHeavyTrafficForP2P); + } + InitializeScheduler(); + + network_quality_estimator_ + .SetAndNotifyObserversOfP2PActiveConnectionsCountChange( + test.p2p_active_connections); + network_quality_estimator_.SetAndNotifyObserversOfEffectiveConnectionType( + test.effective_connection_type); + + std::string url = "http://host/browser-initiatited"; + + net::NetworkTrafficAnnotationTag tag = net::DefineNetworkTrafficAnnotation( + "metrics_report_uma", + "Traffic annotation for unit, browser and other tests"); + // (COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("")); + std::unique_ptr<TestRequest> lows = (NewBrowserRequestWithAnnotationTag( + url.c_str(), net::LOWEST, tag)); //"metrics_report_uma")); + EXPECT_EQ(test.expected_browser_initiated_traffic_started, lows->started()); + } +} + +// Verify that browser requests that are currently queued are dispatched to the +// network as soon as the active P2P connections count drops to 0. +TEST_F(ResourceSchedulerTest, P2PConnectionWentAway) { + base::test::ScopedFeatureList scoped_feature_list; + base::HistogramTester histogram_tester; + base::FieldTrialParams field_trial_params; + field_trial_params["throttled_traffic_annotation_tags"] = "727528"; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kPauseBrowserInitiatedHeavyTrafficForP2P, field_trial_params); + InitializeScheduler(); + + network_quality_estimator_ + .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(1u); + network_quality_estimator_.SetAndNotifyObserversOfEffectiveConnectionType( + net::EFFECTIVE_CONNECTION_TYPE_2G); + + std::string url = "http://host/browser-initiatited"; + + net::NetworkTrafficAnnotationTag tag = net::DefineNetworkTrafficAnnotation( + "metrics_report_uma", + "Traffic annotation for unit, browser and other tests"); + // (COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("")); + std::unique_ptr<TestRequest> lows = (NewBrowserRequestWithAnnotationTag( + url.c_str(), net::LOWEST, tag)); //"metrics_report_uma")); + EXPECT_FALSE(lows->started()); + + network_quality_estimator_ + .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(2u); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(lows->started()); + + network_quality_estimator_ + .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(0u); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(lows->started()); + histogram_tester.ExpectTotalCount( + "ResourceScheduler.BrowserInitiatedHeavyRequest.QueuingDuration", 1u); +} + +// Verify that the previously queued browser requests are dispatched to the +// network when the network quality becomes faster. +TEST_F(ResourceSchedulerTest, + RequestThrottleOnlyOnSlowConnectionsWithP2PRequests) { + base::HistogramTester histogram_tester; + base::test::ScopedFeatureList scoped_feature_list; + base::FieldTrialParams field_trial_params; + field_trial_params["throttled_traffic_annotation_tags"] = "727528"; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kPauseBrowserInitiatedHeavyTrafficForP2P, field_trial_params); + InitializeScheduler(); + + network_quality_estimator_ + .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(1u); + network_quality_estimator_.SetAndNotifyObserversOfEffectiveConnectionType( + net::EFFECTIVE_CONNECTION_TYPE_2G); + + std::string url = "http://host/browser-initiatited"; + + net::NetworkTrafficAnnotationTag tag = net::DefineNetworkTrafficAnnotation( + "metrics_report_uma", + "Traffic annotation for unit, browser and other tests"); + // (COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("")); + std::unique_ptr<TestRequest> lows = (NewBrowserRequestWithAnnotationTag( + url.c_str(), net::LOWEST, tag)); //"metrics_report_uma")); + EXPECT_FALSE(lows->started()); + + network_quality_estimator_ + .SetAndNotifyObserversOfP2PActiveConnectionsCountChange(2u); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(lows->started()); + + network_quality_estimator_.SetAndNotifyObserversOfEffectiveConnectionType( + net::EFFECTIVE_CONNECTION_TYPE_4G); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(lows->started()); + histogram_tester.ExpectTotalCount( + "ResourceScheduler.BrowserInitiatedHeavyRequest.QueuingDuration", 1u); +} + TEST_F(ResourceSchedulerTest, ReprioritizedRequestGoesToBackOfQueue) { // Dummies to enforce scheduling. SetMaxDelayableRequests(1); @@ -1432,7 +1613,8 @@ another_scheduler.SetResourceSchedulerParamsManagerForTests( FixedParamsManager(1)); std::unique_ptr<net::URLRequest> url_request(NewURLRequestWithChildAndRoute( - "http://host/another", net::LOWEST, kChildId, kRouteId)); + "http://host/another", net::LOWEST, TRAFFIC_ANNOTATION_FOR_TESTS, + kChildId, kRouteId)); auto scheduled_request = another_scheduler.ScheduleRequest( kChildId, kRouteId, true, url_request.get()); auto another_request = std::make_unique<TestRequest>( @@ -1787,7 +1969,8 @@ for (int i = 0; i < max_low_priority_requests_allowed + 10; ++i) { EXPECT_EQ(i < max_low_priority_requests_allowed, - lows_singlehost[i]->started()); + lows_singlehost[i]->started()) + << " i=" << i; } }
diff --git a/services/network/sec_header_helpers.cc b/services/network/sec_header_helpers.cc index bb55cce..7241385a 100644 --- a/services/network/sec_header_helpers.cc +++ b/services/network/sec_header_helpers.cc
@@ -22,6 +22,11 @@ bool IsSameSite(const url::Origin& initiator, const url::Origin& target_origin) { + // Cross-scheme initiator should be considered cross-site (even if it's host + // is same-site with the target). See also https://crbug.com/979257. + if (initiator.scheme() != target_origin.scheme()) + return false; + return net::registry_controlled_domains::SameDomainOrHost( initiator, target_origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
diff --git a/services/tracing/perfetto/system_perfetto_unittest.cc b/services/tracing/perfetto/system_perfetto_unittest.cc index 0e628c23..476b353c 100644 --- a/services/tracing/perfetto/system_perfetto_unittest.cc +++ b/services/tracing/perfetto/system_perfetto_unittest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <cerrno> #include <cstdlib> #include <memory> #include <string> @@ -10,9 +11,12 @@ #include "base/android/build_info.h" #include "base/bind.h" +#include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" +#include "base/rand_util.h" #include "base/run_loop.h" #include "base/strings/strcat.h" +#include "base/strings/string_number_conversions.h" #include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" @@ -25,6 +29,8 @@ #include "services/tracing/public/cpp/tracing_features.h" #include "testing/gtest/include/gtest/gtest-death-test.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/perfetto/protos/perfetto/config/trace_config.pb.h" +#include "third_party/perfetto/protos/perfetto/trace/trace.pb.h" namespace tracing { @@ -34,6 +40,14 @@ "org.chromium.chrome_integration_unittest"; const char kPerfettoProducerName[] = "org.chromium.perfetto_producer.123"; +std::string RandomASCII(size_t length) { + std::string tmp; + for (size_t i = 0; i < length; ++i) { + tmp += base::RandInt('a', 'z'); + } + return tmp; +} + class SystemPerfettoTest : public testing::Test { public: SystemPerfettoTest() @@ -113,6 +127,50 @@ PerfettoService* local_service() const { return perfetto_service_.get(); } void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); } + // Fork() + executes the perfetto cmdline client with the given args and + // returns true if we exited with a success otherwise |stderr_| is populated + // with the reason for the failure. + bool ExecPerfetto(std::initializer_list<std::string> args, + std::string config) { + stderr_.clear(); + base::CommandLine cmd(base::FilePath("/system/bin/perfetto")); + for (auto& arg : args) { + cmd.AppendArg(std::move(arg)); + } + std::string config_path = + tmp_dir_.GetPath().Append(FILE_PATH_LITERAL("trace_config")).value(); + config_path += RandomASCII(16); + cmd.AppendArgPath(base::FilePath(config_path)); + base::File config_file( + base::FilePath(config_path), + base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + if (!config_file.IsValid()) { + stderr_ = "Tried to create "; + stderr_ += config_path; + stderr_ += " but failed with error "; + stderr_ += base::File::ErrorToString(config_file.error_details()); + return false; + } + size_t written = config_file.Write(0, config.data(), config.size()); + if (written != config.size()) { + stderr_ = base::StrCat({"Expected ", base::NumberToString(config.size()), + " bytes written but actually wrote ", + base::NumberToString(written)}); + return false; + } + config_file.Close(); + + bool succeeded = base::GetAppOutputAndError(cmd, &stderr_); + if (!succeeded) { + stderr_ += + " !!! end of |stderr_| this was generated by the commandline: "; + stderr_ += cmd.GetCommandLineString(); + } + // This just cleans up the config file we generated above. + EXPECT_EQ(0, remove(config_path.c_str())); + return succeeded; + } + protected: // |tmp_dir_| must be destroyed last. So must be declared first. base::ScopedTempDir tmp_dir_; @@ -121,6 +179,7 @@ std::unique_ptr<PerfettoService> perfetto_service_; std::vector<std::unique_ptr<TestDataSource>> data_sources_; base::test::ScopedTaskEnvironment scoped_task_environment_; + std::string stderr_; }; TEST_F(SystemPerfettoTest, SystemTraceEndToEnd) { @@ -153,6 +212,49 @@ PerfettoProducer::DeleteSoonForTesting(std::move(system_producer)); } +TEST_F(SystemPerfettoTest, SystemTraceEndToEndRealService) { + if (base::android::BuildInfo::GetInstance()->sdk_int() < + base::android::SDK_VERSION_P) { + LOG(INFO) + << "Skipping SystemTraceEndToEndRealService test, this phone " + << "is pre P SDK, which means there is no 'real' service running."; + return; + } + + perfetto::protos::TraceConfig trace_config; + trace_config.add_buffers()->set_size_kb(1024); + trace_config.add_data_sources()->mutable_config()->set_name( + data_sources_[0]->name()); + trace_config.add_data_sources()->mutable_config()->set_name( + data_sources_[2]->name()); + trace_config.set_duration_ms(100); + + std::string path = "/data/misc/perfetto-traces/trace"; + path += RandomASCII(16); + EXPECT_TRUE( + ExecPerfetto({"-o", path, "-c"}, trace_config.SerializeAsString())) + << "failed with stderr: \"" << stderr_ << "\""; + + char* data = new char[1024 * 1024]; + ASSERT_TRUE(data); + int num_bytes = base::ReadFile(base::FilePath(path), data, (1024 * 1024) - 1); + EXPECT_NE(num_bytes, -1); + std::string output(data, num_bytes); + delete[] data; + + perfetto::protos::Trace trace; + EXPECT_TRUE(trace.ParseFromString(output)); + + int count = 0; + for (const auto& packet : trace.packet()) { + if (packet.has_for_testing()) { + ++count; + } + } + EXPECT_EQ(1 + 7, count); + EXPECT_EQ(0, remove(path.c_str())); +} + TEST_F(SystemPerfettoTest, OneSystemSourceWithMultipleLocalSources) { auto system_service = CreateMockSystemService(); @@ -241,8 +343,7 @@ PerfettoProducer::DeleteSoonForTesting(std::move(system_producer)); } -TEST_F(SystemPerfettoTest, - MultipleSystemSourceWithOneLocalSourcesLocalFirst) { +TEST_F(SystemPerfettoTest, MultipleSystemSourceWithOneLocalSourcesLocalFirst) { auto system_service = CreateMockSystemService(); base::RunLoop local_no_more_packets_runloop;
diff --git a/services/tracing/public/cpp/perfetto/perfetto_config.cc b/services/tracing/public/cpp/perfetto/perfetto_config.cc index 5d31211..3323a72 100644 --- a/services/tracing/public/cpp/perfetto/perfetto_config.cc +++ b/services/tracing/public/cpp/perfetto/perfetto_config.cc
@@ -42,7 +42,22 @@ if (size_limit == 0) { size_limit = 100 * 1024; } - perfetto_config.add_buffers()->set_size_kb(size_limit); + auto* buffer_config = perfetto_config.add_buffers(); + buffer_config->set_size_kb(size_limit); + switch (chrome_config.GetTraceRecordMode()) { + case base::trace_event::RECORD_UNTIL_FULL: + case base::trace_event::RECORD_AS_MUCH_AS_POSSIBLE: + buffer_config->set_fill_policy( + perfetto::TraceConfig::BufferConfig::FillPolicy::DISCARD); + break; + case base::trace_event::RECORD_CONTINUOUSLY: + buffer_config->set_fill_policy( + perfetto::TraceConfig::BufferConfig::FillPolicy::RING_BUFFER); + break; + case base::trace_event::ECHO_TO_CONSOLE: + NOTREACHED(); + break; + } // Perfetto uses clock_gettime for its internal snapshotting, which gets // blocked by the sandboxed and isn't needed for Chrome regardless.
diff --git a/services/tracing/public/cpp/trace_event_args_whitelist.cc b/services/tracing/public/cpp/trace_event_args_whitelist.cc index 3d1de85..79fb67d 100644 --- a/services/tracing/public/cpp/trace_event_args_whitelist.cc +++ b/services/tracing/public/cpp/trace_event_args_whitelist.cc
@@ -37,6 +37,9 @@ const char* const kV8GCAllowedArgs[] = {"num_items", "num_tasks", nullptr}; const char* const kTopLevelFlowAllowedArgs[] = {"task_queue_name", nullptr}; const char* const kTopLevelIpcRunTaskAllowedArgs[] = {"ipc_hash", nullptr}; +const char* const kLifecyclesTaskPostedAllowedArgs[] = { + "task_queue_name", "time_since_disabled_ms", "ipc_hash", "location", + nullptr}; const WhitelistEntry kEventArgsWhitelist[] = { {"__metadata", "thread_name", nullptr}, @@ -72,6 +75,8 @@ {"ui", "UserEvent", nullptr}, {TRACE_DISABLED_BY_DEFAULT("toplevel.flow"), "SequenceManager::PostTask", kTopLevelFlowAllowedArgs}, + {TRACE_DISABLED_BY_DEFAULT("lifecycles"), "task_posted_to_disabled_queue", + kLifecyclesTaskPostedAllowedArgs}, {nullptr, nullptr, nullptr}}; const char* kMetadataWhitelist[] = {"chrome-bitness",
diff --git a/sql/recover_module/btree.cc b/sql/recover_module/btree.cc index 72ee3f1..57067ac 100644 --- a/sql/recover_module/btree.cc +++ b/sql/recover_module/btree.cc
@@ -44,7 +44,7 @@ "Move the destructor to the .cc file if it's non-trival"); #endif // !DCHECK_IS_ON() -InnerPageDecoder::InnerPageDecoder(DatabasePageReader* db_reader) +InnerPageDecoder::InnerPageDecoder(DatabasePageReader* db_reader) noexcept : page_id_(db_reader->page_id()), db_reader_(db_reader), cell_count_(ComputeCellCount(db_reader)), @@ -135,7 +135,7 @@ "Move the destructor to the .cc file if it's non-trival"); #endif // !DCHECK_IS_ON() -LeafPageDecoder::LeafPageDecoder(DatabasePageReader* db_reader) +LeafPageDecoder::LeafPageDecoder(DatabasePageReader* db_reader) noexcept : page_id_(db_reader->page_id()), db_reader_(db_reader), cell_count_(ComputeCellCount(db_reader)),
diff --git a/storage/browser/quota/quota_task.cc b/storage/browser/quota/quota_task.cc index a937c4b..ff04875 100644 --- a/storage/browser/quota/quota_task.cc +++ b/storage/browser/quota/quota_task.cc
@@ -22,7 +22,7 @@ QuotaTask::~QuotaTask() = default; void QuotaTask::Start() { - DCHECK(observer_); + DCHECK(observer_ != nullptr); observer()->RegisterTask(this); Run(); } @@ -31,6 +31,7 @@ : observer_(observer), original_task_runner_(base::ThreadTaskRunnerHandle::Get()), delete_scheduled_(false) { + DCHECK(observer != nullptr); } void QuotaTask::CallCompleted() {
diff --git a/storage/browser/quota/quota_task.h b/storage/browser/quota/quota_task.h index 11dcafd..09af2a7 100644 --- a/storage/browser/quota/quota_task.h +++ b/storage/browser/quota/quota_task.h
@@ -45,17 +45,15 @@ void DeleteSoon(); QuotaTaskObserver* observer() const { return observer_; } - base::SingleThreadTaskRunner* original_task_runner() const { - return original_task_runner_.get(); - } private: friend class base::DeleteHelper<QuotaTask>; friend class QuotaTaskObserver; void Abort(); + QuotaTaskObserver* observer_; - scoped_refptr<base::SingleThreadTaskRunner> original_task_runner_; + const scoped_refptr<base::SingleThreadTaskRunner> original_task_runner_; bool delete_scheduled_; };
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index 4007415..0561e63 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -26012,6 +26012,50 @@ ] }, "test": "monochrome_public_test_ar_apk" + }, + { + "args": [ + "--gs-results-bucket=chromium-result-details", + "--recover-devices" + ], + "merge": { + "args": [ + "--bucket", + "chromium-result-details", + "--test-name", + "services_unittests" + ], + "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": "PQ1A.190105.004", + "device_os_type": "userdebug", + "device_type": "walleye", + "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" + } + ] + }, + "test": "services_unittests" } ] }
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 202b82a..b44e1163 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -632,6 +632,36 @@ "script": "//testing/trigger_scripts/chromeos_device_trigger.py" } } + ], + "isolated_scripts": [ + { + "args": [ + "--browser=cros-chrome", + "--remote=variable_chromeos_device_hostname", + "--xvfb" + ], + "isolate_name": "telemetry_perf_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "telemetry_perf_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_type": "kevin", + "os": "ChromeOS", + "pool": "chrome-cros-dut" + } + ], + "idempotent": false, + "shards": 2 + }, + "trigger_script": { + "script": "//testing/trigger_scripts/chromeos_device_trigger.py" + } + } ] }, "linux-chromeos-dbg": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 506e54d7..ab71672 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -120,7 +120,8 @@ "gtest_tests": [ { "args": [ - "--enable-features=VizDisplayCompositor,UseSkiaRenderer" + "--enable-features=VizDisplayCompositor,UseSkiaRenderer", + "--test-launcher-filter-file=../../testing/buildbot/filters/skia_renderer.browser_tests.filter" ], "merge": { "args": [], @@ -6252,36 +6253,7 @@ "args": [ "--browser=cros-chrome", "--remote=variable_chromeos_device_hostname", - "--xvfb" - ], - "isolate_name": "telemetry_perf_unittests", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "telemetry_perf_unittests", - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "device_type": "kevin", - "os": "ChromeOS", - "pool": "chrome-cros-dut" - } - ], - "idempotent": false, - "shards": 6 - }, - "trigger_script": { - "script": "//testing/trigger_scripts/chromeos_device_trigger.py" - } - }, - { - "args": [ - "--browser=cros-chrome", - "--remote=variable_chromeos_device_hostname", - "--jobs=1", - "--retry-limit=1" + "--jobs=1" ], "isolate_name": "telemetry_unittests", "merge": {
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index 6bb9205..667af1d 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -6951,6 +6951,7 @@ "args": [ "--use-vulkan=native", "--disable-vulkan-fallback-to-gl-for-testing", + "--enable-features=UseSkiaRenderer", "--test-launcher-filter-file=../../testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter", "--gs-results-bucket=chromium-result-details", "--recover-devices"
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn index 8c9d01bf..7386b228 100644 --- a/testing/buildbot/filters/BUILD.gn +++ b/testing/buildbot/filters/BUILD.gn
@@ -36,6 +36,7 @@ testonly = true data = [ + "//testing/buildbot/filters/skia_renderer.browser_tests.filter", "//testing/buildbot/filters/webui_html_imports_polyfill_browser_tests.filter", "//testing/buildbot/filters/webrtc_functional.browser_tests.filter", "//testing/buildbot/filters/navigation_loader_on_ui_browser_tests.filter",
diff --git a/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter b/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter index e24de01..36bfd86 100644 --- a/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter +++ b/testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter
@@ -1,11 +1,9 @@ # crbug.com/963266: Android SkiaRenderer Vulkan content_browsertests failures -AccessibilityHitTestingBrowserTest.HitTestingWithPinchZoom +-BrowserSideFlingBrowserTest.InertialGSEGetsBubbledFromOOPIF -BrowserSideFlingBrowserTest.InertialGSUBubblingStopsWhenParentCannotScroll --DumpAccessibilityTreeTest.AccessibilityDfn/blink --DumpAccessibilityTreeTest.AccessibilityOffscreen/blink --DumpAccessibilityTreeTest.AccessibilityOffscreenScroll/blink --DumpAccessibilityTreeTest.AccessibilityOffscreenSelect/blink --DumpAccessibilityTreeTest.AccessibilityWindowCropsItems/blink +-*CompositorImplLowEndBrowserTest.CompositorImplDropsResourcesOnBackground* +-DumpAccessibilityTreeTest.* -File/MediaTest.VideoBearMp4/0 -File/MediaTest.VideoTulipWebm/0 -Http/MediaTest.VideoBearMp4/0 @@ -28,9 +26,11 @@ -MSE_ExternalClearKey/EncryptedMediaTest.Playback_Encryption_CBCS_Video_CENC_Audio/0 -MSE_ExternalClearKey/EncryptedMediaTest.Playback_Encryption_CENC/0 -MSE_ExternalClearKey/EncryptedMediaTest.Playback_Encryption_CENC_Video_CBCS_Audio/0 +-NavigationBrowserTest.* -NavigationControllerBrowserTest.DontIgnoreBackAfterNavEntryLimit -NavigationControllerBrowserTest.ReloadWithUrlAnchor -NavigationControllerBrowserTest.ReloadWithUrlAnchorAndScroll +-NavigationDownloadBrowserTest.StopLoadingAfterDroppedNavigation/0 -OOPBrowserTest.Basic -P/CompositorImplBrowserTestRefreshRate.VideoPreference/0 -SitePerProcessBrowserTest.ChildFrameCrashMetrics_ScrolledIntoViewAfterTabIsShown @@ -40,6 +40,7 @@ -SitePerProcessBrowserTest.ReloadHiddenTabWithCrashedSubframe -SitePerProcessBrowserTest.ScaledIframeRasterSize -SitePerProcessBrowserTest.ScrollOopifInPinchZoomedPage +-SitePerProcessBrowserTest.SubframeReusesExistingProcess -SitePerProcessBrowserTest.SubframeVisibleAfterRenderViewBecomesSwappedOut -SitePerProcessBrowserTest.UnloadNestedPendingDeletion -SitePerProcessEmulatedTouchBrowserTest.EmulatedGestureScrollBubbles/0 @@ -69,15 +70,15 @@ -TouchActionBrowserTest.PanXYMainThreadJanky/1 -TouchActionBrowserTest.PanYMainThreadJanky/1 -TouchSelectionControllerClientAndroidSiteIsolationTest.BasicSelectionIsolatedIframe +-TracingControllerTest.ProcessesPresentInTrace -WebContentsImplBrowserTest.PopupWindowBrowserNavResumeLoad -WebContentsImplBrowserTest.SetPageFrozen --WebRtcBrowserTest.CanSetupH264VideoCallOnSupportedDevice +-WebRtcBrowserTest.* -WebRtcCaptureFromElementBrowserTest.CaptureFromCanvas2DHandlesContextLoss -WebRtcCaptureFromElementBrowserTest.VerifyCanvasCaptureOffscreenCanvasFrames -WebRtcCaptureFromElementBrowserTest.VerifyCanvasCaptureWebGLFrames -WebRtcCaptureFromElementBrowserTest.VerifyCanvasCapture2DFrames -WebRtcCaptureFromElementBrowserTest.VerifyCanvas2DCaptureColor --WebRtcGetUserMediaBrowserTest.TestGetUserMediaAspectRatio1To1/0 --WebRtcGetUserMediaBrowserTest.TestGetUserMediaAspectRatio4To3/0 +-WebRtcGetUserMediaBrowserTest.* -WithOutOfBlinkCors/CrossSiteDocumentBlockingTest.BlockImages/0 -WithoutOutOfBlinkCors/CrossSiteDocumentBlockingTest.BlockImages/0
diff --git a/testing/buildbot/filters/skia_renderer.browser_tests.filter b/testing/buildbot/filters/skia_renderer.browser_tests.filter new file mode 100644 index 0000000..e2e76f9 --- /dev/null +++ b/testing/buildbot/filters/skia_renderer.browser_tests.filter
@@ -0,0 +1,25 @@ +# These tests are all flaking after timing changes associated with +# SkiaRenderer. We will need to determine the root causes, or update the tests +# before beginning Finch trials. https://crbug.com/982933 +-BluetoothLowEnergyApiTest.* +-BrowserActionApiTest.* +-BrowserViewTest.* +-ChromeMainTest.* +-ContentSettingsWorkerModulesBrowserTest.* +-ExtensionOverrideTest.* +-InputImeApiTest.* +-MediaRouterUIBrowserTest.* +-ModernShowActionKey +-NavigationPredictorBrowserTest.* +-PaymentRequestCanMakePaymentMetricsTest.* +-PlatformAppBrowserTest.* +-PopupTrackerBrowserTest.* +-RemoteDebuggingTest.* +-SaveCardBubbleViewsFullFormBrowserTest.* +-SecurityStateTabHelperTest.* +-ServiceWorkerBasedBackgroundTest.* +-ServiceWorkerTest.* +-TabHoverCardBubbleViewBrowserTest.* +-TranslateLanguageBrowserTest.* +-WasmAppTest.* +-WebDialogBrowserTest.*
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 71684fb..da28aa1 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -346,6 +346,21 @@ 'cros_browser_sanity_test': {}, }, + 'chromeos_experimental_remote_device_isolated_tests': { + 'telemetry_unittests': { + 'args': [ + '--browser=cros-chrome', + # The magic hostname that resolves to a CrOS device in the test lab. + '--remote=variable_chromeos_device_hostname', + '--jobs=1', + ], + 'swarming': { + 'idempotent': False, # https://crbug.com/549140 + 'shards': 12, + }, + }, + }, + 'chromeos_isolated_scripts': { 'telemetry_perf_unittests': { 'args': [ @@ -385,21 +400,7 @@ ], 'swarming': { 'idempotent': False, # https://crbug.com/549140 - 'shards': 6, - }, - }, - 'telemetry_unittests': { - 'args': [ - '--browser=cros-chrome', - # The magic hostname that resolves to a CrOS device in the test lab. - '--remote=variable_chromeos_device_hostname', - '--jobs=1', - # TODO(crbug.com/866062): Use the default retry limit. - '--retry-limit=1', - ], - 'swarming': { - 'idempotent': False, # https://crbug.com/549140 - 'shards': 12, + 'shards': 2, }, }, }, @@ -2431,6 +2432,13 @@ }, }, + # On some bots we don't have capacity to run all standard tests (for example + # Android Pie), however there are tracing integration tests we want to + # ensure are still working. + 'chromium_tracing_gtests': { + 'services_unittests': {}, + }, + 'chromium_web_tests_and_wpt_webdriver_isolated_scripts': { 'webkit_layout_tests': { # layout test failures are retried 3 times when '--test-list' is not @@ -3588,6 +3596,7 @@ 'args': [ '--use-vulkan=native', '--disable-vulkan-fallback-to-gl-for-testing', + '--enable-features=UseSkiaRenderer', '--test-launcher-filter-file=../../testing/buildbot/filters/gpu.skiarenderer_vulkan_content_browsertests.filter', ], 'swarming': { @@ -4485,6 +4494,7 @@ 'skia_renderer_browser_tests': { 'args': [ '--enable-features=VizDisplayCompositor,UseSkiaRenderer', + '--test-launcher-filter-file=../../testing/buildbot/filters/skia_renderer.browser_tests.filter', ], 'swarming': { 'shards': 10, @@ -4785,6 +4795,7 @@ 'android_pie_gtests': [ 'android_ddready_vr_gtests', 'android_ar_gtests', + 'chromium_tracing_gtests', # No standard tests due to capacity, no Vega tests since it's currently # O only. ],
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 45f6389..55cc959c 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -678,6 +678,7 @@ }, 'test_suites': { 'gtest_tests': 'chromeos_device_kevin_tests', + 'isolated_scripts': 'chromeos_remote_device_isolated_tests', }, 'os_type': 'chromeos', }, @@ -1629,7 +1630,7 @@ ], }, 'test_suites': { - 'isolated_scripts': 'chromeos_remote_device_isolated_tests', + 'isolated_scripts': 'chromeos_experimental_remote_device_isolated_tests', }, 'os_type': 'chromeos', },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 5e3c39d..0c089e13 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -4833,29 +4833,6 @@ ] } ], - "SkipPassthroughTouchEventQueueFilter": [ - { - "platforms": [ - "linux", - "windows", - "mac", - "android", - "chromeos" - ], - "experiments": [ - { - "name": "EnabledDiscreteEventsRendererProcess_20190507", - "params": { - "skip_filtering_process": "browser_and_renderer", - "type": "discrete" - }, - "enable_features": [ - "SkipTouchEventFilter" - ] - } - ] - } - ], "SpellingServiceRestEndpoint": [ { "platforms": [
diff --git a/third_party/android_crazy_linker/BUILD.gn b/third_party/android_crazy_linker/BUILD.gn index d09d573..88bd711 100644 --- a/third_party/android_crazy_linker/BUILD.gn +++ b/third_party/android_crazy_linker/BUILD.gn
@@ -9,6 +9,9 @@ # NOTE: This file is included in Linux builds to build the # crazy_linker_zip_fuzzer target (see below). However, the rest of the # crazy linker doesn't build or work on Linux yet. +# +# NOTE: Instructions for testing the crazy linker are in +# android_linker_testing.md. config("crazy_config") { include_dirs = [ "src/include" ]
diff --git a/third_party/android_crazy_linker/README.chromium b/third_party/android_crazy_linker/README.chromium index 81cf96a..63106015 100644 --- a/third_party/android_crazy_linker/README.chromium +++ b/third_party/android_crazy_linker/README.chromium
@@ -100,4 +100,6 @@ - Improve FileDescriptor class. -- Safer zip parsing code (avoid integer overflows and add range checks). \ No newline at end of file +- Safer zip parsing code (avoid integer overflows and add range checks). + +- Add a document about testing the crazy linker in a Chromium checkout
diff --git a/third_party/android_crazy_linker/src/README.TXT b/third_party/android_crazy_linker/src/README.TXT index fc025eb..c08168ec 100644 --- a/third_party/android_crazy_linker/src/README.TXT +++ b/third_party/android_crazy_linker/src/README.TXT
@@ -125,9 +125,6 @@ Testing: -------- - If you modify this code, check your changes by running the test suite using: - - cd $NDK - tests/run-tests.sh crazy_linker + See android_linker_testing.md See DESIGN.TXT for an overview of the library's design.
diff --git a/third_party/android_crazy_linker/src/android_linker_testing.md b/third_party/android_crazy_linker/src/android_linker_testing.md new file mode 100644 index 0000000..8c224c29 --- /dev/null +++ b/third_party/android_crazy_linker/src/android_linker_testing.md
@@ -0,0 +1,56 @@ +# Testing the Android Crazy Linker + +The crazy linker is a custom dynamic linker used by Chrome on older Android +versions where dynamic linking is not as advanced. It provides +`android_dlopen_ext` functionality, RELRO sharing, compressed relocations, etc. + +For crazy reasons outlined in `linker/test_case.py` this linker cannot be tested +using GTest or instrumentation test, hence it also carries a custom testing +framework. The tests are not run as part of CQ, but it is still desirable to run +them before landing changes in code locations listed below. + +Sorry. + +These instructions assume +[Building Chromium for Android](android_build_instructions.md) as a +prerequisite. + +## Code Locations + +The tested functionality is spread across these locations: +``` +third_party/android_crazy_linker +base/android/java/src/org/chromium/base/library_loader +``` + +The tests themselves are living mostly in these places: +``` +build/android/pylib/linker/test_case.py +content/shell/android +``` + +## Running native tests + +This will run both unittests and regression tests: +``` +autoninja -C out/Release android_crazy_linker_tests +out/Release/bin/run_android_crazy_linker_tests --unit-tests +``` + +Verbosity of the output can be increased by setting `CRAZY_DEBUG` to 1 in +`crazy_linker_debug.h`. + +## Running Java Tests + +We recommend running these tests in Release mode, as there are known +complications in testing with the component build. Setting `Linker.DEBUG` to +`true` should also help increase verbosity of the output. +``` +autoninja -C out/Release chromium_linker_test_apk +out/Release/bin/run_chromium_linker_test_apk +``` + +## Fuzzer Tests + +There are also a few tests for fuzzing the ZIP parser. The instructions to run +them are at the bottom of `third_party/android_crazy_linker/BUILD.gn`.
diff --git a/third_party/blink/public/mojom/idle/OWNERS b/third_party/blink/public/mojom/idle/OWNERS index b0db262..14238e1 100644 --- a/third_party/blink/public/mojom/idle/OWNERS +++ b/third_party/blink/public/mojom/idle/OWNERS
@@ -2,3 +2,5 @@ per-file *.mojom=set noparent per-file *.mojom=file://ipc/SECURITY_OWNERS + +# TEAM: fugu-dev@chromium.org
diff --git a/third_party/blink/public/web/web_settings.h b/third_party/blink/public/web/web_settings.h index 09437c5d..9ee2dc11 100644 --- a/third_party/blink/public/web/web_settings.h +++ b/third_party/blink/public/web/web_settings.h
@@ -254,6 +254,9 @@ virtual void SetTextTrackTextColor(const WebString&) = 0; virtual void SetTextTrackTextShadow(const WebString&) = 0; virtual void SetTextTrackTextSize(const WebString&) = 0; + virtual void SetTextTrackWindowColor(const WebString&) = 0; + virtual void SetTextTrackWindowPadding(const WebString&) = 0; + virtual void SetTextTrackWindowRadius(const WebString&) = 0; virtual void SetThreadedScrollingEnabled(bool) = 0; virtual void SetTouchDragDropEnabled(bool) = 0; virtual void SetBarrelButtonForDragEnabled(bool) = 0;
diff --git a/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc b/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc index 9404ad9..d5c0490 100644 --- a/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc +++ b/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
@@ -7,8 +7,10 @@ #include <utility> #include "base/logging.h" +#include "third_party/blink/renderer/bindings/core/v8/script_controller.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h" +#include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" @@ -30,9 +32,11 @@ public: IsolatedWorldCSPDelegate(Document& document, scoped_refptr<SecurityOrigin> security_origin, + int world_id, bool apply_policy) : document_(&document), security_origin_(std::move(security_origin)), + world_id_(world_id), apply_policy_(apply_policy) { DCHECK(security_origin_); } @@ -95,14 +99,17 @@ } void DisableEval(const String& error_message) override { - // TODO(crbug.com/896041): Implement this. - NOTIMPLEMENTED(); + if (!document_->GetFrame()) + return; + document_->GetFrame()->GetScriptController().DisableEvalForIsolatedWorld( + world_id_, error_message); } void ReportBlockedScriptExecutionToInspector( const String& directive_text) override { - // TODO(crbug.com/896041): Figure out if this needs to be implemented. - NOTIMPLEMENTED(); + // This allows users to set breakpoints in the Devtools for the case when + // script execution is blocked by CSP. + probe::ScriptExecutionBlockedByCSP(document_, directive_text); } void DidAddContentSecurityPolicies( @@ -111,6 +118,7 @@ private: const Member<Document> document_; const scoped_refptr<SecurityOrigin> security_origin_; + const int world_id_; // Whether the 'IsolatedWorldCSP' feature is enabled, and we are applying the // CSP provided by the isolated world. @@ -172,7 +180,7 @@ IsolatedWorldCSPDelegate* delegate = MakeGarbageCollected<IsolatedWorldCSPDelegate>( - document, std::move(self_origin), apply_policy); + document, std::move(self_origin), world_id, apply_policy); csp->BindToDelegate(*delegate); if (apply_policy) {
diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc index 59af62ec..50c06fdd 100644 --- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc +++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
@@ -31,6 +31,7 @@ #include "third_party/blink/renderer/bindings/core/v8/local_window_proxy.h" #include "third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding.h" +#include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h" #include "third_party/blink/renderer/bindings/core/v8/script_controller.h" #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" @@ -167,19 +168,30 @@ SetupWindowPrototypeChain(); - const SecurityOrigin* origin = nullptr; - if (world_->IsMainWorld()) { - // ActivityLogger for main world is updated within updateDocumentInternal(). - UpdateDocumentInternal(); - origin = GetFrame()->GetDocument()->GetSecurityOrigin(); - // FIXME: Can this be removed when CSP moves to browser? + // Setup handling for eval checks for the context. Isolated worlds which don't + // specify their own CSPs are exempt from eval checks currently. + // TODO(crbug.com/982388): For other CSP checks, we use the main world CSP + // when an isolated world doesn't specify its own CSP. We should do the same + // here. + const bool evaluate_csp_for_eval = + world_->IsMainWorld() || + (world_->IsIsolatedWorld() && + IsolatedWorldCSP::Get().HasContentSecurityPolicy(world_->GetWorldId())); + if (evaluate_csp_for_eval) { ContentSecurityPolicy* csp = - GetFrame()->GetDocument()->GetContentSecurityPolicy(); + GetFrame()->GetDocument()->GetContentSecurityPolicyForWorld(); context->AllowCodeGenerationFromStrings(csp->AllowEval( nullptr, SecurityViolationReportingPolicy::kSuppressReporting, ContentSecurityPolicy::kWillNotThrowException, g_empty_string)); context->SetErrorMessageForCodeGenerationFromStrings( V8String(GetIsolate(), csp->EvalDisabledErrorMessage())); + } + + const SecurityOrigin* origin = nullptr; + if (world_->IsMainWorld()) { + // ActivityLogger for main world is updated within updateDocumentInternal(). + UpdateDocumentInternal(); + origin = GetFrame()->GetDocument()->GetSecurityOrigin(); } else { UpdateActivityLogger(); origin = world_->IsolatedWorldSecurityOrigin();
diff --git a/third_party/blink/renderer/bindings/core/v8/script_controller.cc b/third_party/blink/renderer/bindings/core/v8/script_controller.cc index ad6fca3..9da29ec 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_controller.cc +++ b/third_party/blink/renderer/bindings/core/v8/script_controller.cc
@@ -60,6 +60,7 @@ #include "third_party/blink/renderer/core/loader/frame_loader.h" #include "third_party/blink/renderer/core/loader/progress_tracker.h" #include "third_party/blink/renderer/core/probe/core_probes.h" +#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h" #include "third_party/blink/renderer/platform/histogram.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" @@ -153,23 +154,41 @@ } void ScriptController::EnableEval() { - v8::HandleScope handle_scope(GetIsolate()); - v8::Local<v8::Context> v8_context = - window_proxy_manager_->MainWorldProxyMaybeUninitialized() - ->ContextIfInitialized(); - if (v8_context.IsEmpty()) - return; - v8_context->AllowCodeGenerationFromStrings(true); + SetEvalForWorld(DOMWrapperWorld::MainWorld(), true /* allow_eval */, + g_empty_string /* error_message */); } void ScriptController::DisableEval(const String& error_message) { + SetEvalForWorld(DOMWrapperWorld::MainWorld(), false /* allow_eval */, + error_message); +} + +void ScriptController::DisableEvalForIsolatedWorld( + int world_id, + const String& error_message) { + DCHECK(DOMWrapperWorld::IsIsolatedWorldId(world_id)); + scoped_refptr<DOMWrapperWorld> world = + DOMWrapperWorld::EnsureIsolatedWorld(GetIsolate(), world_id); + SetEvalForWorld(*world, false /* allow_eval */, error_message); +} + +void ScriptController::SetEvalForWorld(DOMWrapperWorld& world, + bool allow_eval, + const String& error_message) { v8::HandleScope handle_scope(GetIsolate()); - v8::Local<v8::Context> v8_context = - window_proxy_manager_->MainWorldProxyMaybeUninitialized() - ->ContextIfInitialized(); + LocalWindowProxy* proxy = + world.IsMainWorld() + ? window_proxy_manager_->MainWorldProxyMaybeUninitialized() + : WindowProxy(world); + + v8::Local<v8::Context> v8_context = proxy->ContextIfInitialized(); if (v8_context.IsEmpty()) return; - v8_context->AllowCodeGenerationFromStrings(false); + + v8_context->AllowCodeGenerationFromStrings(allow_eval); + if (allow_eval) + return; + v8_context->SetErrorMessageForCodeGenerationFromStrings( V8String(GetIsolate(), error_message)); }
diff --git a/third_party/blink/renderer/bindings/core/v8/script_controller.h b/third_party/blink/renderer/bindings/core/v8/script_controller.h index 0a6422c9..0f0c9db 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_controller.h +++ b/third_party/blink/renderer/bindings/core/v8/script_controller.h
@@ -120,8 +120,13 @@ scoped_refptr<DOMWrapperWorld> CreateNewInspectorIsolatedWorld( const String& world_name); + // Disables eval for the main world. void DisableEval(const String& error_message); + // Disables eval for the given isolated |world_id|. This initializes the + // window proxy for the isolated world, if it's not yet initialized. + void DisableEvalForIsolatedWorld(int world_id, const String& error_message); + TextPosition EventHandlerPosition() const; void ClearWindowProxy(); @@ -143,6 +148,12 @@ } void EnableEval(); + // Sets whether eval is enabled for the context corresponding to the given + // |world|. |error_message| is used only when |allow_eval| is false. + void SetEvalForWorld(DOMWrapperWorld& world, + bool allow_eval, + const String& error_message); + v8::Local<v8::Value> EvaluateScriptInMainWorld(const ScriptSourceCode&, const KURL& base_url, SanitizeScriptErrors,
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc b/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc index c25dd97..2cdc9f97 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc
@@ -665,6 +665,9 @@ void EmbedderGraphBuilder::BuildEmbedderGraphCallback(v8::Isolate* isolate, v8::EmbedderGraph* graph, void*) { + // Synchronize with concurrent sweepers before taking a snapshot. + ThreadState::Current()->CompleteSweep(); + NodeBuilder node_builder(graph); V8EmbedderGraphBuilder builder(isolate, graph, &node_builder); builder.BuildEmbedderGraph();
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc index d4fcac3..e53efa8 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -33,6 +33,7 @@ #include "services/metrics/public/cpp/ukm_recorder.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/bindings/core/v8/binding_security.h" +#include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h" #include "third_party/blink/renderer/bindings/core/v8/referrer_script_info.h" #include "third_party/blink/renderer/bindings/core/v8/rejected_promises.h" #include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h" @@ -357,8 +358,16 @@ if (ExecutionContext* execution_context = ToExecutionContext(context)) { DCHECK(execution_context->IsDocument() || execution_context->IsMainThreadWorkletGlobalScope()); + + v8::Context::Scope scope(context); + + // Note this callback is only triggered for contexts which have eval + // disabled. Hence we don't need to handle the case of isolated world + // contexts with no CSP specified. (They should be exempt from the page CSP. + // See crbug.com/982388.) + if (ContentSecurityPolicy* policy = - execution_context->GetContentSecurityPolicy()) { + execution_context->GetContentSecurityPolicyForWorld()) { v8::String::Value source_str(context->GetIsolate(), source); UChar snippet[ContentSecurityPolicy::kMaxSampleLength + 1]; size_t len = std::min((sizeof(snippet) / sizeof(UChar)) - 1,
diff --git a/third_party/blink/renderer/core/animation/css_resolution_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_resolution_interpolation_type.cc index 3b8b3afbf..14756aa 100644 --- a/third_party/blink/renderer/core/animation/css_resolution_interpolation_type.cc +++ b/third_party/blink/renderer/core/animation/css_resolution_interpolation_type.cc
@@ -20,8 +20,7 @@ const StyleResolverState*, ConversionCheckers&) const { auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value); - if (!primitive_value || - !CSSPrimitiveValue::IsResolution(primitive_value->TypeWithCalcResolved())) + if (!primitive_value || !primitive_value->IsResolution()) return nullptr; return InterpolationValue(std::make_unique<InterpolableNumber>( primitive_value->ComputeDotsPerPixel()));
diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.cc b/third_party/blink/renderer/core/css/css_math_expression_node.cc index ff74c1a0..ad173432 100644 --- a/third_party/blink/renderer/core/css/css_math_expression_node.cc +++ b/third_party/blink/renderer/core/css/css_math_expression_node.cc
@@ -145,8 +145,7 @@ CSSMathExpressionNumericLiteral::CSSMathExpressionNumericLiteral( CSSNumericLiteralValue* value, bool is_integer) - : CSSMathExpressionNode(UnitCategory(value->TypeWithCalcResolved()), - is_integer), + : CSSMathExpressionNode(UnitCategory(value->GetType()), is_integer), value_(value) {} bool CSSMathExpressionNumericLiteral::IsZero() const { @@ -233,7 +232,7 @@ CSSPrimitiveValue::UnitType CSSMathExpressionNumericLiteral::ResolvedUnitType() const { - return value_->TypeWithCalcResolved(); + return value_->GetType(); } void CSSMathExpressionNumericLiteral::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/css/css_math_function_value.cc b/third_party/blink/renderer/core/css/css_math_function_value.cc index 8fac2b7..bc8148e5 100644 --- a/third_party/blink/renderer/core/css/css_math_function_value.cc +++ b/third_party/blink/renderer/core/css/css_math_function_value.cc
@@ -150,4 +150,10 @@ return expression_->IsZero(); } +bool CSSMathFunctionValue::IsPx() const { + // TODO(crbug.com/979895): This is the result of refactoring, which might be + // an existing bug. Fix it if necessary. + return Category() == kCalcLength; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_math_function_value.h b/third_party/blink/renderer/core/css/css_math_function_value.h index c4d8093..2b7ad773 100644 --- a/third_party/blink/renderer/core/css/css_math_function_value.h +++ b/third_party/blink/renderer/core/css/css_math_function_value.h
@@ -34,6 +34,14 @@ bool MayHaveRelativeUnit() const; CalculationCategory Category() const { return expression_->Category(); } + bool IsAngle() const { return Category() == kCalcAngle; } + bool IsLength() const { return Category() == kCalcLength; } + bool IsNumber() const { return Category() == kCalcNumber; } + bool IsPercentage() const { return Category() == kCalcPercent; } + bool IsTime() const { return Category() == kCalcTime; } + + bool IsPx() const; + bool IsInt() const { return expression_->IsInteger(); } bool IsNegative() const { return expression_->DoubleValue() < 0; } ValueRange PermittedValueRange() const {
diff --git a/third_party/blink/renderer/core/css/css_numeric_literal_value.cc b/third_party/blink/renderer/core/css/css_numeric_literal_value.cc index 0adefe1..3b3cb93 100644 --- a/third_party/blink/renderer/core/css/css_numeric_literal_value.cc +++ b/third_party/blink/renderer/core/css/css_numeric_literal_value.cc
@@ -104,6 +104,11 @@ } } +double CSSNumericLiteralValue::ComputeDotsPerPixel() const { + DCHECK(IsResolution()); + return DoubleValue() * ConversionToCanonicalUnitsScaleFactor(GetType()); +} + double CSSNumericLiteralValue::ComputeLengthPx( const CSSToLengthConversionData& conversion_data) const { return conversion_data.ZoomedComputedPixels(num_, GetType());
diff --git a/third_party/blink/renderer/core/css/css_numeric_literal_value.h b/third_party/blink/renderer/core/css/css_numeric_literal_value.h index cb1f0055..625875d 100644 --- a/third_party/blink/renderer/core/css/css_numeric_literal_value.h +++ b/third_party/blink/renderer/core/css/css_numeric_literal_value.h
@@ -22,6 +22,7 @@ return static_cast<UnitType>(numeric_literal_unit_type_); } + bool IsAngle() const { return CSSPrimitiveValue::IsAngle(GetType()); } bool IsFontRelativeLength() const { return GetType() == UnitType::kQuirkyEms || GetType() == UnitType::kEms || GetType() == UnitType::kExs || GetType() == UnitType::kRems || @@ -31,6 +32,14 @@ bool IsViewportPercentageLength() const { return CSSPrimitiveValue::IsViewportPercentageLength(GetType()); } + bool IsLength() const { return CSSPrimitiveValue::IsLength(GetType()); } + bool IsPx() const { return GetType() == UnitType::kPixels; } + bool IsNumber() const { + return GetType() == UnitType::kNumber || GetType() == UnitType::kInteger; + } + bool IsInteger() const { return GetType() == UnitType::kInteger; } + bool IsPercentage() const { return GetType() == UnitType::kPercentage; } + bool IsTime() const { return CSSPrimitiveValue::IsTime(GetType()); } bool IsResolution() const { return CSSPrimitiveValue::IsResolution(GetType()); } @@ -41,6 +50,7 @@ double DoubleValue() const { return num_; } double ComputeSeconds() const; double ComputeDegrees() const; + double ComputeDotsPerPixel() const; double ComputeLengthPx( const CSSToLengthConversionData& conversion_data) const;
diff --git a/third_party/blink/renderer/core/css/css_primitive_value.cc b/third_party/blink/renderer/core/css/css_primitive_value.cc index 344ac2f..28542b4 100644 --- a/third_party/blink/renderer/core/css/css_primitive_value.cc +++ b/third_party/blink/renderer/core/css/css_primitive_value.cc
@@ -126,6 +126,48 @@ return IsNumericLiteralValue() && To<CSSNumericLiteralValue>(this)->IsFlex(); } +bool CSSPrimitiveValue::IsAngle() const { + if (IsNumericLiteralValue()) + return To<CSSNumericLiteralValue>(this)->IsAngle(); + return To<CSSMathFunctionValue>(this)->IsAngle(); +} + +bool CSSPrimitiveValue::IsLength() const { + if (IsNumericLiteralValue()) + return To<CSSNumericLiteralValue>(this)->IsLength(); + return To<CSSMathFunctionValue>(this)->IsLength(); +} + +bool CSSPrimitiveValue::IsPx() const { + if (IsNumericLiteralValue()) + return To<CSSNumericLiteralValue>(this)->IsPx(); + return To<CSSMathFunctionValue>(this)->IsPx(); +} + +bool CSSPrimitiveValue::IsNumber() const { + if (IsNumericLiteralValue()) + return To<CSSNumericLiteralValue>(this)->IsNumber(); + return To<CSSMathFunctionValue>(this)->IsNumber(); +} + +bool CSSPrimitiveValue::IsInteger() const { + // TODO(style-dev): Support integer math functions properly. + return IsNumericLiteralValue() && + To<CSSNumericLiteralValue>(this)->IsInteger(); +} + +bool CSSPrimitiveValue::IsPercentage() const { + if (IsNumericLiteralValue()) + return To<CSSNumericLiteralValue>(this)->IsPercentage(); + return To<CSSMathFunctionValue>(this)->IsPercentage(); +} + +bool CSSPrimitiveValue::IsTime() const { + if (IsNumericLiteralValue()) + return To<CSSNumericLiteralValue>(this)->IsTime(); + return To<CSSMathFunctionValue>(this)->IsTime(); +} + CSSPrimitiveValue::CSSPrimitiveValue(ClassType class_type) : CSSValue(class_type) {} @@ -174,9 +216,10 @@ } double CSSPrimitiveValue::ComputeDotsPerPixel() const { - UnitType current_type = TypeWithCalcResolved(); - DCHECK(IsResolution(current_type)); - return GetDoubleValue() * ConversionToCanonicalUnitsScaleFactor(current_type); + // TODO(style-dev): Either support math functions on resolutions; or provide a + // justification for not supporting it. + DCHECK(IsNumericLiteralValue()); + return To<CSSNumericLiteralValue>(this)->ComputeDotsPerPixel(); } template <>
diff --git a/third_party/blink/renderer/core/css/css_primitive_value.h b/third_party/blink/renderer/core/css/css_primitive_value.h index 4162932..e5b0c226 100644 --- a/third_party/blink/renderer/core/css/css_primitive_value.h +++ b/third_party/blink/renderer/core/css/css_primitive_value.h
@@ -159,7 +159,7 @@ return unit == UnitType::kDegrees || unit == UnitType::kRadians || unit == UnitType::kGradians || unit == UnitType::kTurns; } - bool IsAngle() const { return IsAngle(TypeWithCalcResolved()); } + bool IsAngle() const; bool IsFontRelativeLength() const; static bool IsViewportPercentageLength(UnitType type) { return type >= UnitType::kViewportWidth && type <= UnitType::kViewportMax; @@ -173,19 +173,15 @@ type == UnitType::kExs || type == UnitType::kRems || type == UnitType::kChs || IsViewportPercentageLength(type); } - bool IsLength() const { return IsLength(TypeWithCalcResolved()); } - bool IsNumber() const { - return TypeWithCalcResolved() == UnitType::kNumber || - TypeWithCalcResolved() == UnitType::kInteger; - } - bool IsPercentage() const { - return TypeWithCalcResolved() == UnitType::kPercentage; - } - bool IsPx() const { return TypeWithCalcResolved() == UnitType::kPixels; } + bool IsLength() const; + bool IsNumber() const; + bool IsInteger() const; + bool IsPercentage() const; + bool IsPx() const; static bool IsTime(UnitType unit) { return unit == UnitType::kSeconds || unit == UnitType::kMilliseconds; } - bool IsTime() const { return IsTime(TypeWithCalcResolved()); } + bool IsTime() const; static bool IsFrequency(UnitType unit) { return unit == UnitType::kHertz || unit == UnitType::kKilohertz; }
diff --git a/third_party/blink/renderer/core/css/media_query_exp.cc b/third_party/blink/renderer/core/css/media_query_exp.cc index 695792e..735ba846 100644 --- a/third_party/blink/renderer/core/css/media_query_exp.cc +++ b/third_party/blink/renderer/core/css/media_query_exp.cc
@@ -29,6 +29,8 @@ #include "third_party/blink/renderer/core/css/media_query_exp.h" +#include "third_party/blink/renderer/core/css/css_math_expression_node.h" +#include "third_party/blink/renderer/core/css/css_math_function_value.h" #include "third_party/blink/renderer/core/css/parser/css_parser_token_range.h" #include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h" #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h" @@ -117,13 +119,7 @@ static inline bool FeatureWithValidDensity(const String& media_feature, const CSSPrimitiveValue* value) { - if ((value->TypeWithCalcResolved() != - CSSPrimitiveValue::UnitType::kDotsPerPixel && - value->TypeWithCalcResolved() != - CSSPrimitiveValue::UnitType::kDotsPerInch && - value->TypeWithCalcResolved() != - CSSPrimitiveValue::UnitType::kDotsPerCentimeter) || - value->GetDoubleValue() <= 0) + if (!value->IsResolution() || value->GetDoubleValue() <= 0) return false; return media_feature == kResolutionMediaFeature || @@ -147,7 +143,7 @@ static inline bool FeatureWithPositiveInteger(const String& media_feature, const CSSPrimitiveValue* value) { - if (value->TypeWithCalcResolved() != CSSPrimitiveValue::UnitType::kInteger) + if (!value->IsInteger()) return false; return FeatureExpectingPositiveInteger(media_feature); } @@ -165,7 +161,7 @@ static inline bool FeatureWithZeroOrOne(const String& media_feature, const CSSPrimitiveValue* value) { - if (value->TypeWithCalcResolved() != CSSPrimitiveValue::UnitType::kInteger || + if (!value->IsInteger() || !(value->GetDoubleValue() == 1 || !value->GetDoubleValue())) return false; @@ -272,9 +268,7 @@ // Create value for media query expression that must have 1 or more values. if (value) { if (FeatureWithAspectRatio(lower_media_feature)) { - if (value->TypeWithCalcResolved() != - CSSPrimitiveValue::UnitType::kInteger || - value->GetDoubleValue() == 0) + if (!value->IsInteger() || value->GetDoubleValue() == 0) return Invalid(); if (!css_property_parser_helpers::ConsumeSlashIncludingWhitespace(range)) return Invalid(); @@ -291,11 +285,25 @@ FeatureWithPositiveInteger(lower_media_feature, value) || FeatureWithPositiveNumber(lower_media_feature, value) || FeatureWithZeroOrOne(lower_media_feature, value)) { - exp_value.value = value->GetDoubleValue(); - if (value->IsNumber()) - exp_value.unit = CSSPrimitiveValue::UnitType::kNumber; - else - exp_value.unit = value->TypeWithCalcResolved(); + if (!value->IsLength() || !value->IsMathFunctionValue()) { + exp_value.value = value->GetDoubleValue(); + if (value->IsNumber()) + exp_value.unit = CSSPrimitiveValue::UnitType::kNumber; + else + exp_value.unit = value->TypeWithCalcResolved(); + } else { + const auto* math_value = To<CSSMathFunctionValue>(value); + CSSPrimitiveValue::UnitType expression_unit = + math_value->ExpressionNode()->ResolvedUnitType(); + if (expression_unit == CSSPrimitiveValue::UnitType::kUnknown) { + // TODO(crbug.com/982542): Support math expressions involving type + // conversions properly. For example, calc(10px + 1em). + return Invalid(); + } else { + exp_value.value = math_value->DoubleValue(); + exp_value.unit = expression_unit; + } + } exp_value.is_value = true; } else { return Invalid();
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc index ac74d974..af56e06 100644 --- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc +++ b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
@@ -202,7 +202,7 @@ } const CSSMathFunctionValue* Value() const { return calc_value_; } - CSSPrimitiveValue* ConsumeValue() { + CSSMathFunctionValue* ConsumeValue() { if (!calc_value_) return nullptr; source_range_ = range_; @@ -450,8 +450,12 @@ namespace { bool IsNonZeroUserUnitsValue(const CSSPrimitiveValue* value) { - return value && - value->TypeWithCalcResolved() == + // TODO(crbug.com/979895): This is the result of a refactoring, which might + // have revealed an existing bug in handling user units in math functions. Fix + // it if necessary. + const auto* numeric_literal = DynamicTo<CSSNumericLiteralValue>(value); + return numeric_literal && + numeric_literal->GetType() == CSSPrimitiveValue::UnitType::kUserUnits && value->GetDoubleValue() != 0; } @@ -511,14 +515,14 @@ if (const CSSMathFunctionValue* calculation = calc_parser.Value()) { if (calculation->Category() != kCalcAngle) return nullptr; - if (CSSPrimitiveValue* result = calc_parser.ConsumeValue()) { - if (result->GetDoubleValue() < minimum_value) { - return CSSNumericLiteralValue::Create(minimum_value, - result->TypeWithCalcResolved()); + if (CSSMathFunctionValue* result = calc_parser.ConsumeValue()) { + if (result->ComputeDegrees() < minimum_value) { + return CSSNumericLiteralValue::Create( + minimum_value, CSSPrimitiveValue::UnitType::kDegrees); } - if (result->GetDoubleValue() > maximum_value) { - return CSSNumericLiteralValue::Create(maximum_value, - result->TypeWithCalcResolved()); + if (result->ComputeDegrees() > maximum_value) { + return CSSNumericLiteralValue::Create( + maximum_value, CSSPrimitiveValue::UnitType::kDegrees); } return result; }
diff --git a/third_party/blink/renderer/core/css/resolver/transform_builder.cc b/third_party/blink/renderer/core/css/resolver/transform_builder.cc index 7fffb5b..d2bfb95 100644 --- a/third_party/blink/renderer/core/css/resolver/transform_builder.cc +++ b/third_party/blink/renderer/core/css/resolver/transform_builder.cc
@@ -33,6 +33,7 @@ #include "third_party/blink/renderer/core/css/css_function_value.h" #include "third_party/blink/renderer/core/css/css_math_expression_node.h" #include "third_party/blink/renderer/core/css/css_math_function_value.h" +#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h" #include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h" @@ -109,14 +110,14 @@ for (const CSSValue* item : *transform_value) { const auto& primitive_value = To<CSSPrimitiveValue>(*item); - if (primitive_value.IsCalculated() && - To<CSSMathFunctionValue>(primitive_value).MayHaveRelativeUnit()) { - return true; - } - - if (CSSPrimitiveValue::IsRelativeUnit( - primitive_value.TypeWithCalcResolved())) { - return true; + if (primitive_value.IsCalculated()) { + if (To<CSSMathFunctionValue>(primitive_value).MayHaveRelativeUnit()) + return true; + } else { + CSSPrimitiveValue::UnitType unit_type = + To<CSSNumericLiteralValue>(primitive_value).GetType(); + if (CSSPrimitiveValue::IsRelativeUnit(unit_type)) + return true; } } }
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index 8ac2664..2944b05 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -729,8 +729,16 @@ // FinishingPrinting denotes that the non-printing layout state is being // restored. - enum PrintingState { kNotPrinting, kPrinting, kFinishingPrinting }; + enum PrintingState { + kNotPrinting, + kBeforePrinting, + kPrinting, + kFinishingPrinting + }; bool Printing() const { return printing_ == kPrinting; } + bool BeforePrintingOrPrinting() const { + return printing_ == kPrinting || printing_ == kBeforePrinting; + } bool FinishingOrIsPrinting() { return printing_ == kPrinting || printing_ == kFinishingPrinting; }
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index ce27f74..500e277 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -1224,47 +1224,6 @@ return static_cast<const T*>(node); } -template <typename T> -inline T* ToElementOrNull(Node& node) { - return IsElementOfType<const T>(node) ? static_cast<T*>(&node) : nullptr; -} -template <typename T> -inline T* ToElementOrNull(Node* node) { - return (node && IsElementOfType<const T>(*node)) ? static_cast<T*>(node) - : nullptr; -} -template <typename T> -inline const T* ToElementOrNull(const Node& node) { - return IsElementOfType<const T>(node) ? static_cast<const T*>(&node) - : nullptr; -} -template <typename T> -inline const T* ToElementOrNull(const Node* node) { - return (node && IsElementOfType<const T>(*node)) ? static_cast<const T*>(node) - : nullptr; -} - -template <typename T> -inline T& ToElementOrDie(Node& node) { - CHECK(IsElementOfType<const T>(node)); - return static_cast<T&>(node); -} -template <typename T> -inline T* ToElementOrDie(Node* node) { - CHECK(!node || IsElementOfType<const T>(*node)); - return static_cast<T*>(node); -} -template <typename T> -inline const T& ToElementOrDie(const Node& node) { - CHECK(IsElementOfType<const T>(node)); - return static_cast<const T&>(node); -} -template <typename T> -inline const T* ToElementOrDie(const Node* node) { - CHECK(!node || IsElementOfType<const T>(*node)); - return static_cast<const T*>(node); -} - inline bool IsDisabledFormControl(const Node* node) { auto* element = DynamicTo<Element>(node); return element && element->IsDisabledFormControl();
diff --git a/third_party/blink/renderer/core/editing/commands/apply_style_command.cc b/third_party/blink/renderer/core/editing/commands/apply_style_command.cc index 68df523..d4d67a3 100644 --- a/third_party/blink/renderer/core/editing/commands/apply_style_command.cc +++ b/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
@@ -2050,7 +2050,7 @@ return 0; // TODO(yosin): We should have printer for |CSSPrimitiveValue::UnitType|. - DCHECK(value->TypeWithCalcResolved() == CSSPrimitiveValue::UnitType::kPixels); + DCHECK(value->IsPx()); return value->GetFloatValue(); }
diff --git a/third_party/blink/renderer/core/editing/editing_style.cc b/third_party/blink/renderer/core/editing/editing_style.cc index 6312c1f..f8d9d45 100644 --- a/third_party/blink/renderer/core/editing/editing_style.cc +++ b/third_party/blink/renderer/core/editing/editing_style.cc
@@ -1877,25 +1877,32 @@ bool is_monospace_font, LegacyFontSizeMode mode) { if (const auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value)) { - CSSPrimitiveValue::LengthUnitType length_type; - if (CSSPrimitiveValue::UnitTypeToLengthUnitType( - primitive_value->TypeWithCalcResolved(), length_type) && - length_type == CSSPrimitiveValue::kUnitTypePixels) { - double conversion = - CSSPrimitiveValue::ConversionToCanonicalUnitsScaleFactor( - primitive_value->TypeWithCalcResolved()); - int pixel_font_size = - clampTo<int>(primitive_value->GetDoubleValue() * conversion); - int legacy_font_size = FontSizeFunctions::LegacyFontSize( - document, pixel_font_size, is_monospace_font); - // Use legacy font size only if pixel value matches exactly to that of - // legacy font size. - if (mode == kAlwaysUseLegacyFontSize || - FontSizeFunctions::FontSizeForKeyword( - document, legacy_font_size, is_monospace_font) == pixel_font_size) - return legacy_font_size; + if (primitive_value->IsLength()) { + // TODO(crbug.com/979895): This doesn't seem to be handle math functions + // correctly. This is the result of a refactoring, and may have revealed + // an existing bug. Fix it if necessary. + CSSPrimitiveValue::UnitType length_unit = + primitive_value->IsNumericLiteralValue() + ? To<CSSNumericLiteralValue>(primitive_value)->GetType() + : CSSPrimitiveValue::UnitType::kPixels; + if (!CSSPrimitiveValue::IsRelativeUnit(length_unit)) { + double conversion = + CSSPrimitiveValue::ConversionToCanonicalUnitsScaleFactor( + length_unit); + int pixel_font_size = + clampTo<int>(primitive_value->GetDoubleValue() * conversion); + int legacy_font_size = FontSizeFunctions::LegacyFontSize( + document, pixel_font_size, is_monospace_font); + // Use legacy font size only if pixel value matches exactly to that of + // legacy font size. + if (mode == kAlwaysUseLegacyFontSize || + FontSizeFunctions::FontSizeForKeyword(document, legacy_font_size, + is_monospace_font) == + pixel_font_size) + return legacy_font_size; - return 0; + return 0; + } } }
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.cc b/third_party/blink/renderer/core/exported/web_settings_impl.cc index ed21f4e..6b068d1 100644 --- a/third_party/blink/renderer/core/exported/web_settings_impl.cc +++ b/third_party/blink/renderer/core/exported/web_settings_impl.cc
@@ -377,6 +377,18 @@ settings_->SetTextTrackTextSize(size); } +void WebSettingsImpl::SetTextTrackWindowColor(const WebString& color) { + settings_->SetTextTrackWindowColor(color); +} + +void WebSettingsImpl::SetTextTrackWindowPadding(const WebString& padding) { + settings_->SetTextTrackWindowPadding(padding); +} + +void WebSettingsImpl::SetTextTrackWindowRadius(const WebString& radius) { + settings_->SetTextTrackWindowRadius(radius); +} + void WebSettingsImpl::SetDNSPrefetchingEnabled(bool enabled) { settings_->SetDNSPrefetchingEnabled(enabled); }
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.h b/third_party/blink/renderer/core/exported/web_settings_impl.h index 60113db0..91457bfa 100644 --- a/third_party/blink/renderer/core/exported/web_settings_impl.h +++ b/third_party/blink/renderer/core/exported/web_settings_impl.h
@@ -175,6 +175,9 @@ void SetTextTrackTextColor(const WebString&) override; void SetTextTrackTextShadow(const WebString&) override; void SetTextTrackTextSize(const WebString&) override; + void SetTextTrackWindowColor(const WebString&) override; + void SetTextTrackWindowPadding(const WebString&) override; + void SetTextTrackWindowRadius(const WebString&) override; void SetThreadedScrollingEnabled(bool) override; void SetTouchDragDropEnabled(bool) override; void SetBarrelButtonForDragEnabled(bool) override;
diff --git a/third_party/blink/renderer/core/frame/root_frame_viewport.cc b/third_party/blink/renderer/core/frame/root_frame_viewport.cc index 03ae36bed..37a92dbf 100644 --- a/third_party/blink/renderer/core/frame/root_frame_viewport.cc +++ b/third_party/blink/renderer/core/frame/root_frame_viewport.cc
@@ -164,8 +164,7 @@ } void RootFrameViewport::UpdateScrollAnimator() { - GetScrollAnimator().SetCurrentOffset( - ToFloatSize(ScrollOffsetFromScrollAnimators())); + GetScrollAnimator().SetCurrentOffset(ScrollOffsetFromScrollAnimators()); } ScrollOffset RootFrameViewport::ScrollOffsetFromScrollAnimators() const {
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5 index c92364f..196cdaf4 100644 --- a/third_party/blink/renderer/core/frame/settings.json5 +++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -771,6 +771,18 @@ name: "textTrackTextSize", type: "String", }, + { + name: "textTrackWindowColor", + type: "String", + }, + { + name: "textTrackWindowPadding", + type: "String", + }, + { + name: "textTrackWindowRadius", + type: "String", + }, // Margin for title-safe placement of cues with overscan, gives top and bottom margin size as // percentage of video element height (for horizontal text) into which cues will not be placed.
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc index d953864..6addbfc 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -1432,6 +1432,7 @@ is_in_printing_ = true; #endif + GetFrame()->GetDocument()->SetPrinting(Document::kBeforePrinting); DispatchPrintEventRecursively(event_type_names::kBeforeprint); }
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index fc9270fd..1cbf13b 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -773,6 +773,27 @@ context_->PaintRenderingResultsToCanvas(kFrontBuffer); if (HasResourceProvider()) { if (!context.ContextDisabled()) { + // For 2D Canvas, there are two ways of render Canvas for printing: + // display list or image snapshot. Display list allows better PDF printing + // and we prefer this method. + // Here are the requirements for display list to be used: + // 1. We must have had a full repaint of the Canvas after beginprint + // event has been fired. Otherwise, we don't have a PaintRecord. + // 2. CSS property 'image-rendering' must not be 'pixelated'. + + // display list rendering: we replay the last full PaintRecord, if Canvas + // has been redraw since beginprint happened. + if (IsPrinting() && !Is3d() && canvas2d_bridge_) { + canvas2d_bridge_->FlushRecording(); + if (canvas2d_bridge_->getLastRecord()) { + const ComputedStyle* style = GetComputedStyle(); + if (style && style->ImageRendering() != EImageRendering::kPixelated) { + context.Canvas()->drawPicture(canvas2d_bridge_->getLastRecord()); + return; + } + } + } + // or image snapshot rendering: grab a snapshot and raster it. SkBlendMode composite_operator = !context_ || context_->CreationAttributes().alpha ? SkBlendMode::kSrcOver @@ -801,6 +822,10 @@ context_->MarkLayerComposited(); } +bool HTMLCanvasElement::IsPrinting() const { + return GetDocument().BeforePrintingOrPrinting(); +} + void HTMLCanvasElement::SetSurfaceSize(const IntSize& size) { size_ = size; did_fail_to_create_resource_provider_ = false;
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h index 375f60a..675071b 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -223,6 +223,7 @@ bool LowLatencyEnabled() const override { return !!frame_dispatcher_; } CanvasResourceProvider* GetOrCreateCanvasResourceProvider( AccelerationHint hint) override; + bool IsPrinting() const override; void DisableAcceleration(std::unique_ptr<Canvas2DLayerBridge> unaccelerated_bridge_used_for_testing = nullptr);
diff --git a/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc b/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc index 890a17a..251a4be 100644 --- a/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc +++ b/third_party/blink/renderer/core/html/forms/date_time_edit_element.cc
@@ -548,8 +548,8 @@ } inline Element* DateTimeEditElement::FieldsWrapperElement() const { - DCHECK(firstChild()); - return ToElementOrDie(firstChild()); + CHECK(!firstChild() || IsA<Element>(firstChild())); + return To<Element>(firstChild()); } void DateTimeEditElement::AddField(DateTimeFieldElement* field) {
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.cc b/third_party/blink/renderer/core/html/forms/file_input_type.cc index b1095de..50e65c4 100644 --- a/third_party/blink/renderer/core/html/forms/file_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/file_input_type.cc
@@ -323,16 +323,20 @@ void FileInputType::DisabledAttributeChanged() { DCHECK(IsShadowHost(GetElement())); + CHECK(!GetElement().UserAgentShadowRoot()->firstChild() || + IsA<Element>(GetElement().UserAgentShadowRoot()->firstChild())); if (Element* button = - ToElementOrDie(GetElement().UserAgentShadowRoot()->firstChild())) + To<Element>(GetElement().UserAgentShadowRoot()->firstChild())) button->SetBooleanAttribute(kDisabledAttr, GetElement().IsDisabledFormControl()); } void FileInputType::MultipleAttributeChanged() { DCHECK(IsShadowHost(GetElement())); + CHECK(!GetElement().UserAgentShadowRoot()->firstChild() || + IsA<Element>(GetElement().UserAgentShadowRoot()->firstChild())); if (Element* button = - ToElementOrDie(GetElement().UserAgentShadowRoot()->firstChild())) + To<Element>(GetElement().UserAgentShadowRoot()->firstChild())) button->setAttribute( kValueAttr, AtomicString(GetLocale().QueryString(
diff --git a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc index 72e2abe..c5d86ab0 100644 --- a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
@@ -336,6 +336,9 @@ } bool HTMLFormControlElement::IsKeyboardFocusable() const { + if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) + return HTMLElement::IsKeyboardFocusable(); + // Skip tabIndex check in a parent class. return IsFocusable(); }
diff --git a/third_party/blink/renderer/core/html/html_image_element.cc b/third_party/blink/renderer/core/html/html_image_element.cc index 7f0fba4..a06d37c 100644 --- a/third_party/blink/renderer/core/html/html_image_element.cc +++ b/third_party/blink/renderer/core/html/html_image_element.cc
@@ -757,32 +757,7 @@ GetImageLoader().UpdateFromElement(behavior, referrer_policy_); } - ImageResourceContent* image_content = GetImageLoader().GetContent(); - // Images such as data: uri's can return immediately and may already have - // errored out. - bool image_has_loaded = image_content && !image_content->IsLoading() && - !image_content->ErrorOccurred(); - bool image_still_loading = - !image_has_loaded && GetImageLoader().HasPendingActivity() && - !GetImageLoader().HasPendingError() && !ImageSourceURL().IsEmpty(); - bool image_has_image = image_content && image_content->HasImage(); - bool image_is_document = GetImageLoader().IsLoadingImageDocument() && - image_content && !image_content->ErrorOccurred(); - - // Icky special case for deferred images: - // A deferred image is not loading, does have pending activity, does not - // have an error, but it does have an ImageResourceContent associated - // with it, so imageHasLoaded will be true even though the image hasn't - // actually loaded. Fixing the definition of imageHasLoaded isn't - // sufficient, because a deferred image does have pending activity, does not - // have a pending error, and does have a source URL, so if imageHasLoaded - // was correct, imageStillLoading would become wrong. - // - // Instead of dealing with that, there's a separate check that the - // ImageResourceContent has non-null image data associated with it, which - // isn't folded into imageHasLoaded above. - if ((image_has_loaded && image_has_image) || image_still_loading || - image_is_document) + if (GetImageLoader().ImageIsPotentiallyAvailable()) EnsurePrimaryContent(); else EnsureCollapsedOrFallbackContent();
diff --git a/third_party/blink/renderer/core/html/track/text_track_container.cc b/third_party/blink/renderer/core/html/track/text_track_container.cc index 872db89..5fe6743 100644 --- a/third_party/blink/renderer/core/html/track/text_track_container.cc +++ b/third_party/blink/renderer/core/html/track/text_track_container.cc
@@ -66,21 +66,42 @@ } // namespace -TextTrackContainer::TextTrackContainer(Document& document) - : HTMLDivElement(document), default_font_size_(0) {} - TextTrackContainer::TextTrackContainer(HTMLMediaElement& media_element) - : TextTrackContainer(media_element.GetDocument()) { + : HTMLDivElement(media_element.GetDocument()), + media_element_(&media_element), + default_font_size_(0) { SetShadowPseudoId(AtomicString("-webkit-media-text-track-container")); - if (IsHTMLVideoElement(media_element)) - ObserveSizeChanges(media_element); + if (IsHTMLVideoElement(*media_element_)) + ObserveSizeChanges(*media_element_); } void TextTrackContainer::Trace(Visitor* visitor) { + visitor->Trace(media_element_); visitor->Trace(video_size_observer_); HTMLDivElement::Trace(visitor); } +Node::InsertionNotificationRequest TextTrackContainer::InsertedInto( + ContainerNode& root) { + if (!video_size_observer_ && media_element_->isConnected() && + IsHTMLVideoElement(*media_element_)) { + ObserveSizeChanges(*media_element_); + } + + return HTMLDivElement::InsertedInto(root); +} + +void TextTrackContainer::RemovedFrom(ContainerNode& insertion_point) { + DCHECK(!media_element_->isConnected()); + + HTMLDivElement::RemovedFrom(insertion_point); + + if (video_size_observer_) { + video_size_observer_->disconnect(); + video_size_observer_.Clear(); + } +} + LayoutObject* TextTrackContainer::CreateLayoutObject(const ComputedStyle&, LegacyLayout) { // TODO(mstensho): Should use LayoutObjectFactory to create the right type of
diff --git a/third_party/blink/renderer/core/html/track/text_track_container.h b/third_party/blink/renderer/core/html/track/text_track_container.h index 5735a05..190f2474 100644 --- a/third_party/blink/renderer/core/html/track/text_track_container.h +++ b/third_party/blink/renderer/core/html/track/text_track_container.h
@@ -39,9 +39,12 @@ class TextTrackContainer final : public HTMLDivElement { public: - TextTrackContainer(Document&); TextTrackContainer(HTMLMediaElement&); + // Node override. + Node::InsertionNotificationRequest InsertedInto(ContainerNode&) override; + void RemovedFrom(ContainerNode&) override; + // Runs the "rules for updating the text track rendering". The // ExposingControls enum is used in the WebVTT processing model to reset the // layout when the media controls become visible, to avoid overlapping them. @@ -60,6 +63,7 @@ LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout) override; + Member<HTMLMediaElement> media_element_; Member<ResizeObserver> video_size_observer_; float default_font_size_; };
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc b/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc index f3140d13..04897fe 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc
@@ -1129,6 +1129,13 @@ SetInlineStylePropertyIfNotEmpty(*cue_background_box_, CSSPropertyID::kFontSize, settings->GetTextTrackTextSize()); + SetInlineStylePropertyIfNotEmpty(*display_tree_, + CSSPropertyID::kBackgroundColor, + settings->GetTextTrackWindowColor()); + SetInlineStylePropertyIfNotEmpty(*display_tree_, CSSPropertyID::kPadding, + settings->GetTextTrackWindowPadding()); + SetInlineStylePropertyIfNotEmpty(*display_tree_, CSSPropertyID::kBorderRadius, + settings->GetTextTrackWindowRadius()); } ExecutionContext* VTTCue::GetExecutionContext() const {
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index 4a482c1..6d2cb10 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -3583,14 +3583,12 @@ if (RuntimeEnabledFeatures::ElementTimingEnabled(&GetDocument())) { LocalDOMWindow* window = GetDocument().domWindow(); if (window) { - ImageElementTiming::From(*window).NotifyBackgroundImageRemoved(this, - image); + ImageElementTiming::From(*window).NotifyImageRemoved(this, image); } } if (RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled()) { if (LocalFrameView* frame_view = GetFrameView()) { - frame_view->GetPaintTimingDetector().NotifyBackgroundImageRemoved(*this, - image); + frame_view->GetPaintTimingDetector().NotifyImageRemoved(*this, image); } } }
diff --git a/third_party/blink/renderer/core/layout/layout_vtt_cue.cc b/third_party/blink/renderer/core/layout/layout_vtt_cue.cc index 722895a6a..b94fee62 100644 --- a/third_party/blink/renderer/core/layout/layout_vtt_cue.cc +++ b/third_party/blink/renderer/core/layout/layout_vtt_cue.cc
@@ -137,7 +137,7 @@ } IntRect CueBoundingBox(const LayoutBox& cue_box) { - return ContentBoxRelativeToAncestor(cue_box, *cue_box.ContainingBlock()); + return PaddingBoxRelativeToAncestor(cue_box, *cue_box.ContainingBlock()); } bool SnapToLinesLayouter::IsOutside(const IntRect& title_area) const {
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc index ebfacde5..2f53751 100644 --- a/third_party/blink/renderer/core/loader/image_loader.cc +++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -384,6 +384,32 @@ return !HasPendingActivity() || referrer_policy != last_referrer_policy_; } +bool ImageLoader::ImageIsPotentiallyAvailable() const { + bool image_has_loaded = image_content_ && !image_content_->IsLoading() && + !image_content_->ErrorOccurred(); + bool image_still_loading = !image_has_loaded && HasPendingActivity() && + !HasPendingError() && + !element_->ImageSourceURL().IsEmpty(); + bool image_has_image = image_content_ && image_content_->HasImage(); + bool image_is_document = loading_image_document_ && image_content_ && + !image_content_->ErrorOccurred(); + + // Icky special case for deferred images: + // A deferred image is not loading, does have pending activity, does not + // have an error, but it does have an ImageResourceContent associated + // with it, so |image_has_loaded| will be true even though the image hasn't + // actually loaded. Fixing the definition of |image_has_loaded| isn't + // sufficient, because a deferred image does have pending activity, does not + // have a pending error, and does have a source URL, so if |image_has_loaded| + // was correct, |image_still_loading| would become wrong. + // + // Instead of dealing with that, there's a separate check that the + // ImageResourceContent has non-null image data associated with it, which + // isn't folded into |image_has_loaded| above. + return (image_has_loaded && image_has_image) || image_still_loading || + image_is_document; +} + void ImageLoader::ClearImage() { SetImageWithoutConsideringPendingLoadEvent(nullptr); } @@ -667,6 +693,13 @@ new_image_content == old_image_content) { ToLayoutImage(element_->GetLayoutObject())->IntrinsicSizeChanged(); } else { + // Loading didn't start (loading of images was disabled). We show fallback + // contents here, while we don't dispatch an 'error' event etc., because + // spec-wise the image remains in the "Unavailable" state. + if (new_image_content && + new_image_content->GetContentStatus() == ResourceStatus::kNotStarted) + NoImageResourceToLoad(); + if (pending_load_event_.IsActive()) pending_load_event_.Cancel();
diff --git a/third_party/blink/renderer/core/loader/image_loader.h b/third_party/blink/renderer/core/loader/image_loader.h index 30aee841..ffea35f 100644 --- a/third_party/blink/renderer/core/loader/image_loader.h +++ b/third_party/blink/renderer/core/loader/image_loader.h
@@ -95,6 +95,11 @@ network::mojom::ReferrerPolicy referrer_policy = network::mojom::ReferrerPolicy::kDefault) const; + // Returns true if a the owner of this loader should consider the image being + // loaded as "potentially available", i.e that it may eventually become + // available. + bool ImageIsPotentiallyAvailable() const; + // Cancels pending load events, and doesn't dispatch new ones. // Note: ClearImage/SetImage.*() are not a simple setter. // Check the implementation to see what they do. @@ -113,7 +118,6 @@ // Otherwise: // Normal loading via ResourceFetcher/ResourceLoader. // |image_resource_for_image_document_| is null. - bool IsLoadingImageDocument() { return loading_image_document_; } void SetLoadingImageDocument() { loading_image_document_ = true; } ImageResource* ImageResourceForImageDocument() const { return image_resource_for_image_document_;
diff --git a/third_party/blink/renderer/core/page/print_context_test.cc b/third_party/blink/renderer/core/page/print_context_test.cc index 6487b77f..b14acfddf 100644 --- a/third_party/blink/renderer/core/page/print_context_test.cc +++ b/third_party/blink/renderer/core/page/print_context_test.cc
@@ -6,8 +6,10 @@ #include <memory> +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/events/before_print_event.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/html/html_element.h" @@ -24,6 +26,8 @@ #include "third_party/blink/renderer/platform/wtf/text/text_stream.h" #include "third_party/skia/include/core/SkCanvas.h" +using testing::_; + namespace blink { const int kPageWidth = 800; @@ -60,6 +64,22 @@ return recorded_operations_; } + MOCK_METHOD2(onDrawRect, void(const SkRect&, const SkPaint&)); + MOCK_METHOD1(DrawPicture, void(const SkPicture*)); + MOCK_METHOD1(OnDrawPicture, void(const SkPicture*)); + MOCK_METHOD3(OnDrawPicture, + void(const SkPicture*, const SkMatrix*, const SkPaint*)); + MOCK_METHOD3(DrawPicture, + void(const SkPicture*, const SkMatrix*, const SkPaint*)); + MOCK_METHOD4(onDrawImage, + void(const SkImage*, SkScalar, SkScalar, const SkPaint*)); + MOCK_METHOD5(onDrawImageRect, + void(const SkImage*, + const SkRect*, + const SkRect&, + const SkPaint*, + SrcRectConstraint)); + private: Vector<Operation> recorded_operations_; }; @@ -84,8 +104,11 @@ GetDocument().body()->SetInnerHTMLFromString(body_content); } - void PrintSinglePage(MockPageContextCanvas& canvas) { + void PrintSinglePage(SkCanvas& canvas) { IntRect page_rect(0, 0, kPageWidth, kPageHeight); + GetDocument().SetPrinting(Document::kBeforePrinting); + Event* event = MakeGarbageCollected<BeforePrintEvent>(); + GetPrintContext().GetFrame()->DomWindow()->DispatchEvent(*event); GetPrintContext().BeginPrintMode(page_rect.Width(), page_rect.Height()); UpdateAllLifecyclePhasesForTest(); PaintRecordBuilder builder; @@ -396,6 +419,46 @@ EXPECT_EQ(node->OffsetWidth(), 800); } +TEST_P(PrintContextTest, Canvas2DBeforePrint) { + MockPageContextCanvas canvas; + SetBodyInnerHTML("<canvas id='c' width=100 height=100></canvas>"); + GetDocument().GetSettings()->SetScriptEnabled(true); + Element* const script_element = + GetDocument().CreateRawElement(html_names::kScriptTag); + script_element->setTextContent( + "window.addEventListener('beforeprint', (ev) => {" + "const ctx = document.getElementById('c').getContext('2d');" + "ctx.fillRect(0, 0, 10, 10);" + "ctx.fillRect(50, 50, 10, 10);" + "});"); + GetDocument().body()->AppendChild(script_element); + + EXPECT_CALL(canvas, onDrawRect(_, _)).Times(testing::AtLeast(2)); + + PrintSinglePage(canvas); +} + +TEST_P(PrintContextTest, Canvas2DPixelated) { + MockPageContextCanvas canvas; + SetBodyInnerHTML( + "<canvas id='c' style='image-rendering: pixelated' " + "width=100 height=100></canvas>"); + GetDocument().GetSettings()->SetScriptEnabled(true); + Element* const script_element = + GetDocument().CreateRawElement(html_names::kScriptTag); + script_element->setTextContent( + "window.addEventListener('beforeprint', (ev) => {" + "const ctx = document.getElementById('c').getContext('2d');" + "ctx.fillRect(0, 0, 10, 10);" + "ctx.fillRect(50, 50, 10, 10);" + "});"); + GetDocument().body()->AppendChild(script_element); + + EXPECT_CALL(canvas, onDrawImageRect(_, _, _, _, _)); + + PrintSinglePage(canvas); +} + // This tests that we don't resize or re-layout subframes in printed content. // TODO(weili): This test fails when the iframe isn't the root scroller - e.g. // Adding ScopedImplicitRootScrollerForTest disabler(false);
diff --git a/third_party/blink/renderer/core/paint/image_element_timing.cc b/third_party/blink/renderer/core/paint/image_element_timing.cc index abac00e2..d580430 100644 --- a/third_party/blink/renderer/core/paint/image_element_timing.cc +++ b/third_party/blink/renderer/core/paint/image_element_timing.cc
@@ -226,9 +226,8 @@ images_notified_.erase(image); } -void ImageElementTiming::NotifyBackgroundImageRemoved( - const LayoutObject* layout_object, - const ImageResourceContent* image) { +void ImageElementTiming::NotifyImageRemoved(const LayoutObject* layout_object, + const ImageResourceContent* image) { background_images_notified_.erase(std::make_pair(layout_object, image)); }
diff --git a/third_party/blink/renderer/core/paint/image_element_timing.h b/third_party/blink/renderer/core/paint/image_element_timing.h index 82cc5bb..04de9035 100644 --- a/third_party/blink/renderer/core/paint/image_element_timing.h +++ b/third_party/blink/renderer/core/paint/image_element_timing.h
@@ -56,8 +56,8 @@ // Called when the LayoutImage will be destroyed. void NotifyWillBeDestroyed(const LayoutObject*); - void NotifyBackgroundImageRemoved(const LayoutObject*, - const ImageResourceContent* image); + void NotifyImageRemoved(const LayoutObject*, + const ImageResourceContent* image); void Trace(blink::Visitor*) override;
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc index de8180f..0b563ed 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
@@ -63,8 +63,8 @@ DCHECK(b); if (a->first_size != b->first_size) return a->first_size > b->first_size; - // This make sure that two different nodes with the same |first_size| wouldn't - // be merged in the set. + // This make sure that two different |ImageRecord|s with the same |first_size| + // wouldn't be merged in the |size_ordered_set_|. return a->insertion_index < b->insertion_index; } @@ -166,15 +166,15 @@ records_manager_.RemoveInvisibleRecordIfNeeded(node_id); } -void ImagePaintTimingDetector::NotifyBackgroundImageRemoved( +void ImagePaintTimingDetector::NotifyImageRemoved( DOMNodeId node_id, const ImageResourceContent* cached_image) { if (!is_recording_) return; - BackgroundImageId background_image_id = std::make_pair(node_id, cached_image); - if (!records_manager_.IsRecordedVisibleNode(background_image_id)) + RecordId record_id = std::make_pair(node_id, cached_image); + if (!records_manager_.IsRecordedVisibleImage(record_id)) return; - records_manager_.RemoveVisibleRecord(background_image_id); + records_manager_.RemoveVisibleRecord(record_id); need_update_timing_at_frame_end_ = true; } @@ -207,14 +207,14 @@ return; // The callback is safe from race-condition only when running on main-thread. DCHECK(ThreadState::Current()->IsMainThread()); - records_manager_.AssignPaintTimeToRegisteredQueuedNodes( + records_manager_.AssignPaintTimeToRegisteredQueuedRecords( timestamp, last_queued_frame_index); UpdateCandidate(); num_pending_swap_callbacks_--; DCHECK_GE(num_pending_swap_callbacks_, 0); } -void ImageRecordsManager::AssignPaintTimeToRegisteredQueuedNodes( +void ImageRecordsManager::AssignPaintTimeToRegisteredQueuedRecords( const base::TimeTicks& timestamp, unsigned last_queued_frame_index) { // TODO(crbug.com/971419): should guarantee the queue not empty. @@ -231,7 +231,7 @@ } } -void ImagePaintTimingDetector::RecordBackgroundImage( +void ImagePaintTimingDetector::RecordImage( const LayoutObject& object, const IntSize& intrinsic_size, const ImageResourceContent& cached_image, @@ -241,22 +241,21 @@ return; DOMNodeId node_id = DOMNodeIds::IdForNode(node); DCHECK_NE(node_id, kInvalidDOMNodeId); - if (records_manager_.IsRecordedInvisibleNode(node_id)) + if (records_manager_.IsRecordedInvisibleImage(node_id)) return; - BackgroundImageId background_image_id = - std::make_pair(node_id, &cached_image); - bool is_recored_visible_node = - records_manager_.IsRecordedVisibleNode(background_image_id); - if (is_recored_visible_node && - !records_manager_.WasVisibleNodeLoaded(background_image_id) && + RecordId record_id = std::make_pair(node_id, &cached_image); + bool is_recored_visible_image = + records_manager_.IsRecordedVisibleImage(record_id); + if (is_recored_visible_image && + !records_manager_.IsVisibleImageLoaded(record_id) && cached_image.IsLoaded()) { - records_manager_.OnImageLoaded(background_image_id, frame_index_); + records_manager_.OnImageLoaded(record_id, frame_index_); need_update_timing_at_frame_end_ = true; return; } - if (is_recored_visible_node || !is_recording_) + if (is_recored_visible_image || !is_recording_) return; IntRect visual_rect = object.FragmentsVisualRectBoundingBox(); // Before the image resource starts loading, <img> has no size info. We wait @@ -272,14 +271,11 @@ rect_size, intrinsic_size.Area(), visual_rect.Size().Area()); if (rect_size == 0) { - // Each invisible background image is tracked by its node id. In other - // words, when a node is deemed as invisible, all of the background images - // are deemed as invisible. - records_manager_.RecordInvisibleNode(node_id); + records_manager_.RecordInvisible(node_id); } else { - records_manager_.RecordVisibleNode(background_image_id, rect_size); + records_manager_.RecordVisible(record_id, rect_size); if (cached_image.IsLoaded()) { - records_manager_.OnImageLoaded(background_image_id, frame_index_); + records_manager_.OnImageLoaded(record_id, frame_index_); need_update_timing_at_frame_end_ = true; } } @@ -288,10 +284,9 @@ ImageRecordsManager::ImageRecordsManager() : size_ordered_set_(&LargeImageFirst) {} -void ImageRecordsManager::OnImageLoaded( - const BackgroundImageId& background_image_id, - unsigned current_frame_index) { - base::WeakPtr<ImageRecord> record = FindVisibleRecord(background_image_id); +void ImageRecordsManager::OnImageLoaded(const RecordId& record_id, + unsigned current_frame_index) { + base::WeakPtr<ImageRecord> record = FindVisibleRecord(record_id); OnImageLoadedInternal(record, current_frame_index); } @@ -302,13 +297,12 @@ QueueToMeasurePaintTime(record, current_frame_index); } -void ImageRecordsManager::RecordVisibleNode( - const BackgroundImageId& background_image_id, - const uint64_t& visual_size) { - std::unique_ptr<ImageRecord> record = CreateImageRecord( - background_image_id.first, background_image_id.second, visual_size); +void ImageRecordsManager::RecordVisible(const RecordId& record_id, + const uint64_t& visual_size) { + std::unique_ptr<ImageRecord> record = + CreateImageRecord(record_id.first, record_id.second, visual_size); size_ordered_set_.insert(record->AsWeakPtr()); - visible_background_image_map_.insert(background_image_id, std::move(record)); + visible_images_.insert(record_id, std::move(record)); } std::unique_ptr<ImageRecord> ImageRecordsManager::CreateImageRecord( @@ -322,7 +316,7 @@ } ImageRecord* ImageRecordsManager::FindLargestPaintCandidate() const { - DCHECK_EQ(visible_background_image_map_.size(), size_ordered_set_.size()); + DCHECK_EQ(visible_images_.size(), size_ordered_set_.size()); if (size_ordered_set_.size() == 0) return nullptr; return size_ordered_set_.begin()->get();
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector.h b/third_party/blink/renderer/core/paint/image_paint_timing_detector.h index 526d38b3..ebf4cc8 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
@@ -52,7 +52,7 @@ bool loaded = false; }; -typedef std::pair<DOMNodeId, const ImageResourceContent*> BackgroundImageId; +typedef std::pair<DOMNodeId, const ImageResourceContent*> RecordId; // |ImageRecordsManager| is the manager of all of the images that Largest Image // Paint cares about. Note that an image does not necessarily correspond to a @@ -71,43 +71,36 @@ ImageRecordsManager(); ImageRecord* FindLargestPaintCandidate() const; - bool AreAllVisibleNodesDetached() const; - inline void RemoveInvisibleRecordIfNeeded( const DOMNodeId& invisible_node_id) { - invisible_node_ids_.erase(invisible_node_id); + invisible_images_.erase(invisible_node_id); } - inline void RemoveVisibleRecord( - const BackgroundImageId& background_image_id) { + + inline void RemoveVisibleRecord(const RecordId& record_id) { base::WeakPtr<ImageRecord> record = - visible_background_image_map_.find(background_image_id) - ->value->AsWeakPtr(); + visible_images_.find(record_id)->value->AsWeakPtr(); size_ordered_set_.erase(record); - visible_background_image_map_.erase(background_image_id); + visible_images_.erase(record_id); // Leave out |images_queued_for_paint_time_| intentionally because the null - // record will be removed in |AssignPaintTimeToRegisteredQueuedNodes|. + // record will be removed in |AssignPaintTimeToRegisteredQueuedRecords|. } - inline void RecordInvisibleNode(const DOMNodeId& node_id) { - invisible_node_ids_.insert(node_id); + inline void RecordInvisible(const DOMNodeId& node_id) { + invisible_images_.insert(node_id); } - void RecordVisibleNode(const BackgroundImageId& background_image_id, - const uint64_t& visual_size); - size_t CountInvisibleNodes() const { return invisible_node_ids_.size(); } - bool IsRecordedVisibleNode( - const BackgroundImageId& background_image_id) const { - return visible_background_image_map_.Contains(background_image_id); + void RecordVisible(const RecordId& record_id, const uint64_t& visual_size); + bool IsRecordedVisibleImage(const RecordId& record_id) const { + return visible_images_.Contains(record_id); } - bool IsRecordedInvisibleNode(const DOMNodeId& node_id) const { - return invisible_node_ids_.Contains(node_id); + bool IsRecordedInvisibleImage(const DOMNodeId& node_id) const { + return invisible_images_.Contains(node_id); } - inline bool WasVisibleNodeLoaded( - const BackgroundImageId& background_image_id) const { - DCHECK(visible_background_image_map_.Contains(background_image_id)); - return visible_background_image_map_.at(background_image_id)->loaded; + inline bool IsVisibleImageLoaded(const RecordId& record_id) const { + DCHECK(visible_images_.Contains(record_id)); + return visible_images_.at(record_id)->loaded; } - void OnImageLoaded(const BackgroundImageId&, unsigned current_frame_index); + void OnImageLoaded(const RecordId&, unsigned current_frame_index); void OnImageLoadedInternal(base::WeakPtr<ImageRecord>&, unsigned current_frame_index); @@ -128,8 +121,9 @@ DCHECK(last_registered_frame_index <= LastQueuedFrameIndex()); return last_registered_frame_index < LastQueuedFrameIndex(); } - void AssignPaintTimeToRegisteredQueuedNodes(const base::TimeTicks&, - unsigned last_queued_frame_index); + void AssignPaintTimeToRegisteredQueuedRecords( + const base::TimeTicks&, + unsigned last_queued_frame_index); inline unsigned LastQueuedFrameIndex() const { DCHECK(images_queued_for_paint_time_.back()); return images_queued_for_paint_time_.back()->frame_index; @@ -138,10 +132,9 @@ private: // Find the image record of an visible image. inline base::WeakPtr<ImageRecord> FindVisibleRecord( - const BackgroundImageId& background_image_id) const { - DCHECK(visible_background_image_map_.Contains(background_image_id)); - return visible_background_image_map_.find(background_image_id) - ->value->AsWeakPtr(); + const RecordId& record_id) const { + DCHECK(visible_images_.Contains(record_id)); + return visible_images_.find(record_id)->value->AsWeakPtr(); } std::unique_ptr<ImageRecord> CreateImageRecord( const DOMNodeId&, @@ -156,9 +149,8 @@ record->loaded = true; } - HashMap<BackgroundImageId, std::unique_ptr<ImageRecord>> - visible_background_image_map_; - HashSet<DOMNodeId> invisible_node_ids_; + HashMap<RecordId, std::unique_ptr<ImageRecord>> visible_images_; + HashSet<DOMNodeId> invisible_images_; // This stores the image records, which are ordered by size. ImageRecordSet size_ordered_set_; @@ -206,7 +198,7 @@ const PropertyTreeState& current_paint_chunk_properties); void OnPaintFinished(); void LayoutObjectWillBeDestroyed(const LayoutObject&); - void NotifyBackgroundImageRemoved(DOMNodeId, const ImageResourceContent*); + void NotifyImageRemoved(DOMNodeId, const ImageResourceContent*); // After the method being called, the detector stops to record new entries and // node removal. But it still observe the loading status. In other words, if // an image is recorded before stopping recording, and finish loading after
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc b/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc index 440f1ff5..3d93238 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
@@ -99,22 +99,22 @@ size_t CountVisibleImageRecords() { return GetPaintTimingDetector() .GetImagePaintTimingDetector() - ->records_manager_.visible_background_image_map_.size(); + ->records_manager_.visible_images_.size(); } size_t CountInvisibleRecords() { return GetPaintTimingDetector() .GetImagePaintTimingDetector() - ->records_manager_.invisible_node_ids_.size(); + ->records_manager_.invisible_images_.size(); } size_t ContainerTotalSize() { return GetPaintTimingDetector() .GetImagePaintTimingDetector() - ->records_manager_.invisible_node_ids_.size() + + ->records_manager_.invisible_images_.size() + GetPaintTimingDetector() .GetImagePaintTimingDetector() - ->records_manager_.visible_background_image_map_.size() + + ->records_manager_.visible_images_.size() + GetPaintTimingDetector() .GetImagePaintTimingDetector() ->records_manager_.size_ordered_set_.size() + @@ -126,7 +126,7 @@ size_t CountChildFrameRecords() { return GetChildPaintTimingDetector() .GetImagePaintTimingDetector() - ->records_manager_.visible_background_image_map_.size(); + ->records_manager_.visible_images_.size(); } size_t CountRankingSetRecords() {
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc index 5395153..9bad6af 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.cc +++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -2471,6 +2471,8 @@ float zoom = GetLayoutObject().StyleRef().EffectiveZoom(); if (zoom != 1) reference_box.Scale(1 / zoom); + if (!ResourceInfo() || ResourceInfo()->FilterReferenceBox() != reference_box) + GetLayoutObject().SetNeedsPaintPropertyUpdate(); EnsureResourceInfo().SetFilterReferenceBox(reference_box); }
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc index 97384366..9862b2b 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -1002,13 +1002,6 @@ state.backdrop_filter_bounds = properties_->Effect()->BackdropFilterBounds(); } - // With BGPT disabled, UpdateFilterReferenceBox gets called from - // CompositedLayerMapping::UpdateGraphicsLayerGeometry, but only - // for composited layers. - if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() || - layer->GetCompositingState() != kPaintsIntoOwnBacking) { - layer->UpdateFilterReferenceBox(); - } layer->UpdateCompositorFilterOperationsForBackdropFilter( state.backdrop_filter, &state.backdrop_filter_bounds); layer->ClearBackdropFilterOnEffectNodeDirty(); @@ -2290,6 +2283,17 @@ } void FragmentPaintPropertyTreeBuilder::SetNeedsPaintPropertyUpdateIfNeeded() { + if (object_.HasLayer()) { + PaintLayer* layer = ToLayoutBoxModelObject(object_).Layer(); + // With BGPT disabled, UpdateFilterReferenceBox gets called from + // CompositedLayerMapping::UpdateGraphicsLayerGeometry, but only + // for composited layers. + if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() || + layer->GetCompositingState() != kPaintsIntoOwnBacking) { + layer->UpdateFilterReferenceBox(); + } + } + if (!object_.IsBox()) return;
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc index 11b515d0..bc9bb00 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -1725,4 +1725,25 @@ EXPECT_FALSE(PaintPropertiesForElement("fixed")); } +TEST_P(PaintPropertyTreeUpdateTest, InlineFilterReferenceBoxChange) { + SetBodyInnerHTML(R"HTML( + <div id="spacer" style="display: inline-block; height: 20px"></div> + <br> + <span id="span" style="filter: blur(1px); font-size: 20px">SPAN</span> + )HTML"); + + const auto* properties = PaintPropertiesForElement("span"); + ASSERT_TRUE(properties); + ASSERT_TRUE(properties->Filter()); + EXPECT_EQ(FloatPoint(0, 20), + properties->Filter()->Filter().ReferenceBox().Location()); + + GetDocument().getElementById("spacer")->setAttribute( + html_names::kStyleAttr, "display: inline-block; height: 100px"); + UpdateAllLifecyclePhasesForTest(); + ASSERT_EQ(properties, PaintPropertiesForElement("span")); + EXPECT_EQ(FloatPoint(0, 100), + properties->Filter()->Filter().ReferenceBox().Location()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.cc b/third_party/blink/renderer/core/paint/paint_timing_detector.cc index d462f117..530f5ad 100644 --- a/third_party/blink/renderer/core/paint/paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/paint_timing_detector.cc
@@ -94,7 +94,7 @@ return; if (!IsBackgroundImageContentful(*object, *image)) return; - detector.GetImagePaintTimingDetector()->RecordBackgroundImage( + detector.GetImagePaintTimingDetector()->RecordImage( *object, image->Size(), *cached_image, current_paint_chunk_properties); } @@ -112,7 +112,7 @@ PaintTimingDetector& detector = frame_view->GetPaintTimingDetector(); if (!detector.GetImagePaintTimingDetector()) return; - detector.GetImagePaintTimingDetector()->RecordBackgroundImage( + detector.GetImagePaintTimingDetector()->RecordImage( object, intrinsic_size, *cached_image, current_paint_chunk_properties); } @@ -125,15 +125,14 @@ image_paint_timing_detector_->LayoutObjectWillBeDestroyed(object); } -void PaintTimingDetector::NotifyBackgroundImageRemoved( +void PaintTimingDetector::NotifyImageRemoved( const LayoutObject& object, const ImageResourceContent* cached_image) { DOMNodeId node_id = DOMNodeIds::ExistingIdForNode(object.GetNode()); if (node_id == kInvalidDOMNodeId) return; if (image_paint_timing_detector_) { - image_paint_timing_detector_->NotifyBackgroundImageRemoved(node_id, - cached_image); + image_paint_timing_detector_->NotifyImageRemoved(node_id, cached_image); } }
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.h b/third_party/blink/renderer/core/paint/paint_timing_detector.h index 19639a3..ee061d7 100644 --- a/third_party/blink/renderer/core/paint/paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/paint_timing_detector.h
@@ -50,8 +50,7 @@ inline static void NotifyTextPaint(const IntRect& text_visual_rect); void LayoutObjectWillBeDestroyed(const LayoutObject&); - void NotifyBackgroundImageRemoved(const LayoutObject&, - const ImageResourceContent*); + void NotifyImageRemoved(const LayoutObject&, const ImageResourceContent*); void NotifyPaintFinished(); void NotifyInputEvent(WebInputEvent::Type); bool NeedToNotifyInputOrScroll() const;
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/elements/toast/index.mjs b/third_party/blink/renderer/core/script/resources/layered_api/elements/toast/index.mjs index 281dabf..207e32b8 100644 --- a/third_party/blink/renderer/core/script/resources/layered_api/elements/toast/index.mjs +++ b/third_party/blink/renderer/core/script/resources/layered_api/elements/toast/index.mjs
@@ -81,6 +81,22 @@ null; } + set action(val) { + const previousAction = this.action; + if (val !== null) { + if (!isElement(val)) { + throw new TypeError('Invalid argument: must be type Element'); + } + + val.setAttribute('slot', 'action'); + this.insertBefore(val, previousAction); + } + + if (previousAction !== null) { + previousAction.remove(); + } + } + show({duration = DEFAULT_DURATION} = {}) { this.setAttribute('open', ''); clearTimeout(this.#timeoutID); @@ -124,7 +140,9 @@ const toast = new StdToastElement(message); const {action, ...showOptions} = options; - if (action !== undefined) { + if (isElement(action)) { + toast.action = action; + } else if (action !== undefined) { const actionButton = document.createElement('button'); // Unlike String(), this performs the desired JavaScript ToString operation. @@ -140,3 +158,14 @@ return toast; } + +const idGetter = + Object.getOwnPropertyDescriptor(Element.prototype, 'id').get; +function isElement(value) { + try { + idGetter.call(value); + return true; + } catch { + return false; + } +}
diff --git a/third_party/blink/renderer/core/svg/animation/smil_time_container.cc b/third_party/blink/renderer/core/svg/animation/smil_time_container.cc index 3f6fd62..f41918bc 100644 --- a/third_party/blink/renderer/core/svg/animation/smil_time_container.cc +++ b/third_party/blink/renderer/core/svg/animation/smil_time_container.cc
@@ -413,6 +413,7 @@ return; SMILTime earliest_fire_time = UpdateAnimations(elapsed, seek_to_time); + ApplyAnimations(elapsed); if (!CanScheduleFrame(earliest_fire_time)) return; double delay_time = earliest_fire_time.Value() - elapsed; @@ -429,7 +430,8 @@ // scheduledAnimations during this critical section. Similarly, any elements // removed will unschedule themselves, so this will catch modification of // animationsToApply. - prevent_scheduled_animations_changes_ = true; + base::AutoReset<bool> no_scheduled_animations_change_scope( + &prevent_scheduled_animations_changes_, true); #endif if (document_order_indexes_dirty_) @@ -445,8 +447,7 @@ attribute_map.RemoveAll(invalid_keys); } - HeapVector<ScheduledVector> active_sandwiches; - active_sandwiches.ReserveInitialCapacity(scheduled_animations_.size()); + active_sandwiches_.ReserveCapacity(scheduled_animations_.size()); for (auto& attribute_entry : scheduled_animations_) { AttributeMap& attribute_map = attribute_entry.value; for (auto& entry : attribute_map) { @@ -478,20 +479,12 @@ } if (!sandwich.IsEmpty()) { - active_sandwiches.push_back(sandwich); + active_sandwiches_.push_back(sandwich); } } } - if (active_sandwiches.IsEmpty()) { -#if DCHECK_IS_ON() - prevent_scheduled_animations_changes_ = false; -#endif - return earliest_fire_time; - } - - ScheduledVector animations_to_apply; - for (auto& sandwich : active_sandwiches) { + for (auto& sandwich : active_sandwiches_) { if (seek_to_time) { for (auto& animation : sandwich) { animation->TriggerPendingEvents(elapsed); @@ -525,6 +518,19 @@ if (next_fire_time.IsFinite()) earliest_fire_time = std::min(next_fire_time, earliest_fire_time); } + } + return earliest_fire_time; +} + +void SMILTimeContainer::ApplyAnimations(double elapsed) { +#if DCHECK_IS_ON() + prevent_scheduled_animations_changes_ = true; +#endif + ScheduledVector animations_to_apply; + for (auto& sandwich : active_sandwiches_) { + if (sandwich.IsEmpty()) { + continue; + } // Results are accumulated to the first animation that animates and // contributes to a particular element/attribute pair. @@ -553,12 +559,13 @@ animations_to_apply.push_back(result_element); } + active_sandwiches_.Shrink(0); if (animations_to_apply.IsEmpty()) { #if DCHECK_IS_ON() prevent_scheduled_animations_changes_ = false; #endif - return earliest_fire_time; + return; } UseCounter::Count(&GetDocument(), WebFeature::kSVGSMILAnimationAppliedEffect); @@ -588,7 +595,7 @@ } } } - return earliest_fire_time; + return; } void SMILTimeContainer::AdvanceFrameForTesting() { @@ -599,6 +606,7 @@ void SMILTimeContainer::Trace(blink::Visitor* visitor) { visitor->Trace(scheduled_animations_); visitor->Trace(owner_svg_element_); + visitor->Trace(active_sandwiches_); } } // namespace blink
diff --git a/third_party/blink/renderer/core/svg/animation/smil_time_container.h b/third_party/blink/renderer/core/svg/animation/smil_time_container.h index 24a9ca84..ea02d8b 100644 --- a/third_party/blink/renderer/core/svg/animation/smil_time_container.h +++ b/third_party/blink/renderer/core/svg/animation/smil_time_container.h
@@ -112,6 +112,7 @@ void UpdateAnimationsAndScheduleFrameIfNeeded(double elapsed, bool seek_to_time = false); SMILTime UpdateAnimations(double elapsed, bool seek_to_time); + void ApplyAnimations(double elapsed); void ServiceOnNextFrame(); void ScheduleWakeUp(double delay_time, FrameSchedulingState); bool HasPendingSynchronization() const; @@ -137,6 +138,7 @@ TaskRunnerTimer<SMILTimeContainer> animation_policy_once_timer_; AnimationsMap scheduled_animations_; + HeapVector<ScheduledVector> active_sandwiches_; Member<SVGSVGElement> owner_svg_element_;
diff --git a/third_party/blink/renderer/core/svg/svg_animated_length.cc b/third_party/blink/renderer/core/svg/svg_animated_length.cc index 6179957..72f7c26 100644 --- a/third_party/blink/renderer/core/svg/svg_animated_length.cc +++ b/third_party/blink/renderer/core/svg/svg_animated_length.cc
@@ -39,9 +39,13 @@ SVGAnimatedProperty<SVGLength>::AttributeChanged(value); if (SVGLength::NegativeValuesForbiddenForAnimatedLengthAttribute( - AttributeName()) && - BaseValue()->ValueInSpecifiedUnits() < 0) - parse_status = SVGParseStatus::kNegativeValue; + AttributeName())) { + // TODO(crbug.com/982425): Pass |kValueRangeNonNegative| to property parser + // to handle range checking on math functions correctly, and also to avoid + // this ad hoc range checking. + if (BaseValue()->IsNegativeNumericLiteral()) + parse_status = SVGParseStatus::kNegativeValue; + } return parse_status; }
diff --git a/third_party/blink/renderer/core/svg/svg_length.cc b/third_party/blink/renderer/core/svg/svg_length.cc index 9bd69733..4b28bdbc 100644 --- a/third_party/blink/renderer/core/svg/svg_length.cc +++ b/third_party/blink/renderer/core/svg/svg_length.cc
@@ -360,4 +360,10 @@ value_ = CreateInitialCSSValue(static_cast<Initial>(initial_value)); } +bool SVGLength::IsNegativeNumericLiteral() const { + if (!value_->IsNumericLiteralValue()) + return false; + return value_->GetDoubleValue() < 0; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_length.h b/third_party/blink/renderer/core/svg/svg_length.h index f63aa8c..719d474 100644 --- a/third_party/blink/renderer/core/svg/svg_length.h +++ b/third_party/blink/renderer/core/svg/svg_length.h
@@ -114,6 +114,7 @@ bool IsFontRelative() const { return value_->IsFontRelativeLength(); } bool IsCalculated() const { return value_->IsCalculated(); } + bool IsNegativeNumericLiteral() const; bool IsZero() const { return value_->GetFloatValue() == 0; } static SVGLengthMode LengthModeForAnimatedLengthAttribute(
diff --git a/third_party/blink/renderer/core/timing/performance_mark.cc b/third_party/blink/renderer/core/timing/performance_mark.cc index 1464e99..8e52412 100644 --- a/third_party/blink/renderer/core/timing/performance_mark.cc +++ b/third_party/blink/renderer/core/timing/performance_mark.cc
@@ -11,6 +11,8 @@ #include "third_party/blink/renderer/core/timing/performance.h" #include "third_party/blink/renderer/core/timing/performance_mark_options.h" #include "third_party/blink/renderer/core/timing/performance_user_timing.h" +#include "third_party/blink/renderer/core/timing/worker_global_scope_performance.h" +#include "third_party/blink/renderer/core/workers/worker_global_scope.h" namespace blink { @@ -49,15 +51,23 @@ const AtomicString& mark_name, PerformanceMarkOptions* mark_options, ExceptionState& exception_state) { - LocalDOMWindow* window = LocalDOMWindow::From(script_state); - if (!window) - return nullptr; - Performance* performance = DOMWindowPerformance::performance(*window); - if (!performance) - return nullptr; + Performance* performance = nullptr; + if (LocalDOMWindow* window = LocalDOMWindow::From(script_state)) { + performance = DOMWindowPerformance::performance(*window); + DCHECK(performance); + } else if (auto* scope = DynamicTo<WorkerGlobalScope>( + ExecutionContext::From(script_state))) { + performance = WorkerGlobalScopePerformance::performance(*scope); + DCHECK(performance); + } - return performance->GetUserTiming().CreatePerformanceMark( - script_state, mark_name, mark_options, exception_state); + if (performance) { + return performance->GetUserTiming().CreatePerformanceMark( + script_state, mark_name, mark_options, exception_state); + } + exception_state.ThrowTypeError( + "PerformanceMark: no 'worker' or 'window' in current context."); + return nullptr; } AtomicString PerformanceMark::entryType() const {
diff --git a/third_party/blink/renderer/devtools/front_end/audits/lighthouse/report-generator.js b/third_party/blink/renderer/devtools/front_end/audits/lighthouse/report-generator.js index 01257be..cec8f79 100644 --- a/third_party/blink/renderer/devtools/front_end/audits/lighthouse/report-generator.js +++ b/third_party/blink/renderer/devtools/front_end/audits/lighthouse/report-generator.js
@@ -18,10 +18,18 @@ const cachedResources = Runtime.cachedResources; module.exports = { - REPORT_CSS: cachedResources['audits/lighthouse/report.css'], - REPORT_JAVASCRIPT: cachedResources['audits/lighthouse/report.js'], - REPORT_TEMPLATE: cachedResources['audits/lighthouse/template.html'], - REPORT_TEMPLATES: cachedResources['audits/lighthouse/templates.html'], + get REPORT_CSS() { + return cachedResources['audits/lighthouse/report.css']; + }, + get REPORT_JAVASCRIPT() { + return cachedResources['audits/lighthouse/report.js']; + }, + get REPORT_TEMPLATE() { + return cachedResources['audits/lighthouse/template.html']; + }, + get REPORT_TEMPLATES() { + return cachedResources['audits/lighthouse/templates.html']; + }, }; },{}],1:[function(require,module,exports){
diff --git a/third_party/blink/renderer/devtools/front_end/persistence/WorkspaceSettingsTab.js b/third_party/blink/renderer/devtools/front_end/persistence/WorkspaceSettingsTab.js index a534245..f0e40db6 100644 --- a/third_party/blink/renderer/devtools/front_end/persistence/WorkspaceSettingsTab.js +++ b/third_party/blink/renderer/devtools/front_end/persistence/WorkspaceSettingsTab.js
@@ -105,7 +105,7 @@ */ _renderFileSystem(fileSystem) { const fileSystemPath = fileSystem.path(); - const lastIndexOfSlash = fileSystemPath.lastIndexOf(Host.isWin() ? '\\' : '/'); + const lastIndexOfSlash = fileSystemPath.lastIndexOf('/'); const folderName = fileSystemPath.substr(lastIndexOfSlash + 1); const element = createElementWithClass('div', 'file-system-container');
diff --git a/third_party/blink/renderer/devtools/scripts/check_localizable_resources.js b/third_party/blink/renderer/devtools/scripts/check_localizable_resources.js index 525bc05..bec1895 100644 --- a/third_party/blink/renderer/devtools/scripts/check_localizable_resources.js +++ b/third_party/blink/renderer/devtools/scripts/check_localizable_resources.js
@@ -44,8 +44,9 @@ async function getErrors(frontendStrings, IDSkeys) { const toAddError = await checkLocalizedStrings.getAndReportResourcesToAdd(frontendStrings, IDSkeys); + const toModifyError = checkLocalizedStrings.getAndReportIDSKeysToModify(); const toRemoveError = checkLocalizedStrings.getAndReportResourcesToRemove(frontendStrings, IDSkeys); - let error = `${toAddError ? toAddError : ''}${toRemoveError ? toRemoveError : ''}`; + let error = `${toAddError || ''}${toModifyError || ''}${toRemoveError || ''}`; if (error === '') { console.log('DevTools localizable resources checker passed.'); @@ -61,9 +62,10 @@ const keysToAddToGRD = checkLocalizedStrings.getDifference(IDSkeys, frontendStrings); const keysToRemoveFromGRD = checkLocalizedStrings.getDifference(frontendStrings, IDSkeys); const resourceAdded = await addResourcesToGRDP(keysToAddToGRD, keysToRemoveFromGRD); + const resourceModified = await modifyResourcesInGRDP(); const resourceRemoved = await removeResourcesFromGRDP(keysToRemoveFromGRD); - if (!resourceAdded && !resourceRemoved) { + if (!resourceAdded && !resourceRemoved && !resourceModified) { console.log('DevTools localizable resources checker passed.'); return; } @@ -78,27 +80,30 @@ // Return true if any resources are added async function addResourcesToGRDP(keysToAddToGRD, keysToRemoveFromGRD) { + function mapGRDPFilePathToStrings(keysToAddToGRD, keysToRemoveFromGRD) { + const grdpFilePathToStrings = new Map(); + // Get the grdp files that need to be modified + for (const [key, stringObj] of keysToAddToGRD) { + if (!grdpFilePathToStrings.has(stringObj.grdpPath)) + grdpFilePathToStrings.set(stringObj.grdpPath, []); + + // Add the IDS key to stringObj so we have access to it later + stringObj.ids = key; + // If the same key is to be removed, this is likely a string copy + // to another folder. Keep the description. + if (keysToRemoveFromGRD.has(key)) + stringObj.description = keysToRemoveFromGRD.get(key).description; + grdpFilePathToStrings.get(stringObj.grdpPath).push(stringObj); + } + return grdpFilePathToStrings; + } + if (keysToAddToGRD.size === 0) return false; // Map grdp file path to strings to be added to that file so that we only need to // modify every grdp file once - const grdpFilePathToStrings = new Map(); - - // Get the grdp files that need to be modified - for (const [key, stringObj] of keysToAddToGRD) { - if (!grdpFilePathToStrings.has(stringObj.grdpPath)) - grdpFilePathToStrings.set(stringObj.grdpPath, []); - - // Add the IDS key to stringObj so we have access to it later - stringObj.ids = key; - // If the same key is to be removed, this is likely a string copy - // to another folder. Keep the description. - if (keysToRemoveFromGRD.has(key)) - stringObj.description = keysToRemoveFromGRD.get(key).description; - grdpFilePathToStrings.get(stringObj.grdpPath).push(stringObj); - } - + const grdpFilePathToStrings = mapGRDPFilePathToStrings(keysToAddToGRD, keysToRemoveFromGRD); const promises = []; const grdpFilePathsToAdd = []; @@ -188,28 +193,44 @@ return writeFileAsync(localizationUtils.GRD_PATH, newGrdFileContent); } +// Return true if any resources are updated +async function modifyResourcesInGRDP() { + const messagesToModify = checkLocalizedStrings.getIDSKeysToModify(); + if (messagesToModify.size === 0) + return false; + + const grdpToMessages = mapGRDPFilePathToMessages(messagesToModify); + const promises = []; + for (const [grdpPath, messages] of grdpToMessages) { + let fileContent = await localizationUtils.parseFileContent(grdpPath); + for (const message of messages) { + const idsRegex = new RegExp(`name="${message.actualIDSKey}"`); + fileContent = fileContent.replace(idsRegex, `name="${message.ids}"`); + } + promises.push(writeFileAsync(grdpPath, fileContent)); + } + await Promise.all(promises); + return true; +} + // Return true if any resources are removed async function removeResourcesFromGRDP(keysToRemoveFromGRD) { + function lineContainsIDS(line, messages) { + return messages.some(message => line.includes(message.ids)); + } + if (keysToRemoveFromGRD.size === 0) return false; - // Map grdp file path to message IDS keys to remove - const grdpFilePathToKeys = new Map(); - for (const [key, messageObj] of keysToRemoveFromGRD) { - if (!grdpFilePathToKeys.has(messageObj.grdpPath)) - grdpFilePathToKeys.set(messageObj.grdpPath, []); - - grdpFilePathToKeys.get(messageObj.grdpPath).push(key); - } - + const grdpToMessages = mapGRDPFilePathToMessages(keysToRemoveFromGRD); const promises = []; - for (const [grdpFilePath, listOfKeys] of grdpFilePathToKeys) { + for (const [grdpFilePath, messages] of grdpToMessages) { let newGrdpFileContent = ''; const grdpFileContent = await localizationUtils.parseFileContent(grdpFilePath); const grdpFileLines = grdpFileContent.split('\n'); for (let i = 0; i < grdpFileLines.length; i++) { - if (!lineContainsIDS(grdpFileLines[i], listOfKeys)) { + if (!lineContainsIDS(grdpFileLines[i], messages)) { newGrdpFileContent += grdpFileLines[i]; if (i < grdpFileLines.length - 1) newGrdpFileContent += '\n'; @@ -226,6 +247,17 @@ return true; } -function lineContainsIDS(line, listOfIDS) { - return listOfIDS.some(ids => line.includes(ids)); +// Given a map from IDS key to a list of messages, return a map +// from grdp file path to a list of messages with a new property +// `ids` set to the key. +function mapGRDPFilePathToMessages(keyToMessages) { + const grdpFilePathToMessages = new Map(); + for (const [ids, message] of keyToMessages) { + if (!grdpFilePathToMessages.has(message.grdpPath)) + grdpFilePathToMessages.set(message.grdpPath, []); + + message.ids = ids; + grdpFilePathToMessages.get(message.grdpPath).push(message); + } + return grdpFilePathToMessages; }
diff --git a/third_party/blink/renderer/devtools/scripts/localization_utils/check_localized_strings.js b/third_party/blink/renderer/devtools/scripts/localization_utils/check_localized_strings.js index 0a912dc9..32e1dde3 100644 --- a/third_party/blink/renderer/devtools/scripts/localization_utils/check_localized_strings.js +++ b/third_party/blink/renderer/devtools/scripts/localization_utils/check_localized_strings.js
@@ -42,6 +42,7 @@ // Format // { // IDS_KEY => { +// actualIDSKey: string, // the IDS key in the message tag // description: string, // filepath: string, // location: { @@ -297,31 +298,33 @@ } // Example: - // <message name="IDS_*" desc="Description of this message"> + // <message name="IDS_DEVTOOLS_md5_hash" desc="Description of this message"> // Message text here with optional placeholders <ph name="phname">$1s</ph> // </message> // match[0]: the entire '<message>...</message>' block. - // match[1]: 'Description of this message' - // match[2]: ' Message text here with optional placeholders <ph name="phname">$1s</ph>\n ' - const messageRegex = new RegExp('<message[^>]*desc="([^"]*)"[^>]*>\s*\n(.*?)<\/message>', 'gms'); + // match[1]: 'IDS_DEVTOOLS_md5_hash' + // match[2]: 'Description of this message' + // match[3]: ' Message text here with optional placeholders <ph name="phname">$1s</ph>\n ' + const messageRegex = new RegExp('<message[^>]*name="([^"]*)"[^>]*desc="([^"]*)"[^>]*>\s*\n(.*?)<\/message>', 'gms'); let match; while ((match = messageRegex.exec(fileContent)) !== null) { const line = lineNumberOfIndex(fileContent, match.index); - const description = match[1]; - let message = match[2]; + const actualIDSKey = match[1]; + const description = match[2]; + let message = match[3]; message = convertToFrontendPlaceholders(message.trim()); message = stripWhitespacePadding(message); message = localizationUtils.sanitizeStringIntoFrontendFormat(message); const ids = localizationUtils.getIDSKey(message); - IDSkeys.set(ids, {grdpPath: filePath, location: {start: {line}, end: {line}}, description}); + IDSkeys.set(ids, {actualIDSKey, grdpPath: filePath, location: {start: {line}, end: {line}}, description}); } } /** * The following functions compare frontend localizable strings - * with grdp <message>s and report error of resources to add or - * remove. + * with grdp <message>s and report error of resources to add, + * remove or modify. */ async function getAndReportResourcesToAdd(frontendStrings, IDSkeys) { const keysToAddToGRD = getDifference(IDSkeys, frontendStrings); @@ -363,6 +366,22 @@ return errorStr; } +function getAndReportIDSKeysToModify() { + const messagesToModify = getIDSKeysToModify(); + if (messagesToModify.size === 0) + return; + + let errorStr = '\nThe following GRD/GRDP message(s) do not have the correct IDS key.\n'; + errorStr += 'Please update the key(s) by changing the "name" value.\n\n'; + + for (const [expectedIDSKey, message] of messagesToModify) { + errorStr += `${localizationUtils.getRelativeFilePathFromSrc(message.grdpPath)}${ + localizationUtils.getLocationMessage(message.location)}:\n`; + errorStr += `${message.actualIDSKey} --> ${expectedIDSKey}\n\n`; + } + return errorStr; +} + /** * Output a Map containing sorted entries that are in @comparison but not @reference, * or entries that are in both but belong to different grdp files. @@ -376,11 +395,22 @@ return new Map(difference.sort()); } +function getIDSKeysToModify() { + const messagesToModify = new Map(); + for (const [expectedIDSKey, message] of IDSkeys) { + if (expectedIDSKey !== message.actualIDSKey) + messagesToModify.set(expectedIDSKey, message); + } + return messagesToModify; +} + module.exports = { frontendStrings, IDSkeys, parseLocalizableResourceMaps, + getAndReportIDSKeysToModify, getAndReportResourcesToAdd, getAndReportResourcesToRemove, - getDifference + getDifference, + getIDSKeysToModify };
diff --git a/third_party/blink/renderer/modules/accessibility/ax_selection.cc b/third_party/blink/renderer/modules/accessibility/ax_selection.cc index bdf32836..827dfd3 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_selection.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_selection.cc
@@ -120,15 +120,6 @@ AXSelection AXSelection::FromCurrentSelection( const Document& document, const AXSelectionBehavior selection_behavior) { - // Previously, retrieving the selection would cause the layout to become - // clean, because we were using a deprecated function for retrieving the - // selection from the DOM tree, - // FrameSelection::ComputeVisibleSelectionInDOMTreeDeprecated. The layout - // should not be dirty in the first place, but somehow it is. While we are - // investigating the reasons behind this, the workaround is to restore the - // previous behavior by forcing the layout to clean. - // TODO(nektar): Remove the following line at the earliest opportunity. - const_cast<Document&>(document).UpdateStyleAndLayout(); const LocalFrame* frame = document.GetFrame(); if (!frame) return {};
diff --git a/third_party/blink/renderer/modules/credentialmanager/authenticator_selection_criteria.idl b/third_party/blink/renderer/modules/credentialmanager/authenticator_selection_criteria.idl index 7efb40a0..59f6982 100644 --- a/third_party/blink/renderer/modules/credentialmanager/authenticator_selection_criteria.idl +++ b/third_party/blink/renderer/modules/credentialmanager/authenticator_selection_criteria.idl
@@ -22,5 +22,5 @@ dictionary AuthenticatorSelectionCriteria { AuthenticatorAttachment authenticatorAttachment; boolean requireResidentKey = false; - UserVerificationRequirement userVerification = "preferred"; + UserVerificationRequirement userVerification; };
diff --git a/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc b/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc index 530c4421..4a5fac5 100644 --- a/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc +++ b/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
@@ -293,8 +293,11 @@ mojo_criteria->authenticator_attachment = ConvertTo<AuthenticatorAttachment>(criteria->authenticatorAttachment()); mojo_criteria->require_resident_key = criteria->requireResidentKey(); - mojo_criteria->user_verification = - ConvertTo<UserVerificationRequirement>(criteria->userVerification()); + mojo_criteria->user_verification = UserVerificationRequirement::PREFERRED; + if (criteria->hasUserVerification()) { + mojo_criteria->user_verification = + ConvertTo<UserVerificationRequirement>(criteria->userVerification()); + } return mojo_criteria; } @@ -553,8 +556,11 @@ } } - mojo_options->user_verification = - ConvertTo<UserVerificationRequirement>(options->userVerification()); + mojo_options->user_verification = UserVerificationRequirement::PREFERRED; + if (options->hasUserVerification()) { + mojo_options->user_verification = + ConvertTo<UserVerificationRequirement>(options->userVerification()); + } if (options->hasExtensions()) { auto* extensions = options->extensions();
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc index e676d55..4b5b647 100644 --- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc +++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -16,6 +16,7 @@ #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/frame/frame.h" +#include "third_party/blink/renderer/core/frame/frame_console.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/inspector/console_message.h" #include "third_party/blink/renderer/core/page/frame_tree.h" @@ -536,6 +537,18 @@ } } + if (!options->publicKey()->hasUserVerification()) { + resolver->GetFrame()->Console().AddMessage(ConsoleMessage::Create( + mojom::ConsoleMessageSource::kJavaScript, + mojom::ConsoleMessageLevel::kWarning, + "publicKey.userVerification was not set to any value in Web " + "Authentication navigator.credentials.get() call. This defaults to " + "'preferred', which is probably not what you want. If in doubt, set " + "to 'discouraged'. See " + "https://chromium.googlesource.com/chromium/src/+/master/content/" + "browser/webauth/uv_preferred.md for details.")); + } + if (options->hasSignal()) { if (options->signal()->aborted()) { resolver->Reject(MakeGarbageCollected<DOMException>( @@ -735,6 +748,21 @@ WTF::Bind(&Abort, WTF::Passed(WrapPersistent(script_state)))); } + if (options->publicKey()->hasAuthenticatorSelection() && + !options->publicKey() + ->authenticatorSelection() + ->hasUserVerification()) { + resolver->GetFrame()->Console().AddMessage(ConsoleMessage::Create( + mojom::ConsoleMessageSource::kJavaScript, + mojom::ConsoleMessageLevel::kWarning, + "publicKey.authenticatorSelection.userVerification was not set to " + "any value in Web Authentication navigator.credentials.create() " + "call. This defaults to 'preferred', which is probably not what you " + "want. If in doubt, set to 'discouraged'. See " + "https://chromium.googlesource.com/chromium/src/+/master/content/" + "browser/webauth/uv_preferred.md for details")); + } + auto mojo_options = MojoPublicKeyCredentialCreationOptions::From(options->publicKey()); if (!mojo_options) {
diff --git a/third_party/blink/renderer/modules/credentialmanager/public_key_credential_request_options.idl b/third_party/blink/renderer/modules/credentialmanager/public_key_credential_request_options.idl index d5fe5025..041dcb58 100644 --- a/third_party/blink/renderer/modules/credentialmanager/public_key_credential_request_options.idl +++ b/third_party/blink/renderer/modules/credentialmanager/public_key_credential_request_options.idl
@@ -9,6 +9,6 @@ unsigned long timeout; USVString rpId; sequence<PublicKeyCredentialDescriptor> allowCredentials = []; - UserVerificationRequirement userVerification = "preferred"; + UserVerificationRequirement userVerification; AuthenticationExtensionsClientInputs extensions; };
diff --git a/third_party/blink/renderer/modules/exported/web_ax_object.cc b/third_party/blink/renderer/modules/exported/web_ax_object.cc index 0d5844e..2455817 100644 --- a/third_party/blink/renderer/modules/exported/web_ax_object.cc +++ b/third_party/blink/renderer/modules/exported/web_ax_object.cc
@@ -127,6 +127,8 @@ static bool IsLayoutClean(Document* document) { if (!document || !document->View()) return false; + if (document->NeedsLayoutTreeUpdate()) + return false; if (document->View()->NeedsLayout()) return false; DocumentLifecycle::LifecycleState state = document->Lifecycle().GetState();
diff --git a/third_party/blink/renderer/modules/idle/OWNERS b/third_party/blink/renderer/modules/idle/OWNERS index 5a67a327..bb1b52f 100644 --- a/third_party/blink/renderer/modules/idle/OWNERS +++ b/third_party/blink/renderer/modules/idle/OWNERS
@@ -1 +1,3 @@ file://content/browser/idle/OWNERS + +# TEAM: fugu-dev@chromium.org
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc b/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc index b9a11484..c0b2f16 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate.cc
@@ -50,16 +50,6 @@ kMax = 3 }; -// These values are used for histograms. Do not reorder. -enum class LockResultMetrics { - kAlreadyLocked = 0, // Frame already has a lock. - kPortrait = 1, // Locked to portrait. - kLandscape = 2, // Locked to landscape. - - // Keep at the end. - kMax = 3 -}; - void RecordMetadataAvailability(MetadataAvailabilityMetrics metrics) { DEFINE_STATIC_LOCAL( EnumerationHistogram, metadata_histogram, @@ -68,13 +58,6 @@ metadata_histogram.Count(static_cast<int>(metrics)); } -void RecordLockResult(LockResultMetrics metrics) { - DEFINE_STATIC_LOCAL(EnumerationHistogram, lock_result_histogram, - ("Media.Video.FullscreenOrientationLock.LockResult", - static_cast<int>(LockResultMetrics::kMax))); - lock_result_histogram.Count(static_cast<int>(metrics)); -} - void RecordAutoRotateEnabled(bool enabled) { DEFINE_STATIC_LOCAL( BooleanHistogram, auto_rotate_histogram, @@ -144,21 +127,14 @@ auto* controller = ScreenOrientationController::From(*GetDocument().GetFrame()); - if (controller->MaybeHasActiveLock()) { - RecordLockResult(LockResultMetrics::kAlreadyLocked); + if (controller->MaybeHasActiveLock()) return; - } locked_orientation_ = ComputeOrientationLock(); DCHECK_NE(locked_orientation_, kWebScreenOrientationLockDefault); controller->lock(locked_orientation_, std::make_unique<DummyScreenOrientationCallback>()); - if (locked_orientation_ == kWebScreenOrientationLockLandscape) - RecordLockResult(LockResultMetrics::kLandscape); - else - RecordLockResult(LockResultMetrics::kPortrait); - MaybeListenToDeviceOrientation(); }
diff --git a/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css index 01a5fbe..26cbd81 100644 --- a/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css +++ b/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
@@ -1226,7 +1226,6 @@ transition: top 433ms linear; } - video::-webkit-media-text-track-display { position: absolute; overflow: hidden;
diff --git a/third_party/blink/renderer/modules/sms/OWNERS b/third_party/blink/renderer/modules/sms/OWNERS index ad9d6f7..39f063f 100644 --- a/third_party/blink/renderer/modules/sms/OWNERS +++ b/third_party/blink/renderer/modules/sms/OWNERS
@@ -1 +1,4 @@ file://content/browser/sms/OWNERS + +# COMPONENT: Blink>SMS +# TEAM: fugu-dev@chromium.org
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc index 225e4d0..77c2ce3 100644 --- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc +++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
@@ -266,7 +266,7 @@ void OfflineAudioDestinationHandler::NotifySuspend(size_t frame) { DCHECK(IsMainThread()); - if (Context() && Context()->GetExecutionContext()) + if (!IsExecutionContextDestroyed() && Context()) Context()->ResolveSuspendOnMainThread(frame); }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_buffer.cc b/third_party/blink/renderer/modules/webgl/webgl_buffer.cc index 2df498d..d49b4fe 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_buffer.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_buffer.cc
@@ -41,9 +41,7 @@ SetObject(buffer); } -WebGLBuffer::~WebGLBuffer() { - RunDestructor(); -} +WebGLBuffer::~WebGLBuffer() = default; void WebGLBuffer::DeleteObjectImpl(gpu::gles2::GLES2Interface* gl) { gl->DeleteBuffers(1, &object_);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc index 0746836d..d25b582 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc
@@ -219,9 +219,7 @@ ctx->ContextGL()->GenFramebuffers(1, &object_); } -WebGLFramebuffer::~WebGLFramebuffer() { - RunDestructor(); -} +WebGLFramebuffer::~WebGLFramebuffer() = default; void WebGLFramebuffer::SetAttachmentForBoundFramebuffer(GLenum target, GLenum attachment,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_object.cc b/third_party/blink/renderer/modules/webgl/webgl_object.cc index b3db68f..094b25c 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_object.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_object.cc
@@ -76,10 +76,10 @@ DeleteObject(nullptr); } -void WebGLObject::RunDestructor() { +void WebGLObject::Dispose() { DCHECK(!destruction_in_progress_); - // This boilerplate destructor is sufficient for all subclasses, as long - // as they implement deleteObjectImpl properly, and don't try to touch + // This boilerplate pre-finalizer is sufficient for all subclasses, as long + // as they implement DeleteObjectImpl properly, and don't try to touch // other objects on the Oilpan heap if the destructor's been entered. destruction_in_progress_ = true; DetachAndDeleteObject();
diff --git a/third_party/blink/renderer/modules/webgl/webgl_object.h b/third_party/blink/renderer/modules/webgl/webgl_object.h index 1ac871c..a595ece 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_object.h +++ b/third_party/blink/renderer/modules/webgl/webgl_object.h
@@ -57,13 +57,19 @@ } class WebGLObject : public ScriptWrappable { + // WebGLObjects are pre-finalized, and the WebGLRenderingContextBase + // is specifically not. This is done in order to allow WebGLObjects to + // refer back to their owning context in their destructor to delete their + // resources if they are GC'd before the context is. + USING_PRE_FINALIZER(WebGLObject, Dispose); + public: // We can't call virtual functions like deleteObjectImpl in this class's // destructor; doing so results in a pure virtual function call. Further, // making this destructor non-virtual is complicated with respect to // Oilpan tracing. Therefore this destructor is declared virtual, but is // empty, and the code that would have gone into its body is called by - // subclasses via runDestructor(). + // subclasses via Dispose(). ~WebGLObject() override; // deleteObject may not always delete the OpenGL resource. For programs and @@ -84,12 +90,6 @@ const WebGLRenderingContextBase*) const = 0; virtual bool HasObject() const = 0; - // WebGLObjects are eagerly finalized, and the WebGLRenderingContextBase - // is specifically not. This is done in order to allow WebGLObjects to - // refer back to their owning context in their destructor to delete their - // resources if they are GC'd before the context is. - EAGERLY_FINALIZE(); - protected: explicit WebGLObject(WebGLRenderingContextBase*); @@ -111,10 +111,9 @@ virtual gpu::gles2::GLES2Interface* GetAGLInterface() const = 0; - // Used by leaf subclasses to run the destruction sequence -- what would - // be in the destructor of the base class, if it could be. Must be called - // no more than once. - void RunDestructor(); + // Runs the pre-finalization sequence -- what would be in the destructor + // of the base class, if it could be. Must be called no more than once. + void Dispose(); // Indicates to subclasses that the destructor is being run. bool DestructionInProgress() const;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_program.cc b/third_party/blink/renderer/modules/webgl/webgl_program.cc index 026b3e6..48372fe0 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_program.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_program.cc
@@ -46,9 +46,7 @@ SetObject(ctx->ContextGL()->CreateProgram()); } -WebGLProgram::~WebGLProgram() { - RunDestructor(); -} +WebGLProgram::~WebGLProgram() = default; void WebGLProgram::DeleteObjectImpl(gpu::gles2::GLES2Interface* gl) { gl->DeleteProgram(object_);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_query.cc b/third_party/blink/renderer/modules/webgl/webgl_query.cc index ed12cbe..6b533e6e 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_query.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_query.cc
@@ -33,9 +33,7 @@ SetObject(query); } -WebGLQuery::~WebGLQuery() { - RunDestructor(); -} +WebGLQuery::~WebGLQuery() = default; void WebGLQuery::SetTarget(GLenum target) { DCHECK(Object());
diff --git a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc index 09203b8..cecfa2b 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc
@@ -45,9 +45,7 @@ SetObject(rbo); } -WebGLRenderbuffer::~WebGLRenderbuffer() { - RunDestructor(); -} +WebGLRenderbuffer::~WebGLRenderbuffer() = default; void WebGLRenderbuffer::DeleteObjectImpl(gpu::gles2::GLES2Interface* gl) { gl->DeleteRenderbuffers(1, &object_);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_sampler.cc b/third_party/blink/renderer/modules/webgl/webgl_sampler.cc index 962aa16..24d45af 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_sampler.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_sampler.cc
@@ -20,9 +20,7 @@ SetObject(sampler); } -WebGLSampler::~WebGLSampler() { - RunDestructor(); -} +WebGLSampler::~WebGLSampler() = default; void WebGLSampler::DeleteObjectImpl(gpu::gles2::GLES2Interface* gl) { gl->DeleteSamplers(1, &object_);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_shader.cc b/third_party/blink/renderer/modules/webgl/webgl_shader.cc index c9fea1f..50f4417 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_shader.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_shader.cc
@@ -39,9 +39,7 @@ SetObject(ctx->ContextGL()->CreateShader(type)); } -WebGLShader::~WebGLShader() { - RunDestructor(); -} +WebGLShader::~WebGLShader() = default; void WebGLShader::DeleteObjectImpl(gpu::gles2::GLES2Interface* gl) { gl->DeleteShader(object_);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_sync.cc b/third_party/blink/renderer/modules/webgl/webgl_sync.cc index b10625391..01ec4dd 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_sync.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_sync.cc
@@ -28,9 +28,7 @@ ScheduleAllowCacheUpdate(); } -WebGLSync::~WebGLSync() { - RunDestructor(); -} +WebGLSync::~WebGLSync() = default; void WebGLSync::UpdateCache(gpu::gles2::GLES2Interface* gl) { if (sync_status_ == GL_SIGNALED) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_texture.cc b/third_party/blink/renderer/modules/webgl/webgl_texture.cc index 6f2647a2..6b2dc57 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_texture.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_texture.cc
@@ -41,9 +41,7 @@ SetObject(texture); } -WebGLTexture::~WebGLTexture() { - RunDestructor(); -} +WebGLTexture::~WebGLTexture() = default; void WebGLTexture::SetTarget(GLenum target) { if (!Object())
diff --git a/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.cc b/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.cc index cbb0b5e..344dc2d 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_timer_query_ext.cc
@@ -27,9 +27,7 @@ Context()->ContextGL()->GenQueriesEXT(1, &query_id_); } -WebGLTimerQueryEXT::~WebGLTimerQueryEXT() { - RunDestructor(); -} +WebGLTimerQueryEXT::~WebGLTimerQueryEXT() = default; void WebGLTimerQueryEXT::ResetCachedResult() { can_update_availability_ = false;
diff --git a/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc b/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc index 907695b..7203b64 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_transform_feedback.cc
@@ -40,9 +40,7 @@ } } -WebGLTransformFeedback::~WebGLTransformFeedback() { - RunDestructor(); -} +WebGLTransformFeedback::~WebGLTransformFeedback() = default; void WebGLTransformFeedback::DispatchDetached(gpu::gles2::GLES2Interface* gl) { for (WebGLBuffer* buffer : bound_indexed_transform_feedback_buffers_) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc index 6113578..2fec1e6 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_base.cc
@@ -32,9 +32,7 @@ } } -WebGLVertexArrayObjectBase::~WebGLVertexArrayObjectBase() { - RunDestructor(); -} +WebGLVertexArrayObjectBase::~WebGLVertexArrayObjectBase() = default; void WebGLVertexArrayObjectBase::DispatchDetached( gpu::gles2::GLES2Interface* gl) {
diff --git a/third_party/blink/renderer/platform/geometry/double_point.cc b/third_party/blink/renderer/platform/geometry/double_point.cc index 3ffbe33..53e3844 100644 --- a/third_party/blink/renderer/platform/geometry/double_point.cc +++ b/third_party/blink/renderer/platform/geometry/double_point.cc
@@ -5,12 +5,15 @@ #include "third_party/blink/renderer/platform/geometry/double_point.h" #include <algorithm> -#include "third_party/blink/renderer/platform/geometry/float_size.h" -#include "third_party/blink/renderer/platform/geometry/layout_point.h" +#include "third_party/blink/renderer/platform/wtf/math_extras.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { +DoublePoint::operator FloatPoint() const { + return FloatPoint(clampTo<float>(x_), clampTo<float>(y_)); +} + DoublePoint DoublePoint::ExpandedTo(const DoublePoint& other) const { return DoublePoint(std::max(x_, other.x_), std::max(y_, other.y_)); }
diff --git a/third_party/blink/renderer/platform/geometry/double_point.h b/third_party/blink/renderer/platform/geometry/double_point.h index 3b16da26..bb874d1 100644 --- a/third_party/blink/renderer/platform/geometry/double_point.h +++ b/third_party/blink/renderer/platform/geometry/double_point.h
@@ -14,8 +14,6 @@ namespace blink { -class LayoutPoint; - class PLATFORM_EXPORT DoublePoint { DISALLOW_NEW(); @@ -33,7 +31,7 @@ constexpr explicit DoublePoint(const DoubleSize& size) : x_(size.Width()), y_(size.Height()) {} - constexpr explicit operator FloatPoint() const { return FloatPoint(x_, y_); } + explicit operator FloatPoint() const; static constexpr DoublePoint Zero() { return DoublePoint(); } @@ -123,10 +121,6 @@ return IntPoint(clampTo<int>(floor(p.X())), clampTo<int>(floor(p.Y()))); } -constexpr FloatPoint ToFloatPoint(const DoublePoint& a) { - return FloatPoint(a.X(), a.Y()); -} - constexpr DoubleSize ToDoubleSize(const DoublePoint& a) { return DoubleSize(a.X(), a.Y()); }
diff --git a/third_party/blink/renderer/platform/geometry/double_size.h b/third_party/blink/renderer/platform/geometry/double_size.h index b9cfd6a7..b31f181 100644 --- a/third_party/blink/renderer/platform/geometry/double_size.h +++ b/third_party/blink/renderer/platform/geometry/double_size.h
@@ -104,10 +104,6 @@ return IntSize(clampTo<int>(ceil(p.Width())), clampTo<int>(ceil(p.Height()))); } -constexpr FloatSize ToFloatSize(const DoubleSize& p) { - return FloatSize(p.Width(), p.Height()); -} - PLATFORM_EXPORT std::ostream& operator<<(std::ostream&, const DoubleSize&); } // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc index 6b887046..76bdeca 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -69,11 +69,14 @@ snapshot_state_(kInitialSnapshotState), resource_host_(nullptr), random_generator_((uint32_t)base::RandUint64()), - bernoulli_distribution_(kRasterMetricProbability) { + bernoulli_distribution_(kRasterMetricProbability), + last_recording_(nullptr) { // Used by browser tests to detect the use of a Canvas2DLayerBridge. TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation", TRACE_EVENT_SCOPE_GLOBAL); - StartRecording(); + if (is_deferral_enabled_) { + StartRecording(); + } // Clear the background transparent or opaque. Similar code at // CanvasResourceProvider::Clear(). if (IsValid()) { @@ -546,8 +549,11 @@ { // Make a new scope so that PaintRecord gets deleted and that gets timed cc::PaintCanvas* canvas = ResourceProvider()->Canvas(); - sk_sp<PaintRecord> recording = recorder_->finishRecordingAsPicture(); - canvas->drawPicture(recording); + last_recording_ = recorder_->finishRecordingAsPicture(); + canvas->drawPicture(last_recording_); + if (!resource_host_ || !resource_host_->IsPrinting()) { + last_recording_ = nullptr; + } ResourceProvider()->FlushSkia(); }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h index 0eccc46..b9231df 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h +++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
@@ -169,6 +169,9 @@ CanvasResourceProvider* ResourceProvider() const; void FlushRecording(); + PaintRecorder* getRecorder() { return recorder_.get(); } + sk_sp<cc::PaintRecord> getLastRecord() { return last_recording_; } + private: friend class Canvas2DLayerBridgeTest; friend class CanvasRenderingContext2DTest; @@ -230,6 +233,8 @@ std::bernoulli_distribution bernoulli_distribution_; Deque<RasterTimer> pending_raster_timers_; + sk_sp<cc::PaintRecord> last_recording_; + base::WeakPtrFactory<Canvas2DLayerBridge> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(Canvas2DLayerBridge);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc index dbb7f45..efd53ab 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -685,14 +685,13 @@ is_overlay_candidate_(is_overlay_candidate), size_(size), is_origin_top_left_(is_origin_top_left), - texture_target_( - is_overlay_candidate_ - ? gpu::GetBufferTextureTarget( - gfx::BufferUsage::SCANOUT, - BufferFormat(ColorParams().TransferableResourceFormat()), - context_provider_wrapper_->ContextProvider() - ->GetCapabilities()) - : GL_TEXTURE_2D), + texture_target_(is_overlay_candidate_ + ? gpu::GetBufferTextureTarget( + gfx::BufferUsage::SCANOUT, + ColorParams().GetBufferFormat(), + context_provider_wrapper_->ContextProvider() + ->GetCapabilities()) + : GL_TEXTURE_2D), owning_thread_id_(Thread::Current()->ThreadId()), owning_thread_task_runner_(Thread::Current()->GetTaskRunner()) { if (!context_provider_wrapper_) @@ -709,7 +708,7 @@ flags |= gpu::SHARED_IMAGE_USAGE_SCANOUT; auto shared_image_mailbox = shared_image_interface->CreateSharedImage( - ColorParams().TransferableResourceFormat(), gfx::Size(size), + viz::GetResourceFormat(ColorParams().GetBufferFormat()), gfx::Size(size), ColorParams().GetStorageGfxColorSpace(), flags); // Wait for the mailbox to be ready to be used. @@ -830,18 +829,12 @@ // Initialize GLFilter first so that the generated sync token includes this // update. SetGLFilterIfNeeded(); - GetSyncToken(); // TODO(khushalsagar): This is for consistency with MailboxTextureHolder // transfer path. Its unclear why the verification can not be deferred until // the resource needs to be transferred cross-process. - if (!owning_thread_data().sync_token.verified_flush()) { - int8_t* token_data = owning_thread_data().sync_token.GetData(); - auto* gl = ContextGL(); - gl->ShallowFlushCHROMIUM(); - gl->VerifySyncTokensCHROMIUM(&token_data, 1); - owning_thread_data().sync_token.SetVerifyFlush(); - } + owning_thread_data().mailbox_sync_mode = kVerifiedSyncToken; + GetSyncToken(); } scoped_refptr<StaticBitmapImage> CanvasResourceSharedImage::Bitmap() { @@ -880,6 +873,12 @@ SkImageInfo image_info = SkImageInfo::Make( Size().Width(), Size().Height(), ColorParams().GetSkColorType(), ColorParams().GetSkAlphaType(), ColorParams().GetSkColorSpace()); + + // If its cross thread, then the sync token was already verified. If not, then + // it doesn't need to be verified. + if (!is_cross_thread()) + owning_thread_data().mailbox_sync_mode = kUnverifiedSyncToken; + image = AcceleratedStaticBitmapImage::CreateFromCanvasMailbox( mailbox(), is_cross_thread() ? sync_token() : GetSyncToken(), texture_id_for_image, image_info, texture_target_, @@ -920,20 +919,34 @@ } const gpu::SyncToken CanvasResourceSharedImage::GetSyncToken() { - if (mailbox_needs_new_sync_token()) { - DCHECK(!is_cross_thread()); + if (is_cross_thread()) { + // Sync token should be generated at Transfer time, which must always be + // called before cross-thread usage. And since we don't allow writes on + // another thread, the sync token generated at Transfer time shouldn't + // have been invalidated. + DCHECK(!mailbox_needs_new_sync_token()); + DCHECK(sync_token().verified_flush()); + return sync_token(); + } + + if (mailbox_needs_new_sync_token()) { auto* gl = ContextGL(); DCHECK(gl); // caller should already have early exited if !gl. - if (owning_thread_data().mailbox_sync_mode == kVerifiedSyncToken) { - gl->GenSyncTokenCHROMIUM(owning_thread_data().sync_token.GetData()); - DCHECK(owning_thread_data().sync_token.verified_flush()); - } else { - gl->GenUnverifiedSyncTokenCHROMIUM( - owning_thread_data().sync_token.GetData()); - } + gl->GenUnverifiedSyncTokenCHROMIUM( + owning_thread_data().sync_token.GetData()); owning_thread_data().mailbox_needs_new_sync_token = false; } + + if (owning_thread_data().mailbox_sync_mode == kVerifiedSyncToken && + !owning_thread_data().sync_token.verified_flush()) { + int8_t* token_data = owning_thread_data().sync_token.GetData(); + auto* gl = ContextGL(); + gl->ShallowFlushCHROMIUM(); + gl->VerifySyncTokensCHROMIUM(&token_data, 1); + owning_thread_data().sync_token.SetVerifyFlush(); + } + return sync_token(); }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_host.h b/third_party/blink/renderer/platform/graphics/canvas_resource_host.h index 239e25f..9c1e69a6 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_host.h +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_host.h
@@ -40,6 +40,8 @@ virtual void DiscardResourceProvider(); + virtual bool IsPrinting() const { return false; } + private: std::unique_ptr<CanvasResourceProvider> resource_provider_; };
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc index b7d88c0..4d5d2d37f 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -563,30 +563,30 @@ if (IsGpuContextLost()) return; - // If |resource_| is still being used by the compositor we need to create - // a new resource or reuse a previously recycled one. This class holds one - // reference so we check if there is more than one. - if (!resource_->HasOneRef() || resource()->is_lost()) { + if (DoCopyOnWrite()) { DCHECK(!current_resource_has_write_access_) << "Write access must be released before sharing the resource"; - auto* old_resource = - static_cast<CanvasResourceSharedImage*>(resource_.get()); + auto old_resource = std::move(resource_); + auto* old_resource_shared_image = + static_cast<CanvasResourceSharedImage*>(old_resource.get()); resource_ = NewOrRecycledResource(); + DCHECK(resource_); + EnsureWriteAccess(); if (surface_) { // Take read access to the outgoing resource for the skia copy below. - if (!old_resource->has_read_access()) { + if (!old_resource_shared_image->has_read_access()) { ContextGL()->BeginSharedImageAccessDirectCHROMIUM( - old_resource->GetTextureIdForBackendTexture(), + old_resource_shared_image->GetTextureIdForBackendTexture(), GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM); } surface_->replaceBackendTexture(CreateGrTextureForResource(), GetGrSurfaceOrigin()); surface_->flush(); - if (!old_resource->has_read_access()) { + if (!old_resource_shared_image->has_read_access()) { ContextGL()->EndSharedImageAccessDirectCHROMIUM( - old_resource->GetTextureIdForBackendTexture()); + old_resource_shared_image->GetTextureIdForBackendTexture()); } } } @@ -595,6 +595,24 @@ resource()->WillDraw(); } + bool DoCopyOnWrite() { + // If the resource was lost, we can not use it for writes again. + if (resource()->is_lost()) + return true; + + // We have the only ref to the resource which implies there are no active + // readers. + if (resource_->HasOneRef()) + return false; + + // Its possible to have deferred work in skia which uses this resource. Try + // flushing once to see if that releases the read refs. We can avoid a copy + // by queuing this work before writing to this resource. + surface_->flush(); + + return !resource_->HasOneRef(); + } + sk_sp<SkSurface> CreateSkSurface() const override { TRACE_EVENT0("blink", "CanvasResourceProviderSharedImage::CreateSkSurface"); if (IsGpuContextLost())
diff --git a/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc b/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc index 7cbf81a..243b9a1 100644 --- a/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc +++ b/third_party/blink/renderer/platform/graphics/compositor_filter_operations.cc
@@ -117,7 +117,8 @@ } String CompositorFilterOperations::ToString() const { - return filter_operations_.ToString().c_str(); + return String(filter_operations_.ToString().c_str()) + " at " + + reference_box_.ToString(); } } // namespace blink
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h b/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h index 0a2ae5a9..3622f7f6 100644 --- a/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h +++ b/third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h
@@ -111,10 +111,6 @@ void AddObserver(WebMediaStreamObserver*); void RemoveObserver(WebMediaStreamObserver*); - // |m_extraData| may hold pointers to GC objects, and it may touch them in - // destruction. So this class is eagerly finalized to finalize |m_extraData| - // promptly. - EAGERLY_FINALIZE(); void Trace(blink::Visitor*); private:
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_source.cc b/third_party/blink/renderer/platform/mediastream/media_stream_source.cc index 639c7b4..32f2f5a 100644 --- a/third_party/blink/renderer/platform/mediastream/media_stream_source.cc +++ b/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
@@ -166,6 +166,12 @@ visitor->Trace(observers_); } +void MediaStreamSource::Dispose() { + audio_consumers_.clear(); + platform_source_.reset(); + constraints_.Reset(); +} + STATIC_ASSERT_ENUM(WebMediaStreamSource::kTypeAudio, MediaStreamSource::kTypeAudio); STATIC_ASSERT_ENUM(WebMediaStreamSource::kTypeVideo,
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_source.h b/third_party/blink/renderer/platform/mediastream/media_stream_source.h index 7cbeae6..fecbcc2 100644 --- a/third_party/blink/renderer/platform/mediastream/media_stream_source.h +++ b/third_party/blink/renderer/platform/mediastream/media_stream_source.h
@@ -51,6 +51,8 @@ class PLATFORM_EXPORT MediaStreamSource final : public GarbageCollectedFinalized<MediaStreamSource> { + USING_PRE_FINALIZER(MediaStreamSource, Dispose); + public: class PLATFORM_EXPORT Observer : public GarbageCollectedMixin { public: @@ -119,12 +121,10 @@ return audio_consumers_; } - // |m_extraData| may hold pointers to GC objects, and it may touch them in - // destruction. So this class is eagerly finalized to finalize |m_extraData| - // promptly. - EAGERLY_FINALIZE(); void Trace(blink::Visitor*); + void Dispose(); + private: String id_; StreamType type_;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 3e1af82..4af60a1 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -477,7 +477,7 @@ }, { name: "DiscardInputToMovingIframes", - status: "experimental", + status: "stable", }, { name: "DisplayCutoutAPI",
diff --git a/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc b/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc index 9c366e27..02127048 100644 --- a/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc +++ b/third_party/blink/renderer/platform/scheduler/common/dummy_schedulers.cc
@@ -33,6 +33,7 @@ bool IsFrameVisible() const override { return true; } bool IsPageVisible() const override { return true; } void SetPaused(bool) override {} + void SetShouldReportPostedTasksWhenDisabled(bool) override {} void SetCrossOrigin(bool) override {} bool IsCrossOrigin() const override { return false; } void SetIsAdFrame() override {}
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc index e281441..163238f 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -780,6 +780,17 @@ UpdatePolicy(); } +void FrameSchedulerImpl::SetShouldReportPostedTasksWhenDisabled( + bool should_report) { + // Forward this to all the task queues associated with this frame. + for (const auto& task_queue_and_voter : + frame_task_queue_controller_->GetAllTaskQueuesAndVoters()) { + auto* task_queue = task_queue_and_voter.first; + if (task_queue->CanBeFrozen()) + task_queue->SetShouldReportPostedTasksWhenDisabled(should_report); + } +} + void FrameSchedulerImpl::SetPageFrozenForTracing(bool frozen) { page_frozen_for_tracing_ = frozen; }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h index 30514c8..fbc2b9ed 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
@@ -86,6 +86,7 @@ bool IsAudioPlaying() const; void SetPaused(bool frame_paused) override; + void SetShouldReportPostedTasksWhenDisabled(bool should_report) override; void SetCrossOrigin(bool cross_origin) override; bool IsCrossOrigin() const override;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc index 5d122d3..b334baf8 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
@@ -257,8 +257,10 @@ if (is_frozen_ == frozen) return; is_frozen_ = frozen; - for (FrameSchedulerImpl* frame_scheduler : frame_schedulers_) + for (FrameSchedulerImpl* frame_scheduler : frame_schedulers_) { frame_scheduler->SetPageFrozenForTracing(frozen); + frame_scheduler->SetShouldReportPostedTasksWhenDisabled(frozen); + } if (notification_policy == PageSchedulerImpl::NotificationPolicy::kNotifyFrames) NotifyFrames();
diff --git a/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h index c7c7ece..a32a0d2 100644 --- a/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h +++ b/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h
@@ -77,6 +77,10 @@ // allowed to run on a suspended frame. virtual void SetPaused(bool) = 0; + // Sets whether or not this frame should report (via tracing) tasks that are + // posted to it. + virtual void SetShouldReportPostedTasksWhenDisabled(bool) = 0; + // Set whether this frame is cross origin w.r.t. the top level frame. Cross // origin frames may use a different scheduling policy from same origin // frames.
diff --git a/third_party/blink/renderer/platform/speech/platform_speech_synthesizer.cc b/third_party/blink/renderer/platform/speech/platform_speech_synthesizer.cc index 630cb12b..105b406 100644 --- a/third_party/blink/renderer/platform/speech/platform_speech_synthesizer.cc +++ b/third_party/blink/renderer/platform/speech/platform_speech_synthesizer.cc
@@ -113,4 +113,8 @@ visitor->Trace(web_speech_synthesizer_client_); } +void PlatformSpeechSynthesizer::Dispose() { + web_speech_synthesizer_.reset(); +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/speech/platform_speech_synthesizer.h b/third_party/blink/renderer/platform/speech/platform_speech_synthesizer.h index 0739d16..4b4821ac 100644 --- a/third_party/blink/renderer/platform/speech/platform_speech_synthesizer.h +++ b/third_party/blink/renderer/platform/speech/platform_speech_synthesizer.h
@@ -62,6 +62,18 @@ class PLATFORM_EXPORT PlatformSpeechSynthesizer : public GarbageCollectedFinalized<PlatformSpeechSynthesizer> { + // Pre-finalization is required to promptly release the owned + // WebSpeechSynthesizer. + // + // If not and delayed until lazily swept, web_speech_synthesizer_client_ may + // end up being lazily swept first (i.e., before this + // PlatformSpeechSynthesizer), leaving web_speech_synthesizer_ with a + // dangling pointer to a finalized object -- WebSpeechSynthesizer embedder + // implementations calling notification methods in the other directions by + // way of web_speech_synthesizer_client_. Eagerly releasing + // WebSpeechSynthesizer prevents such unsafe accesses. + USING_PRE_FINALIZER(PlatformSpeechSynthesizer, Dispose); + public: static PlatformSpeechSynthesizer* Create(PlatformSpeechSynthesizerClient*); @@ -81,19 +93,10 @@ void SetVoiceList(Vector<scoped_refptr<PlatformSpeechSynthesisVoice>>&); - // Eager finalization is required to promptly release the owned - // WebSpeechSynthesizer. - // - // If not and delayed until lazily swept, m_webSpeechSynthesizerClient may end - // up being lazily swept first (i.e., before this PlatformSpeechSynthesizer), - // leaving m_webSpeechSynthesizer with a dangling pointer to a finalized - // object -- WebSpeechSynthesizer embedder implementations calling - // notification methods in the other directions by way of - // m_webSpeechSynthesizerClient. Eagerly releasing WebSpeechSynthesizer - // prevents such unsafe accesses. - EAGERLY_FINALIZE(); virtual void Trace(blink::Visitor*); + void Dispose(); + protected: virtual void InitializeVoiceList();
diff --git a/third_party/blink/tools/blinkpy/third_party/README.chromium b/third_party/blink/tools/blinkpy/third_party/README.chromium index 773092d..f09295f 100644 --- a/third_party/blink/tools/blinkpy/third_party/README.chromium +++ b/third_party/blink/tools/blinkpy/third_party/README.chromium
@@ -32,7 +32,7 @@ Name: web-platform-tests - Test Suites for Web Platform specifications Short Name: wpt URL: https://github.com/web-platform-tests/wpt/ -Version: 7edf9eabfae3550a4dd2a48625e68b02a734de15 +Version: 3fb0150bb0a53b5a6630e8eda7f43bf75d8a6bbe License: LICENSES FOR W3C TEST SUITES (http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html) License File: wpt/wpt/LICENSE.md Security Critical: no
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh index ffc40e2..e49dd713 100755 --- a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh +++ b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
@@ -9,7 +9,7 @@ TARGET_DIR=$DIR/wpt REMOTE_REPO="https://github.com/web-platform-tests/wpt.git" -WPT_HEAD=7edf9eabfae3550a4dd2a48625e68b02a734de15 +WPT_HEAD=3fb0150bb0a53b5a6630e8eda7f43bf75d8a6bbe function clone { # Remove existing repo if already exists.
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py index 5b156b1..834e5c5 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py
@@ -146,6 +146,13 @@ return [] +def check_file_type(repo_root, path): + # type: (str, str) -> List[rules.Error] + if os.path.islink(path): + return [rules.FileType.error(path, (path, "symlink"))] + return [] + + def check_worker_collision(repo_root, path): # type: (str, str) -> List[rules.Error] endings = [(".any.html", ".any.js"), @@ -913,7 +920,8 @@ logger.info(line) return sum(itervalues(error_count)) -path_lints = [check_path_length, check_worker_collision, check_ahem_copy, check_gitignore_file] +path_lints = [check_file_type, check_path_length, check_worker_collision, check_ahem_copy, + check_gitignore_file] all_paths_lints = [check_css_globally_unique] file_lints = [check_regexp_line, check_parsed, check_python_ast, check_script_metadata]
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/rules.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/rules.py index 685bac34..9b78f349 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/rules.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/rules.py
@@ -57,6 +57,11 @@ description = "/%s longer than maximum path length (%d > 150)" +class FileType(Rule): + name = "FILE TYPE" + description = "/%s is an unsupported file type (%s)" + + class WorkerCollision(Rule): name = "WORKER COLLISION" description = ("path ends with %s which collides with generated tests "
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py index b5ebeed6..616f95e 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/manifest.py
@@ -2,7 +2,7 @@ import json import os from collections import MutableMapping, defaultdict -from six import iteritems, iterkeys, itervalues, string_types +from six import iteritems, iterkeys, itervalues, string_types, binary_type, text_type from . import vcs from .item import (ConformanceCheckerTest, ManifestItem, ManualTest, RefTest, RefTestNode, Stub, @@ -323,7 +323,7 @@ for source_file, update in tree: if not update: - assert isinstance(source_file, (bytes, str)) + assert isinstance(source_file, (binary_type, text_type)) rel_path = source_file # type: Text seen_files.add(rel_path) assert rel_path in path_hash
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py index c810be12..d87e804c 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/manifest/vcs.py
@@ -61,24 +61,11 @@ # type: () -> Set[bytes] """get a set of files which have changed between HEAD and working copy""" assert self.git is not None - - changes = set() # type: Set[bytes] - - cmd = [b"status", b"-z", b"--ignore-submodules=all"] - data = self.git(*cmd) # type: bytes - - in_rename = False - for line in data.split(b"\0")[:-1]: - if in_rename: - changes.add(line) - in_rename = False - else: - status = line[:2] - if b"R" in status or b"C" in status: - in_rename = True - changes.add(line[3:]) - - return changes + # note that git runs the command with tests_root as the cwd, which may + # not be the root of the git repo (e.g., within a browser repo) + cmd = [b"diff-index", b"--relative", b"--no-renames", b"--name-only", b"-z", b"HEAD"] + data = self.git(*cmd) + return set(data.split(b"\0")) def hash_cache(self): # type: () -> Dict[bytes, Optional[bytes]] @@ -90,7 +77,9 @@ if self.git is None: return hash_cache - cmd = [b"ls-tree", b"-r", b"-z", b"HEAD"] + # note that git runs the command with tests_root as the cwd, which may + # not be the root of the git repo (e.g., within a browser repo) + cmd = ["ls-tree", "-r", "-z", "HEAD"] local_changes = self._local_changes() for result in self.git(*cmd).split(b"\0")[:-1]: # type: bytes data, rel_path = result.rsplit(b"\t", 1) @@ -168,7 +157,10 @@ try: if not rebuild: with open(self.path, 'r') as f: - data = json.load(f) + try: + data = json.load(f) + except ValueError: + pass data = self.check_valid(data) except IOError: pass
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py index 1fc61747..77675dbe 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/serve/serve.py
@@ -8,6 +8,7 @@ import logging import os import platform +import signal import socket import sys import threading @@ -574,13 +575,11 @@ class WebSocketDaemon(object): - def __init__(self, host, port, doc_root, handlers_root, log_level, bind_address, - ssl_config): + def __init__(self, host, port, doc_root, handlers_root, bind_address, ssl_config): self.host = host cmd_args = ["-p", port, "-d", doc_root, - "-w", handlers_root, - "--log-level", log_level] + "-w", handlers_root] if ssl_config is not None: # This is usually done through pywebsocket.main, however we're @@ -604,17 +603,6 @@ opts, args = pywebsocket._parse_args_and_config(cmd_args) opts.cgi_directories = [] opts.is_executable_method = None - - # Logging needs to be configured both before and after reloading, - # because some modules store loggers as global variables. - pywebsocket._configure_logging(opts) - # Ensure that when we start this in a new process we have the global - # lock in the logging module unlocked. - reload_module(logging) - release_mozlog_lock() - pywebsocket._configure_logging(opts) - # DO NOT LOG BEFORE THIS LINE. - self.server = pywebsocket.WebSocketServer(opts) ports = [item[0].getsockname()[1] for item in self.server._sockets] assert all(item == ports[0] for item in ports) @@ -661,21 +649,27 @@ def start_ws_server(host, port, paths, routes, bind_address, config, **kwargs): + # Ensure that when we start this in a new process we have the global lock + # in the logging module unlocked + reload_module(logging) + release_mozlog_lock() return WebSocketDaemon(host, str(port), repo_root, config.paths["ws_doc_root"], - config.log_level.lower(), bind_address, ssl_config=None) def start_wss_server(host, port, paths, routes, bind_address, config, **kwargs): + # Ensure that when we start this in a new process we have the global lock + # in the logging module unlocked + reload_module(logging) + release_mozlog_lock() return WebSocketDaemon(host, str(port), repo_root, config.paths["ws_doc_root"], - config.log_level.lower(), bind_address, config.ssl_config) @@ -841,11 +835,19 @@ def run(**kwargs): + received_signal = threading.Event() + with build_config(os.path.join(repo_root, "config.json"), **kwargs) as config: global logger logger = config.logger set_logger(logger) + # Configure the root logger to cover third-party libraries. + logging.getLogger().setLevel(config.log_level) + + def handle_signal(signum, frame): + logger.debug("Received signal %s. Shutting down.", signum) + received_signal.set() bind_address = config["bind_address"] @@ -868,20 +870,19 @@ with stash.StashServer(stash_address, authkey=str(uuid.uuid4())): servers = start(config, build_routes(config["aliases"]), **kwargs) + signal.signal(signal.SIGTERM, handle_signal) + signal.signal(signal.SIGINT, handle_signal) - try: - while all(item.is_alive() for item in iter_procs(servers)): - for item in iter_procs(servers): - item.join(1) - exited = [item for item in iter_procs(servers) if not item.is_alive()] - subject = "subprocess" if len(exited) == 1 else "subprocesses" - - logger.info("%s %s exited:" % (len(exited), subject)) - + while all(item.is_alive() for item in iter_procs(servers)) and not received_signal.is_set(): for item in iter_procs(servers): - logger.info("Status of %s:\t%s" % (item.name, "running" if item.is_alive() else "not running")) - except KeyboardInterrupt: - logger.info("Shutting down") + item.join(1) + exited = [item for item in iter_procs(servers) if not item.is_alive()] + subject = "subprocess" if len(exited) == 1 else "subprocesses" + + logger.info("%s %s exited:" % (len(exited), subject)) + + for item in iter_procs(servers): + logger.info("Status of %s:\t%s" % (item.name, "running" if item.is_alive() else "not running")) def main():
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py index 52ebc95..0bddd7b 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/webdriver/webdriver/client.py
@@ -218,7 +218,12 @@ ``ActionSequence.dict``. """ body = {"actions": [] if actions is None else actions} - return self.session.send_session_command("POST", "actions", body) + actions = self.session.send_session_command("POST", "actions", body) + """WebDriver window should be set to the top level window when wptrunner + processes the next event. + """ + self.session.switch_frame(None) + return actions @command def release(self): @@ -308,8 +313,11 @@ self.session = session @command - def css(self, selector, all=True): - return self._find_element("css selector", selector, all) + def css(self, element_selector, all=True, frame="window"): + if (frame != "window"): + self.session.switch_frame(frame) + elements = self._find_element("css selector", element_selector, all) + return elements def _find_element(self, strategy, selector, all): route = "elements" if all else "element" @@ -413,7 +421,7 @@ if self.session_id is not None: return - body = {} + body = {"capabilities": {}} if self.requested_capabilities is not None: body["capabilities"] = self.requested_capabilities
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py index 1b883b9..23e91a7 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
@@ -3,6 +3,7 @@ import re import shutil import stat +import errno import subprocess import tempfile import urlparse @@ -17,6 +18,24 @@ uname = platform.uname() +def _get_fileversion(binary, logger=None): + command = "(Get-Item '%s').VersionInfo.FileVersion" % binary.replace("'", "''") + try: + return call("powershell.exe", command).strip() + except (subprocess.CalledProcessError, OSError): + if logger is not None: + logger.warning("Failed to call %s in PowerShell" % command) + return None + + +def handle_remove_readonly(func, path, exc): + excvalue = exc[1] + if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES: + os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 0777 + func(path) + else: + raise + class Browser(object): __metaclass__ = ABCMeta @@ -108,7 +127,7 @@ ("linux", "x86"): "linux", ("linux", "x86_64"): "linux64", ("win", "x86"): "win", - ("win", "x86_64"): "win64", + ("win", "AMD64"): "win64", ("macos", "x86_64"): "osx", } os_key = (self.platform, uname[4]) @@ -149,7 +168,7 @@ installer_path = os.path.join(dest, filename) - with open(installer_path, "w") as f: + with open(installer_path, "wb") as f: f.write(resp.content) try: @@ -197,6 +216,14 @@ path = os.path.join(venv_path, "browsers", channel) binary = self.find_binary_path(path, channel) + if not binary and self.platform == "win": + winpaths = [os.path.expandvars("$SYSTEMDRIVE\\Program Files\\Mozilla Firefox"), + os.path.expandvars("$SYSTEMDRIVE\\Program Files (x86)\\Mozilla Firefox")] + for winpath in winpaths: + binary = self.find_binary_path(winpath, channel) + if binary is not None: + break + if not binary and self.platform == "macos": macpaths = ["/Applications/Firefox Nightly.app/Contents/MacOS", os.path.expanduser("~/Applications/Firefox Nightly.app/Contents/MacOS"), @@ -215,7 +242,7 @@ path = find_executable("certutil") if path is None: return None - if os.path.splitdrive(path)[1].split(os.path.sep) == ["", "Windows", "system32", "certutil.exe"]: + if os.path.splitdrive(os.path.normcase(path))[1].split(os.path.sep) == ["", "windows", "system32", "certutil.exe"]: return None return path @@ -418,7 +445,8 @@ return "/usr/bin/google-chrome" if uname[0] == "Darwin": return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" - # TODO Windows? + if uname[0] == "Windows": + return os.path.expandvars("$SYSTEMDRIVE\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe") self.logger.warning("Unable to find the browser binary.") return None @@ -521,19 +549,19 @@ def version(self, binary=None, webdriver_binary=None): binary = binary or self.binary - if uname[0] != "Windows": - try: - version_string = call(binary, "--version").strip() - except subprocess.CalledProcessError: - self.logger.warning("Failed to call %s" % binary) - return None - m = re.match(r"(?:Google Chrome|Chromium) (.*)", version_string) - if not m: - self.logger.warning("Failed to extract version from: %s" % version_string) - return None - return m.group(1) - self.logger.warning("Unable to extract version from binary on Windows.") - return None + if uname[0] == "Windows": + return _get_fileversion(binary, self.logger) + + try: + version_string = call(binary, "--version").strip() + except subprocess.CalledProcessError: + self.logger.warning("Failed to call %s" % binary) + return None + m = re.match(r"(?:Google Chrome|Chromium) (.*)", version_string) + if not m: + self.logger.warning("Failed to extract version from: %s" % version_string) + return None + return m.group(1) class ChromeAndroid(Browser): @@ -644,6 +672,7 @@ "Darwin": "macos" }.get(uname[0]) product = "edgechromium" + edgedriver_name = "msedgedriver" requirements = "requirements_edge_chromium.txt" def install(self, dest=None, channel=None): @@ -678,22 +707,40 @@ return find_executable("msedgedriver") def install_webdriver(self, dest=None, channel=None, browser_binary=None): - if self.platform == "win": - raise ValueError("Only Windows platform is currently supported") + if self.platform != "win" and self.platform != "macos": + raise ValueError("Only Windows and Mac platforms are currently supported") if dest is None: dest = os.pwd - platform = "x64" if uname[4] == "x86_64" else "x86" - url = "https://az813057.vo.msecnd.net/webdriver/msedgedriver_%s/msedgedriver.exe" % platform + if channel is None: + version_url = "https://msedgedriver.azureedge.net/LATEST_DEV" + else: + version_url = "https://msedgedriver.azureedge.net/LATEST_%s" % channel.upper() + version = get(version_url).text.strip() + + if self.platform == "macos": + bits = "mac64" + edgedriver_path = os.path.join(dest, self.edgedriver_name) + else: + bits = "win64" if uname[4] == "x86_64" else "win32" + edgedriver_path = os.path.join(dest, "%s.exe" % self.edgedriver_name) + url = "https://msedgedriver.azureedge.net/%s/edgedriver_%s.zip" % (version, bits) + + # cleanup existing Edge driver files to avoid access_denied errors when unzipping + if os.path.isfile(edgedriver_path): + # remove read-only attribute + os.chmod(edgedriver_path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 0777 + os.remove(edgedriver_path) + driver_notes_path = os.path.join(dest, "Driver_notes") + if os.path.isdir(driver_notes_path): + shutil.rmtree(driver_notes_path, ignore_errors=False, onerror=handle_remove_readonly) self.logger.info("Downloading MSEdgeDriver from %s" % url) - resp = get(url) - installer_path = os.path.join(dest, "msedgedriver.exe") - with open(installer_path, "wb") as f: - f.write(resp.content) - - return find_executable("msedgedriver", dest) + unzip(get(url).raw, dest) + if os.path.isfile(edgedriver_path): + self.logger.info("Successfully downloaded MSEdgeDriver to %s" % edgedriver_path) + return find_executable(self.edgedriver_name, dest) def version(self, binary=None, webdriver_binary=None): if binary is None: @@ -711,12 +758,7 @@ return m.group(1) else: if binary is not None: - command = "(Get-Item '%s').VersionInfo.FileVersion" % binary - try: - return call("powershell.exe", command).strip() - except (subprocess.CalledProcessError, OSError): - self.logger.warning("Failed to call %s in PowerShell" % command) - return None + return _get_fileversion(binary, self.logger) self.logger.warning("Failed to find Edge binary.") return None
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py index be6bf81..b107752 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/install.py
@@ -6,6 +6,7 @@ latest_channels = { 'firefox': 'nightly', 'chrome': 'dev', + 'edgechromium': 'dev', 'safari': 'preview', 'servo': 'nightly' } @@ -18,6 +19,7 @@ 'dev': latest_channels, 'preview': latest_channels, 'experimental': latest_channels, + 'canary': 'canary', }
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py index 0b306aee..282dd29 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/run.py
@@ -338,15 +338,23 @@ browser_cls = browser.EdgeChromium def setup_kwargs(self, kwargs): + browser_channel = kwargs["browser_channel"] + if kwargs["binary"] is None: + binary = self.browser.find_binary(channel=browser_channel) + if binary: + kwargs["binary"] = self.browser.find_binary() + else: + raise WptrunError("Unable to locate Edge binary") if kwargs["webdriver_binary"] is None: webdriver_binary = self.browser.find_webdriver() - if webdriver_binary is None: + # Install browser if none are found or if it's found in venv path + if webdriver_binary is None or webdriver_binary in self.venv.bin_path: install = self.prompt_install("msedgedriver") if install: logger.info("Downloading msedgedriver") - webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path) + webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path, channel=browser_channel) else: logger.info("Using webdriver binary %s" % webdriver_binary) @@ -354,6 +362,9 @@ kwargs["webdriver_binary"] = webdriver_binary else: raise WptrunError("Unable to locate or install msedgedriver binary") + if browser_channel == "dev": + logger.info("Automatically turning on experimental features for Edge Dev") + kwargs["binary_args"].append("--enable-experimental-web-platform-features") class Edge(BrowserSetup): @@ -576,7 +587,8 @@ kwargs["browser_channel"] = channel else: logger.info("Valid channels for %s not known; using argument unmodified" % kwargs["product"]) - del kwargs["channel"] + kwargs["browser_channel"] = kwargs["channel"] + del kwargs["channel"] if install_browser: logger.info("Installing browser")
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/virtualenv.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/virtualenv.py index e0f51d5..a894c9c 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/virtualenv.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/virtualenv.py
@@ -34,6 +34,11 @@ def exists(self): return os.path.isdir(self.path) + @property + def broken_link(self): + python_link = os.path.join(self.path, ".Python") + return os.path.lexists(python_link) and not os.path.exists(python_link) + def create(self): if os.path.exists(self.path): shutil.rmtree(self.path) @@ -88,7 +93,7 @@ execfile(path, {"__file__": path}) # noqa: F821 def start(self): - if not self.exists: + if not self.exists or self.broken_link: self.create() self.activate()
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/pipes.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/pipes.py index d1eb724..ceb34cc 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/pipes.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/pipes.py
@@ -342,23 +342,25 @@ A dictionary of parts of the request URL. Valid keys are 'server, 'scheme', 'host', 'hostname', 'port', 'path' and 'query'. 'server' is scheme://host:port, 'host' is hostname:port, and query - includes the leading '?', but other delimiters are omitted. + includes the leading '?', but other delimiters are omitted. headers A dictionary of HTTP headers in the request. header_or_default(header, default) The value of an HTTP header, or a default value if it is absent. - For example: + For example:: {{header_or_default(X-Test, test-header-absent)}} + GET A dictionary of query parameters supplied with the request. uuid() A pesudo-random UUID suitable for usage with stash file_hash(algorithm, filepath) The cryptographic hash of a file. Supported algorithms: md5, sha1, - sha224, sha256, sha384, and sha512. For example: + sha224, sha256, sha384, and sha512. For example:: {{file_hash(md5, dom/interfaces.html)}} + fs_path(filepath) The absolute path to a file inside the wpt document root @@ -369,16 +371,15 @@ {{domains[www]}} => www.localhost {{ports[http][1]}} => 81 + It is also possible to assign a value to a variable name, which must start + with the $ character, using the ":" syntax e.g.:: - It is also possible to assign a value to a variable name, which must start with - the $ character, using the ":" syntax e.g. - - {{$id:uuid()}} + {{$id:uuid()}} Later substitutions in the same file may then refer to the variable - by name e.g. + by name e.g.:: - {{$id}} + {{$id}} """ content = resolve_content(response)
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/response.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/response.py index 6a241039..3a60c2ba 100644 --- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/response.py +++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/response.py
@@ -179,11 +179,13 @@ If any part of the content is a function, this will be called and the resulting value (if any) returned. - :param read_file: - boolean controlling the behaviour when content - is a file handle. When set to False the handle will be returned directly - allowing the file to be passed to the output in small chunks. When set to - True, the entire content of the file will be returned as a string facilitating - non-streaming operations like template substitution. + :param read_file: boolean controlling the behaviour when content is a + file handle. When set to False the handle will be + returned directly allowing the file to be passed to + the output in small chunks. When set to True, the + entire content of the file will be returned as a + string facilitating non-streaming operations like + template substitution. """ if isinstance(self.content, binary_type): yield self.content
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer b/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer index 362c2640..c0ccb3ca 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer +++ b/third_party/blink/web_tests/FlagExpectations/enable-features=UseSkiaRenderer
@@ -3,3 +3,5 @@ crbug.com/954328 css3/filters/effect-blur-hw.html [ Failure ] crbug.com/954328 media/video-layer-crash.html [ Failure ] crbug.com/954328 transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ] + +crbug.com/918155 compositing/overflow/scrollbar-layer-placement-negative-z-index-child.html [ Failure ]
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization b/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization index d814edd8..f1b0771 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization +++ b/third_party/blink/web_tests/FlagExpectations/enable-gpu-rasterization
@@ -88,6 +88,7 @@ # Tests fail even with a fuzzy pixel diff. They require a re-baseline. crbug.com/954328 compositing/fixed-background-after-style-recalc.html [ Failure ] crbug.com/954328 compositing/overflow/mask-with-filter.html [ Failure ] +crbug.com/954328 compositing/overflow/scrollbar-layer-placement-negative-z-index-child.html [ Failure ] crbug.com/954328 css3/blending/background-blend-mode-crossfade-image-gradient.html [ Failure ] crbug.com/954328 css3/blending/background-blend-mode-default-value.html [ Failure ] crbug.com/954328 css3/blending/background-blend-mode-gradient-gradient.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index e60318e..03a3241 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -5169,6 +5169,10 @@ crbug.com/783301 external/wpt/imagecapture/MediaStreamTrack-getSettings.html [ Pass Failure ] crbug.com/783301 external/wpt/imagecapture/MediaStreamTrack-getCapabilities.html [ Pass Failure ] +# Cookie Store API +crbug.com/827231 external/wpt/cookie-store/document_cookie.tentative.html [ Pass Failure ] +crbug.com/827231 external/wpt/cookie-store/document_cookie.tentative.https.html [ Pass Failure ] + # Failing SameSite cookies tests crbug.com/843945 external/wpt/cookies/samesite/form-get-blank-reload.html [ Failure ] crbug.com/843945 external/wpt/cookies/samesite/form-post-blank-reload.html [ Failure ] @@ -6238,20 +6242,6 @@ # TODO(crbug.com/980588): reenable once WPT is fixed crbug.com/980588 external/wpt/screen-orientation/lock-unlock-check.html [ Pass Failure ] -# TODO (michaelludwig) - Rebaseline for Skia roll -crbug.com/981879 virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png.html [ Pass Failure ] -crbug.com/981879 virtual/gpu-rasterization/images/color-profile-background-image-cross-fade.html [ Pass Failure ] -crbug.com/981879 virtual/gpu-rasterization/images/cross-fade-background-size.html [ Pass Failure ] - -crbug.com/982289 virtual/gpu-rasterization/images/color-profile-background-image-cover.html [ Pass Failure ] -crbug.com/982289 virtual/gpu-rasterization/images/color-profile-background-image-repeat.html [ Pass Failure ] -crbug.com/982289 virtual/gpu-rasterization/images/color-profile-background-image-space.html [ Pass Failure ] -crbug.com/982289 virtual/gpu-rasterization/images/color-profile-image-canvas-pattern.html [ Pass Failure ] -crbug.com/982289 virtual/gpu-rasterization/images/color-profile-image-canvas.html [ Pass Failure ] -crbug.com/982289 virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Pass Failure ] -crbug.com/982289 virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile.html [ Pass Failure ] -crbug.com/982289 virtual/gpu-rasterization/images/color-profile-image.html [ Pass Failure ] - # Sheriff 2019-07-11 crbug.com/982290 [ Win ] http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits.js [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/mq-calc-006.html b/third_party/blink/web_tests/external/wpt/css/mediaqueries/mq-calc-006.html new file mode 100644 index 0000000..989ee42 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/mediaqueries/mq-calc-006.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<link rel="author" title="Xiaocheng Hu" href="xiaochengh@chromium.org"> +<link rel="help" href="http://www.w3.org/TR/css3-values/#calc-notation"> +<link rel="help" href="http://www.w3.org/TR/css3-mediaqueries/"> +<link rel="match" href="../reference/ref-filled-green-100px-square.xht"> +<meta name="assert" content="The 'in' unit used in calc is not mistaken as 'px'."> +<style> +p { font-size: 16px; } +#target { + width: 100px; + height: 100px; + background-color: green; +} +@media (min-width: calc(100in)) { + /* Should not be selected */ + #target { background-color: red } +} +</style> +<p>Test passes if there is a filled green square and <strong>no red</strong>.</p> +<div id=target></div>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch.tentative.sub.html new file mode 100644 index 0000000..0c5caa7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch.tentative.sub.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=/fetch/sec-metadata/resources/helper.js></script> +<script> + // http -> https should see `Sec-Fetch-Site: cross-site`. + // This is a regression test for + // https://github.com/w3c/webappsec-fetch-metadata/issues/34 + promise_test(t => { + assert_equals(location.protocol, "http:"); + return fetch("https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/echo-as-json.py") + .then(r => r.json()) + .then(j => { + assert_header_equals(j, { + "dest": "empty", + "site": "cross-site", + "user": "", + "mode": "cors", + }); + }); + }, "http->https fetch (cross-scheme => cross-site)"); + + // http -> http should see no `Sec-Fetch-Site`. + promise_test(t => { + assert_equals(location.protocol, "http:"); + return fetch("resources/echo-as-json.py") + .then(r => r.json()) + .then(j => { + assert_header_equals(j, { + "dest": "", + "site": "", + "user": "", + "mode": "", + }); + }); + }, "http->http fetch (non-trustworthy destination => no sec-metadata)"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.sub.html index eab2d3f..2bc2581 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/iframe.tentative.sub.html
@@ -60,4 +60,23 @@ document.body.appendChild(i); }, "Non-secure cross-site iframe => No headers."); + + async_test(t => { + let i = document.createElement('iframe'); + i.src = "https://{{host}}:{{ports[https][0]}}/fetch/sec-metadata/resources/post-to-owner.py"; + window.addEventListener('message', t.step_func(e => { + if (e.source != i.contentWindow) + return; + + assert_header_equals(e.data, { + "dest": "nested-document", + "site": "cross-site", + "user": "", + "mode": "nested-navigate", + }); + t.done(); + })); + + document.body.appendChild(i); + }, "Secure, cross-site (cross-scheme, same-host) iframe"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html index 3f8726d..cede671 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/multiple-redirect-https-downgrade-upgrade.tentative.sub.html
@@ -19,7 +19,7 @@ <div id="fontTest">Downgraded then upgraded font</div> <script> let nonce = token(); - let expected = { "dest": "", "site": "same-site", "user": "", "mode": "" }; + let expected = { "dest": "", "site": "cross-site", "user": "", "mode": "" }; // Validate various scenarios handle a request that redirects from https => http // correctly and avoids disclosure of any Sec- headers. @@ -52,7 +52,7 @@ // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way // that `image.py` encodes data. "dest": undefined, - "site": "same-site", + "site": "cross-site", "user": undefined, "mode": undefined, });
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/redirect-http-upgrade.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/redirect-http-upgrade.tentative.sub.html index fe55cda..4f173d9 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/redirect-http-upgrade.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/redirect/redirect-http-upgrade.tentative.sub.html
@@ -19,7 +19,7 @@ <div id="fontTest">Upgraded font</div> <script> let nonce = token(); - let expected = { "dest": "", "site": "same-site", "user": "", "mode": "" }; + let expected = { "dest": "", "site": "cross-site", "user": "", "mode": "" }; // Validate various scenarios handle a request that redirects from http => https correctly and add the proper Sec- headers. RunCommonRedirectTests("Http upgrade", upgradeRedirectTo, expected); @@ -51,7 +51,7 @@ // Note that we're using `undefined` here, as opposed to "" elsewhere because of the way // that `image.py` encodes data. "dest": undefined, - "site": "same-site", + "site": "cross-site", "user": undefined, "mode": undefined, });
diff --git a/third_party/blink/web_tests/external/wpt/std-toast/actions.html b/third_party/blink/web_tests/external/wpt/std-toast/actions.html index 018ce21..d07e5fd3 100644 --- a/third_party/blink/web_tests/external/wpt/std-toast/actions.html +++ b/third_party/blink/web_tests/external/wpt/std-toast/actions.html
@@ -102,4 +102,89 @@ assert_equals(actionButton, null); }, 'passing non-string (undefined) as action option does not create an action button'); + +testToastElement((toast) => { + const actionButton = document.createElement('button'); + actionButton.textContent = 'action'; + toast.action = actionButton; + + assertActionButtonOnToast(actionButton, toast); +}, 'setting the action on an actionless toast inserts the element into the slot'); + +testActionToast((toast, action) => { + const actionButton = document.createElement('button'); + actionButton.textContent = 'replacement'; + toast.action = actionButton; + + assert_false(document.contains(action)); + assertActionButtonOnToast(actionButton, toast); +}, 'resetting the action on an action toast changes the action element'); + +testToastElement((toast) => { + const text = document.createTextNode('some text'); + assert_throws(new TypeError(), () => { + toast.action = text; + }); +}, 'setting the action to an invalid type (Text node) throws an error'); + +testToastElement((toast) => { + const text = 'some text'; + assert_throws(new TypeError(), () => { + toast.action = text; + }); +}, 'setting the action to an invalid type (string) throws an error'); + +test(() => { + const actionButton = document.createElement('button'); + actionButton.textContent = 'action'; + const toast = showToast('Message', {action: actionButton}); + + assertActionButtonOnToast(actionButton, toast); +}, 'showToast can take an Element as the action parameter'); + +testActionToast((toast, action) => { + toast.action = null; + + assert_not_equals(toast.action, action); + assert_equals(toast.querySelector('button'), null); +}, 'setting toast.action to null removes the action from the toast'); + +testActionToast((toast, action) => { + const wrongAction = document.createElement('button'); + wrongAction.textContent = 'wrong'; + wrongAction.setAttribute('slot', 'action'); + toast.appendChild(wrongAction); + + const correctAction = document.createElement('button'); + correctAction.textContent = 'correct'; + toast.action = correctAction; + + assertActionButtonOnToast(correctAction, toast); +}, 'resetting toast.action on a toast with multiple actions slotted sets properly'); + +test(() => { + try { + Object.defineProperty(Element, Symbol.hasInstance, { + value: () => true, + configurable: true + }); + + const fakeElement = {}; + const toast = showToast('Message'); + assert_throws(new TypeError(), () => toast.action = fakeElement); + } finally { + delete Element[Symbol.hasInstance]; + } +}, 'spoofing element instance will not register as element to action setter'); + +test(() => { + const iframe = document.createElement('iframe'); + document.body.append(iframe); + iframe.contentDocument.body.innerHTML = '<div></div>'; + const elementFromAnotherFrame = iframe.contentDocument.querySelector('div'); + + // Should not throw: + const toast = showToast('Message'); + toast.action = elementFromAnotherFrame; +}, 'element from iframe instance will pass correctly to action without throwing an error'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/mark-entry-constructor.any.js b/third_party/blink/web_tests/external/wpt/user-timing/mark-entry-constructor.any.js new file mode 100644 index 0000000..ef9c403d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/user-timing/mark-entry-constructor.any.js
@@ -0,0 +1,40 @@ +// META: script=resources/user-timing-helper.js + +test(()=>{ + const entry = new PerformanceMark("name"); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark"}); +}, "Mark entry can be created by 'new PerformanceMark(string)'."); + +test(()=>{ + const entry = new PerformanceMark("name", {}); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark"}); +}, "Mark entry can be created by 'new PerformanceMark(string, {})'."); + +test(()=>{ + const entry = new PerformanceMark("name", {startTime: 1}); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark", startTime: 1}); +}, "Mark entry can be created by 'new PerformanceMark(string, {startTime})'."); + +test(()=>{ + const entry = new PerformanceMark("name", {detail: {info: "abc"}}); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark", detail: {info: "abc"}}); +}, "Mark entry can be created by 'new PerformanceMark(string, {detail})'."); + +test(()=>{ + const entry = + new PerformanceMark("name", {startTime: 1, detail: {info: "abc"}}); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark", startTime: 1, detail: {info: "abc"}}); +}, "Mark entry can be created by " + + "'new PerformanceMark(string, {startTime, detail})'."); + +test(()=>{ + const entry = new PerformanceMark("name"); + assert_true(entry instanceof PerformanceMark); + checkEntry(entry, {name: "name", entryType: "mark"}); + assert_equals(performance.getEntriesByName("name").length, 0); +}, "Using new PerformanceMark() shouldn't add the entry to performance timeline.");
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/mark-entry-constructor.html b/third_party/blink/web_tests/external/wpt/user-timing/mark-entry-constructor.html deleted file mode 100644 index 47c9a64..0000000 --- a/third_party/blink/web_tests/external/wpt/user-timing/mark-entry-constructor.html +++ /dev/null
@@ -1,50 +0,0 @@ -<!DOCTYPE HTML> -<meta charset=utf-8> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="resources/user-timing-helper.js"></script> -<title>User Timing L3: create mark entry by constructor</title> -<h1>User Timing L3: create mark entry by constructor</h1> -<p> -User Timing L3: Mark entry can be created by using constructor." -</p> -<script> - test(()=>{ - const entry = new PerformanceMark("name"); - assert_true(entry instanceof PerformanceMark); - checkEntry(entry, {name: "name", entryType: "mark"}); - }, "Mark entry can be created by 'new PerformanceMark(string)'."); - - test(()=>{ - const entry = new PerformanceMark("name", {}); - assert_true(entry instanceof PerformanceMark); - checkEntry(entry, {name: "name", entryType: "mark"}); - }, "Mark entry can be created by 'new PerformanceMark(string, {})'."); - - test(()=>{ - const entry = new PerformanceMark("name", {startTime: 1}); - assert_true(entry instanceof PerformanceMark); - checkEntry(entry, {name: "name", entryType: "mark", startTime: 1}); - }, "Mark entry can be created by 'new PerformanceMark(string, {startTime})'."); - - test(()=>{ - const entry = new PerformanceMark("name", {detail: {info: "abc"}}); - assert_true(entry instanceof PerformanceMark); - checkEntry(entry, {name: "name", entryType: "mark", detail: {info: "abc"}}); - }, "Mark entry can be created by 'new PerformanceMark(string, {detail})'."); - - test(()=>{ - const entry = - new PerformanceMark("name", {startTime: 1, detail: {info: "abc"}}); - assert_true(entry instanceof PerformanceMark); - checkEntry(entry, {name: "name", entryType: "mark", startTime: 1, detail: {info: "abc"}}); - }, "Mark entry can be created by " + - "'new PerformanceMark(string, {startTime, detail})'."); - - test(()=>{ - const entry = new PerformanceMark("name"); - assert_true(entry instanceof PerformanceMark); - checkEntry(entry, {name: "name", entryType: "mark"}); - assert_equals(performance.getEntriesByName("name").length, 0); - }, "Using new PerformanceMark() shouldn't add the entry to performance timeline."); -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/mark-errors.any.js b/third_party/blink/web_tests/external/wpt/user-timing/mark-errors.any.js new file mode 100644 index 0000000..3207d18 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/user-timing/mark-errors.any.js
@@ -0,0 +1,15 @@ +test(function() { + assert_throws(new TypeError(), function() { self.performance.mark("mark1", 123); }, "Number passed as a dict argument should cause type-error.") +}, "Number should be rejected as the mark-options.") + +test(function() { + assert_throws(new TypeError(), function() { self.performance.mark("mark1", NaN); }, "NaN passed as a dict argument should cause type-error.") +}, "NaN should be rejected as the mark-options.") + +test(function() { + assert_throws(new TypeError(), function() { self.performance.mark("mark1", Infinity); }, "Infinity passed as a dict argument should cause type-error.") +}, "Infinity should be rejected as the mark-options.") + +test(function() { + assert_throws(new TypeError(), function() { self.performance.mark("mark1", "string"); }, "String passed as a dict argument should cause type-error.") +}, "String should be rejected as the mark-options.")
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/mark-errors.html b/third_party/blink/web_tests/external/wpt/user-timing/mark-errors.html deleted file mode 100644 index c182a39..0000000 --- a/third_party/blink/web_tests/external/wpt/user-timing/mark-errors.html +++ /dev/null
@@ -1,23 +0,0 @@ -<!DOCTYPE HTML> -<meta charset=utf-8> -<title>UserTimingL3: errors are thrown when mark() is called incorrectly.</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<h1>UserTimingL3: Mark</h1> -<script> - test(function() { - assert_throws(new TypeError(), function() { self.performance.mark("mark1", 123); }, "Number passed as a dict argument should cause type-error.") - }, "Number should be rejected as the mark-options.") - - test(function() { - assert_throws(new TypeError(), function() { self.performance.mark("mark1", NaN); }, "NaN passed as a dict argument should cause type-error.") - }, "NaN should be rejected as the mark-options.") - - test(function() { - assert_throws(new TypeError(), function() { self.performance.mark("mark1", Infinity); }, "Infinity passed as a dict argument should cause type-error.") - }, "Infinity should be rejected as the mark-options.") - - test(function() { - assert_throws(new TypeError(), function() { self.performance.mark("mark1", "string"); }, "String passed as a dict argument should cause type-error.") - }, "String should be rejected as the mark-options.") -</script>
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/mark-l3.html b/third_party/blink/web_tests/external/wpt/user-timing/mark-l3.any.js similarity index 84% rename from third_party/blink/web_tests/external/wpt/user-timing/mark-l3.html rename to third_party/blink/web_tests/external/wpt/user-timing/mark-l3.any.js index bb4b22510..407a5c8b 100644 --- a/third_party/blink/web_tests/external/wpt/user-timing/mark-l3.html +++ b/third_party/blink/web_tests/external/wpt/user-timing/mark-l3.any.js
@@ -1,11 +1,6 @@ -<!DOCTYPE HTML> -<meta charset=utf-8> -<title>User Timing L3: mark</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="resources/user-timing-helper.js"></script> -<script> - async_test(function (t) { +// META: script=resources/user-timing-helper.js + +async_test(function (t) { let mark_entries = []; const expected_entries = [{ entryType: "mark", name: "mark1", detail: null}, @@ -41,5 +36,4 @@ returned_entries.push(self.performance.mark("mark8", {startTime: 234.56})); returned_entries.push(self.performance.mark("mark9", {detail: {count: 3}, startTime: 345.67})); checkEntries(returned_entries, expected_entries); - }, "mark entries' detail and startTime are customizable."); -</script> +}, "mark entries' detail and startTime are customizable.");
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/mark-measure-return-objects.any.js b/third_party/blink/web_tests/external/wpt/user-timing/mark-measure-return-objects.any.js new file mode 100644 index 0000000..fa45388 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/user-timing/mark-measure-return-objects.any.js
@@ -0,0 +1,37 @@ +async_test(function (t) { + self.performance.clearMeasures(); + const measure = self.performance.measure("measure1"); + assert_true(measure instanceof PerformanceMeasure); + t.done(); +}, "L3: performance.measure(name) should return an entry."); + +async_test(function (t) { + self.performance.clearMeasures(); + const measure = self.performance.measure("measure2", + { startTime: 12, endTime:23 }); + assert_true(measure instanceof PerformanceMeasure); + t.done(); +}, "L3: performance.measure(name, param1) should return an entry."); + +async_test(function (t) { + self.performance.clearMeasures(); + self.performance.mark("1"); + self.performance.mark("2"); + const measure = self.performance.measure("measure3", "1", "2"); + assert_true(measure instanceof PerformanceMeasure); + t.done(); +}, "L3: performance.measure(name, param1, param2) should return an entry."); + +async_test(function (t) { + self.performance.clearMarks(); + const mark = self.performance.mark("mark1"); + assert_true(mark instanceof PerformanceMark); + t.done(); +}, "L3: performance.mark(name) should return an entry."); + +async_test(function (t) { + self.performance.clearMarks(); + const mark = self.performance.mark("mark2", { startTime: 34 }); + assert_true(mark instanceof PerformanceMark); + t.done(); +}, "L3: performance.mark(name, param) should return an entry.");
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/mark-measure-return-objects.html b/third_party/blink/web_tests/external/wpt/user-timing/mark-measure-return-objects.html deleted file mode 100644 index d2d8cc3c..0000000 --- a/third_party/blink/web_tests/external/wpt/user-timing/mark-measure-return-objects.html +++ /dev/null
@@ -1,46 +0,0 @@ -<!DOCTYPE HTML> -<meta charset=utf-8> -<title>UserTiming L3: mark/measure methods return objects.</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<p>Custom User Timing: L3 API returns a mark/measure object</p> -<div id="log"></div> -<script> - async_test(function (t) { - self.performance.clearMeasures(); - const measure = self.performance.measure("measure1"); - assert_true(measure instanceof PerformanceMeasure); - t.done(); - }, "L3: performance.measure(name) should return an entry."); - - async_test(function (t) { - self.performance.clearMeasures(); - const measure = self.performance.measure("measure2", - { startTime: 12, endTime:23 }); - assert_true(measure instanceof PerformanceMeasure); - t.done(); - }, "L3: performance.measure(name, param1) should return an entry."); - - async_test(function (t) { - self.performance.clearMeasures(); - self.performance.mark("1"); - self.performance.mark("2"); - const measure = self.performance.measure("measure3", "1", "2"); - assert_true(measure instanceof PerformanceMeasure); - t.done(); - }, "L3: performance.measure(name, param1, param2) should return an entry."); - - async_test(function (t) { - self.performance.clearMarks(); - const mark = self.performance.mark("mark1"); - assert_true(mark instanceof PerformanceMark); - t.done(); - }, "L3: performance.mark(name) should return an entry."); - - async_test(function (t) { - self.performance.clearMarks(); - const mark = self.performance.mark("mark2", { startTime: 34 }); - assert_true(mark instanceof PerformanceMark); - t.done(); - }, "L3: performance.mark(name, param) should return an entry."); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/measure-l3.any.js b/third_party/blink/web_tests/external/wpt/user-timing/measure-l3.any.js new file mode 100644 index 0000000..24c27c4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/user-timing/measure-l3.any.js
@@ -0,0 +1,35 @@ +// META: script=resources/user-timing-helper.js + +function endTime(entry) { + return entry.startTime + entry.duration; +} + +test(function() { + performance.clearMarks(); + performance.clearMeasures(); + const markEntry = performance.mark("mark", {startTime: 123}); + const measureEntry = performance.measure("A", undefined, "mark"); + assert_equals(measureEntry.startTime, 0); + assert_equals(endTime(measureEntry), markEntry.startTime); +}, "When the end mark is given and the start is unprovided, the end time of the measure entry should be the end mark's time, the start time should be 0."); + +test(function() { + performance.clearMarks(); + performance.clearMeasures(); + const markEntry = performance.mark("mark", {startTime: 123}); + const endMin = performance.now(); + const measureEntry = performance.measure("A", "mark", undefined); + const endMax = performance.now(); + assert_equals(measureEntry.startTime, markEntry.startTime); + assert_greater_than_equal(endTime(measureEntry), endMin); + assert_greater_than_equal(endMax, endTime(measureEntry)); +}, "When the start mark is given and the end is unprovided, the start time of the measure entry should be the start mark's time, the end should be now."); + +test(function() { + performance.clearMarks(); + performance.clearMeasures(); + const markEntry = performance.mark("mark", {startTime: 123}); + const measureEntry = performance.measure("A", "mark", "mark"); + assert_equals(endTime(measureEntry), markEntry.startTime); + assert_equals(measureEntry.startTime, markEntry.startTime); +}, "When start and end mark are both given, the start time and end time of the measure entry should be the the marks' time, repectively");
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/measure-l3.html b/third_party/blink/web_tests/external/wpt/user-timing/measure-l3.html deleted file mode 100644 index 0e8dacf..0000000 --- a/third_party/blink/web_tests/external/wpt/user-timing/measure-l3.html +++ /dev/null
@@ -1,40 +0,0 @@ -<!DOCTYPE HTML> -<meta charset=utf-8> -<title>UserTiming L3: Measure basic usage</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script> - function endTime(entry) { - return entry.startTime + entry.duration; - } - - test(function() { - performance.clearMarks(); - performance.clearMeasures(); - const markEntry = performance.mark("mark", {startTime: 123}); - const measureEntry = performance.measure("A", undefined, "mark"); - assert_equals(measureEntry.startTime, 0); - assert_equals(endTime(measureEntry), markEntry.startTime); - }, "When the end mark is given and the start is unprovided, the end time of the measure entry should be the end mark's time, the start time should be 0."); - - test(function() { - performance.clearMarks(); - performance.clearMeasures(); - const markEntry = performance.mark("mark", {startTime: 123}); - const endMin = performance.now(); - const measureEntry = performance.measure("A", "mark", undefined); - const endMax = performance.now(); - assert_equals(measureEntry.startTime, markEntry.startTime); - assert_greater_than_equal(endTime(measureEntry), endMin); - assert_greater_than_equal(endMax, endTime(measureEntry)); - }, "When the start mark is given and the end is unprovided, the start time of the measure entry should be the start mark's time, the end should be now."); - - test(function() { - performance.clearMarks(); - performance.clearMeasures(); - const markEntry = performance.mark("mark", {startTime: 123}); - const measureEntry = performance.measure("A", "mark", "mark"); - assert_equals(endTime(measureEntry), markEntry.startTime); - assert_equals(measureEntry.startTime, markEntry.startTime); - }, "When start and end mark are both given, the start time and end time of the measure entry should be the the marks' time, repectively"); -</script>
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/measure-with-dict.html b/third_party/blink/web_tests/external/wpt/user-timing/measure-with-dict.any.js similarity index 91% rename from third_party/blink/web_tests/external/wpt/user-timing/measure-with-dict.html rename to third_party/blink/web_tests/external/wpt/user-timing/measure-with-dict.any.js index 8ba7b9f..99a2fe4d7 100644 --- a/third_party/blink/web_tests/external/wpt/user-timing/measure-with-dict.html +++ b/third_party/blink/web_tests/external/wpt/user-timing/measure-with-dict.any.js
@@ -1,16 +1,11 @@ -<!DOCTYPE HTML> -<meta charset=utf-8> -<title>User Timing L3: measure is customizable</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script src="resources/user-timing-helper.js"></script> -<script> - function cleanupPerformanceTimeline() { +// META: script=resources/user-timing-helper.js + +function cleanupPerformanceTimeline() { performance.clearMarks(); performance.clearMeasures(); - } +} - async_test(function (t) { +async_test(function (t) { this.add_cleanup(cleanupPerformanceTimeline); let measureEntries = []; const timeStamp1 = 784.4; @@ -91,9 +86,9 @@ returnedEntries.push(self.performance.measure("measure20", undefined, 'mark1')); returnedEntries.push(self.performance.measure("measure21", { invalidDict:1 }, 'mark1')); checkEntries(returnedEntries, expectedEntries); - }, "measure entries' detail and start/end are customizable"); +}, "measure entries' detail and start/end are customizable"); - test(function() { +test(function() { this.add_cleanup(cleanupPerformanceTimeline); assert_throws(new TypeError(), function() { self.performance.measure("optionsAndNumberEnd", {'start': 2}, 12); @@ -107,5 +102,5 @@ assert_throws(new TypeError(), function() { self.performance.measure("negativeEndInOptions", {'end': -1}); }, "measure cannot have a negative time stamp for end."); - }, "measure should throw a TypeError when passed an invalid argument combination"); -</script> +}, "measure should throw a TypeError when passed an invalid argument combination"); +
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/structured-serialize-detail.any.js b/third_party/blink/web_tests/external/wpt/user-timing/structured-serialize-detail.any.js new file mode 100644 index 0000000..55cbd924 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/user-timing/structured-serialize-detail.any.js
@@ -0,0 +1,64 @@ +test(function() { + performance.clearMarks(); + const detail = { randomInfo: 123 } + const markEntry = new PerformanceMark("A", { detail }); + assert_equals(markEntry.detail.randomInfo, detail.randomInfo); + assert_not_equals(markEntry.detail, detail); +}, "The detail property in the mark constructor should be structured-clone."); + +test(function() { + performance.clearMarks(); + const detail = { randomInfo: 123 } + const markEntry = performance.mark("A", { detail }); + assert_not_equals(markEntry.detail, detail); +}, "The detail property in the mark method should be structured-clone."); + +test(function() { + performance.clearMarks(); + const markEntry = performance.mark("A"); + assert_equals(markEntry.detail, null); +}, "When accessing detail from a mark entry and the detail is not provided, just return a null value."); + +test(function() { + performance.clearMarks(); + const detail = { unserializable: Symbol() }; + assert_throws("DataCloneError", ()=>{ + new PerformanceMark("A", { detail }); + }, "Trying to structured-serialize a Symbol."); +}, "Mark: Throw an exception when the detail property cannot be structured-serialized."); + +test(function() { + performance.clearMeasures(); + const detail = { randomInfo: 123 } + const measureEntry = performance.measure("A", { detail }); + assert_not_equals(measureEntry.detail, detail); +}, "The detail property in the measure method should be structured-clone."); + +test(function() { + performance.clearMeasures(); + const detail = { randomInfo: 123 } + const measureEntry = performance.measure("A", { detail }); + assert_equals(measureEntry.detail, measureEntry.detail); +}, "The detail property in the measure method should be the same reference."); + +test(function() { + performance.clearMeasures(); + const measureEntry = performance.measure("A"); + assert_equals(measureEntry.detail, null); +}, "When accessing detail from a measure entry and the detail is not provided, just return a null value."); + +test(function() { + performance.clearMeasures(); + const detail = { unserializable: Symbol() }; + assert_throws("DataCloneError", ()=>{ + performance.measure("A", { detail }); + }, "Trying to structured-serialize a Symbol."); +}, "Measure: Throw an exception when the detail property cannot be structured-serialized."); + +test(function() { + const bar = { 1: 2 }; + const detail = { foo: 1, bar }; + const mark = performance.mark("m", { detail }); + detail.foo = 2; + assert_equals(mark.detail.foo, 1); +}, "The detail object is cloned when passed to mark API.");
diff --git a/third_party/blink/web_tests/external/wpt/user-timing/structured-serialize-detail.html b/third_party/blink/web_tests/external/wpt/user-timing/structured-serialize-detail.html deleted file mode 100644 index c9689fe3..0000000 --- a/third_party/blink/web_tests/external/wpt/user-timing/structured-serialize-detail.html +++ /dev/null
@@ -1,71 +0,0 @@ -<!DOCTYPE HTML> -<meta charset=utf-8> -<title>UserTiming L3: the detail property should be serialized-cloned.</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script> - test(function() { - performance.clearMarks(); - const detail = { randomInfo: 123 } - const markEntry = new PerformanceMark("A", { detail }); - assert_equals(markEntry.detail.randomInfo, detail.randomInfo); - assert_not_equals(markEntry.detail, detail); - }, "The detail property in the mark constructor should be structured-clone."); - - test(function() { - performance.clearMarks(); - const detail = { randomInfo: 123 } - const markEntry = performance.mark("A", { detail }); - assert_not_equals(markEntry.detail, detail); - }, "The detail property in the mark method should be structured-clone."); - - test(function() { - performance.clearMarks(); - const markEntry = performance.mark("A"); - assert_equals(markEntry.detail, null); - }, "When accessing detail from a mark entry and the detail is not provided, just return a null value."); - - test(function() { - performance.clearMarks(); - const detail = { unserializable: Symbol() }; - assert_throws("DataCloneError", ()=>{ - new PerformanceMark("A", { detail }); - }, "Trying to structured-serialize a Symbol."); - }, "Mark: Throw an exception when the detail property cannot be structured-serialized."); - - test(function() { - performance.clearMeasures(); - const detail = { randomInfo: 123 } - const measureEntry = performance.measure("A", { detail }); - assert_not_equals(measureEntry.detail, detail); - }, "The detail property in the measure method should be structured-clone."); - - test(function() { - performance.clearMeasures(); - const detail = { randomInfo: 123 } - const measureEntry = performance.measure("A", { detail }); - assert_equals(measureEntry.detail, measureEntry.detail); - }, "The detail property in the measure method should be the same reference."); - - test(function() { - performance.clearMeasures(); - const measureEntry = performance.measure("A"); - assert_equals(measureEntry.detail, null); - }, "When accessing detail from a measure entry and the detail is not provided, just return a null value."); - - test(function() { - performance.clearMeasures(); - const detail = { unserializable: Symbol() }; - assert_throws("DataCloneError", ()=>{ - performance.measure("A", { detail }); - }, "Trying to structured-serialize a Symbol."); - }, "Measure: Throw an exception when the detail property cannot be structured-serialized."); - - test(function() { - const bar = { 1: 2 }; - const detail = { foo: 1, bar }; - const mark = performance.mark("m", { detail }); - detail.foo = 2; - assert_equals(mark.detail.foo, 1); - }, "The detail object is cloned when passed to mark API."); -</script>
diff --git a/third_party/blink/web_tests/http/tests/devtools/unit/list-control-equal-height-expected.txt b/third_party/blink/web_tests/http/tests/devtools/unit/list-control-equal-height-expected.txt index ec113cad..86237d4 100644 --- a/third_party/blink/web_tests/http/tests/devtools/unit/list-control-equal-height-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/unit/list-control-equal-height-expected.txt
@@ -191,7 +191,7 @@ Resizing Creating element for 15 Creating element for 16 -----list[length=20][height=84]---- +----list[length=20][height=83]---- [0] top *[0] 0 *[10] 1 @@ -216,29 +216,29 @@ Creating element for 17 Creating element for 18 Creating element for 19 -----list[length=20][height=84]---- - [-116] top - [-86] 3 - [-76] 4 - [-66] 5 - [-56] 6 - [-46] 7 - [-36] 8 - [-26] 9 - [-16] 10 -+[-6] 11 -*[4] 12 -*[14] 13 -*[24] 14 -*[34] 15 -*[44] 16 -*[54] 17 -*[64] 18 -*[74] 19 - [84] bottom +----list[length=20][height=83]---- + [-117] top + [-87] 3 + [-77] 4 + [-67] 5 + [-57] 6 + [-47] 7 + [-37] 8 + [-27] 9 + [-17] 10 ++[-7] 11 +*[3] 12 +*[13] 13 +*[23] 14 +*[33] 15 +*[43] 16 +*[53] 17 +*[63] 18 +*[73] 19 + [83] bottom Scrolling to 5 -----list[length=20][height=84]---- +----list[length=20][height=83]---- [-50] top [-50] 0 [-40] 1 @@ -263,7 +263,7 @@ [150] bottom Scrolling to 12 -----list[length=20][height=84]---- +----list[length=20][height=83]---- [-50] top [-50] 0 [-40] 1 @@ -288,29 +288,29 @@ [150] bottom Scrolling to 13 -----list[length=20][height=84]---- - [-56] top - [-56] 0 - [-46] 1 - [-36] 2 - [-26] 3 - [-16] 4 -+[-6] 5 -*[4] 6 -*[14] 7 -*[24] 8 -*[34] 9 -*[44] 10 -*[54] 11 -*[64] 12 -*[74] 13 - [84] 14 - [94] 15 - [104] 16 - [114] 17 - [124] 18 - [134] 19 - [144] bottom +----list[length=20][height=83]---- + [-57] top + [-57] 0 + [-47] 1 + [-37] 2 + [-27] 3 + [-17] 4 ++[-7] 5 +*[3] 6 +*[13] 7 +*[23] 8 +*[33] 9 +*[43] 10 +*[53] 11 +*[63] 12 +*[73] 13 + [83] 14 + [93] 15 + [103] 16 + [113] 17 + [123] 18 + [133] 19 + [143] bottom Changing the item height Creating element for 0 @@ -328,87 +328,87 @@ Creating element for 12 Creating element for 13 Creating element for 14 -----list[length=20][height=84]---- - [-56] top - [-56] 0 - [-41] 1 - [-26] 2 -+[-11] 3 -*[4] 4 -*[19] 5 -*[34] 6 -*[49] 7 -*[64] 8 -+[79] 9 - [94] 10 - [109] 11 - [124] 12 - [139] 13 - [154] 14 - [169] bottom +----list[length=20][height=83]---- + [-57] top + [-57] 0 + [-42] 1 + [-27] 2 ++[-12] 3 +*[3] 4 +*[18] 5 +*[33] 6 +*[48] 7 +*[63] 8 ++[78] 9 + [93] 10 + [108] 11 + [123] 12 + [138] 13 + [153] 14 + [168] bottom Selecting 7 Selection changed from null to 7 -----list[length=20][height=84]---- - [-56] top - [-56] 0 - [-41] 1 - [-26] 2 -+[-11] 3 -*[4] 4 -*[19] 5 -*[34] 6 -*[49] 7 (selected) -*[64] 8 -+[79] 9 - [94] 10 - [109] 11 - [124] 12 - [139] 13 - [154] 14 - [169] bottom +----list[length=20][height=83]---- + [-57] top + [-57] 0 + [-42] 1 + [-27] 2 ++[-12] 3 +*[3] 4 +*[18] 5 +*[33] 6 +*[48] 7 (selected) +*[63] 8 ++[78] 9 + [93] 10 + [108] 11 + [123] 12 + [138] 13 + [153] 14 + [168] bottom Replacing 7 with 27 Creating element for 27 Selection changed from 7 to 10 -----list[length=20][height=84]---- - [-56] top - [-56] 0 - [-41] 1 - [-26] 2 -+[-11] 3 -*[4] 4 -*[19] 5 -*[34] 6 -*[49] 27 -*[64] 8 -+[79] 9 - [94] 10 (selected) - [109] 11 - [124] 12 - [139] 13 - [154] 14 - [169] bottom +----list[length=20][height=83]---- + [-57] top + [-57] 0 + [-42] 1 + [-27] 2 ++[-12] 3 +*[3] 4 +*[18] 5 +*[33] 6 +*[48] 27 +*[63] 8 ++[78] 9 + [93] 10 (selected) + [108] 11 + [123] 12 + [138] 13 + [153] 14 + [168] bottom Replacing 18, 19 with 28, 29 -----list[length=20][height=84]---- - [-56] top - [-56] 0 - [-41] 1 - [-26] 2 -+[-11] 3 -*[4] 4 -*[19] 5 -*[34] 6 -*[49] 27 -*[64] 8 -+[79] 9 - [94] 10 (selected) - [109] 11 - [124] 12 - [139] 13 - [154] 14 - [169] bottom +----list[length=20][height=83]---- + [-57] top + [-57] 0 + [-42] 1 + [-27] 2 ++[-12] 3 +*[3] 4 +*[18] 5 +*[33] 6 +*[48] 27 +*[63] 8 ++[78] 9 + [93] 10 (selected) + [108] 11 + [123] 12 + [138] 13 + [153] 14 + [168] bottom PageDown Creating element for 15 @@ -417,144 +417,144 @@ Creating element for 28 Creating element for 29 Selection changed from 10 to 17 -----list[length=20][height=84]---- - [-186] top - [-96] 6 - [-81] 27 - [-66] 8 - [-51] 9 - [-36] 10 - [-21] 11 -+[-6] 12 -*[9] 13 -*[24] 14 -*[39] 15 -*[54] 16 -*[69] 17 (selected) - [84] 28 - [99] 29 - [114] bottom +----list[length=20][height=83]---- + [-187] top + [-97] 6 + [-82] 27 + [-67] 8 + [-52] 9 + [-37] 10 + [-22] 11 ++[-7] 12 +*[8] 13 +*[23] 14 +*[38] 15 +*[53] 16 +*[68] 17 (selected) + [83] 28 + [98] 29 + [113] bottom Replacing 1, 2, 3 with [31-43] -----list[length=30][height=84]---- - [-336] top - [-96] 6 - [-81] 27 - [-66] 8 - [-51] 9 - [-36] 10 - [-21] 11 -+[-6] 12 -*[9] 13 -*[24] 14 -*[39] 15 -*[54] 16 -*[69] 17 (selected) - [84] 28 - [99] 29 - [114] bottom +----list[length=30][height=83]---- + [-337] top + [-97] 6 + [-82] 27 + [-67] 8 + [-52] 9 + [-37] 10 + [-22] 11 ++[-7] 12 +*[8] 13 +*[23] 14 +*[38] 15 +*[53] 16 +*[68] 17 (selected) + [83] 28 + [98] 29 + [113] bottom Scrolling to 13 (center) -----list[length=30][height=84]---- - [-310] top - [-85] 5 - [-70] 6 - [-55] 27 - [-40] 8 - [-25] 9 -+[-10] 10 -*[5] 11 -*[20] 12 -*[35] 13 -*[50] 14 -*[65] 15 -+[80] 16 - [95] 17 (selected) - [110] 28 - [125] 29 - [140] bottom +----list[length=30][height=83]---- + [-311] top + [-86] 5 + [-71] 6 + [-56] 27 + [-41] 8 + [-26] 9 ++[-11] 10 +*[4] 11 +*[19] 12 +*[34] 13 +*[49] 14 +*[64] 15 ++[79] 16 + [94] 17 (selected) + [109] 28 + [124] 29 + [139] bottom ArrowUp Selection changed from 17 to 15 -----list[length=30][height=84]---- - [-310] top - [-85] 5 - [-70] 6 - [-55] 27 - [-40] 8 - [-25] 9 -+[-10] 10 -*[5] 11 -*[20] 12 -*[35] 13 -*[50] 14 -*[65] 15 (selected) -+[80] 16 - [95] 17 - [110] 28 - [125] 29 - [140] bottom +----list[length=30][height=83]---- + [-311] top + [-86] 5 + [-71] 6 + [-56] 27 + [-41] 8 + [-26] 9 ++[-11] 10 +*[4] 11 +*[19] 12 +*[34] 13 +*[49] 14 +*[64] 15 (selected) ++[79] 16 + [94] 17 + [109] 28 + [124] 29 + [139] bottom Selecting -1 Selection changed from 15 to null -----list[length=30][height=84]---- - [-310] top - [-85] 5 - [-70] 6 - [-55] 27 - [-40] 8 - [-25] 9 -+[-10] 10 -*[5] 11 -*[20] 12 -*[35] 13 -*[50] 14 -*[65] 15 -+[80] 16 - [95] 17 - [110] 28 - [125] 29 - [140] bottom +----list[length=30][height=83]---- + [-311] top + [-86] 5 + [-71] 6 + [-56] 27 + [-41] 8 + [-26] 9 ++[-11] 10 +*[4] 11 +*[19] 12 +*[34] 13 +*[49] 14 +*[64] 15 ++[79] 16 + [94] 17 + [109] 28 + [124] 29 + [139] bottom ArrowUp Selection changed from null to 17 -----list[length=30][height=84]---- - [-336] top - [-96] 6 - [-81] 27 - [-66] 8 - [-51] 9 - [-36] 10 - [-21] 11 -+[-6] 12 -*[9] 13 -*[24] 14 -*[39] 15 -*[54] 16 -*[69] 17 (selected) - [84] 28 - [99] 29 - [114] bottom +----list[length=30][height=83]---- + [-337] top + [-97] 6 + [-82] 27 + [-67] 8 + [-52] 9 + [-37] 10 + [-22] 11 ++[-7] 12 +*[8] 13 +*[23] 14 +*[38] 15 +*[53] 16 +*[68] 17 (selected) + [83] 28 + [98] 29 + [113] bottom Selecting -1 Selection changed from 17 to null -----list[length=30][height=84]---- - [-336] top - [-96] 6 - [-81] 27 - [-66] 8 - [-51] 9 - [-36] 10 - [-21] 11 -+[-6] 12 -*[9] 13 -*[24] 14 -*[39] 15 -*[54] 16 -*[69] 17 - [84] 28 - [99] 29 - [114] bottom +----list[length=30][height=83]---- + [-337] top + [-97] 6 + [-82] 27 + [-67] 8 + [-52] 9 + [-37] 10 + [-22] 11 ++[-7] 12 +*[8] 13 +*[23] 14 +*[38] 15 +*[53] 16 +*[68] 17 + [83] 28 + [98] 29 + [113] bottom ArrowDown Creating element for 41 @@ -569,7 +569,7 @@ Creating element for 32 Creating element for 31 Selection changed from null to 0 -----list[length=30][height=84]---- +----list[length=30][height=83]---- [0] top *[0] 0 (selected) *[15] 31 @@ -587,7 +587,7 @@ Selecting -1 Selection changed from 0 to null -----list[length=30][height=84]---- +----list[length=30][height=83]---- [0] top *[0] 0 *[15] 31 @@ -607,37 +607,37 @@ Creating element for 42 Creating element for 43 Selection changed from null to 12 -----list[length=30][height=84]---- - [-261] top - [-96] 41 - [-81] 42 - [-66] 43 - [-51] 4 - [-36] 5 - [-21] 6 -+[-6] 27 -*[9] 8 -*[24] 9 -*[39] 10 -*[54] 11 -*[69] 12 (selected) - [84] 13 - [99] 14 - [114] 15 - [129] 16 - [144] 17 - [159] 28 - [174] bottom +----list[length=30][height=83]---- + [-262] top + [-97] 41 + [-82] 42 + [-67] 43 + [-52] 4 + [-37] 5 + [-22] 6 ++[-7] 27 +*[8] 8 +*[23] 9 +*[38] 10 +*[53] 11 +*[68] 12 (selected) + [83] 13 + [98] 14 + [113] 15 + [128] 16 + [143] 17 + [158] 28 + [173] bottom Replacing all but 29 with [] Selection changed from 12 to null -----list[length=1][height=84]---- +----list[length=1][height=83]---- [0] top *[0] 29 *[15] bottom ArrowDown -----list[length=1][height=84]---- +----list[length=1][height=83]---- [0] top *[0] 29 *[15] bottom @@ -646,7 +646,7 @@ Creating element for 5 Creating element for 6 Creating element for 7 -----list[length=1][height=84]---- +----list[length=1][height=83]---- [0] top *[0] 5 *[15] 6 @@ -655,7 +655,7 @@ Pushing 8 Creating element for 8 -----list[length=1][height=84]---- +----list[length=1][height=83]---- [0] top *[0] 5 *[15] 6 @@ -664,7 +664,7 @@ *[60] bottom Pushing 9 to old model -----list[length=2][height=84]---- +----list[length=2][height=83]---- [0] top *[0] 5 *[15] 6
diff --git a/third_party/blink/web_tests/http/tests/devtools/unit/list-control-equal-height.js b/third_party/blink/web_tests/http/tests/devtools/unit/list-control-equal-height.js index 15cafb0d..d89bfb1 100644 --- a/third_party/blink/web_tests/http/tests/devtools/unit/list-control-equal-height.js +++ b/third_party/blink/web_tests/http/tests/devtools/unit/list-control-equal-height.js
@@ -118,7 +118,7 @@ dumpList(); TestRunner.addResult('Resizing'); - list.element.style.height = '84px'; + list.element.style.height = '83px'; list.viewportResized(); dumpList();
diff --git a/third_party/blink/web_tests/http/tests/devtools/workspace-view-file-system-header-expected.txt b/third_party/blink/web_tests/http/tests/devtools/workspace-view-file-system-header-expected.txt new file mode 100644 index 0000000..289a663 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/workspace-view-file-system-header-expected.txt
@@ -0,0 +1,5 @@ +Tests workspace view file system headers + +File system name: test +File system path: file:///this/is/a/test +
diff --git a/third_party/blink/web_tests/http/tests/devtools/workspace-view-file-system-header.js b/third_party/blink/web_tests/http/tests/devtools/workspace-view-file-system-header.js new file mode 100644 index 0000000..634d9c7f --- /dev/null +++ b/third_party/blink/web_tests/http/tests/devtools/workspace-view-file-system-header.js
@@ -0,0 +1,22 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(async function() { + TestRunner.addResult('Tests workspace view file system headers\n'); + await TestRunner.loadModule('bindings_test_runner'); + + const fs = new BindingsTestRunner.TestFileSystem('file:///this/is/a/test'); + await fs.reportCreatedPromise(); + + await UI.viewManager.showView('workspace'); + const workspaceElement = (await UI.viewManager.view('workspace').widget()).element; + + const fsName = workspaceElement.querySelector('.file-system-name').textContent; + const fsPath = workspaceElement.querySelector('.file-system-path').textContent; + + TestRunner.addResult(`File system name: ${fsName}`); + TestRunner.addResult(`File system path: ${fsPath}`); + + TestRunner.completeTest(); +})();
diff --git a/third_party/blink/web_tests/http/tests/security/isolatedWorld/isolated-world-eval-csp-expected.txt b/third_party/blink/web_tests/http/tests/security/isolatedWorld/isolated-world-eval-csp-expected.txt new file mode 100644 index 0000000..90d9b8f --- /dev/null +++ b/third_party/blink/web_tests/http/tests/security/isolatedWorld/isolated-world-eval-csp-expected.txt
@@ -0,0 +1,12 @@ +CONSOLE MESSAGE: line 38: Testing main world. Eval should be blocked by main world CSP. +CONSOLE MESSAGE: line 7: EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'". + +CONSOLE MESSAGE: line 13: PASS: eval blocked as expected. +CONSOLE MESSAGE: line 44: Testing isolated world with no csp. Eval should be allowed. +CONSOLE MESSAGE: PASS: eval allowed as expected. +CONSOLE MESSAGE: line 55: Testing isolated world with strict csp. +CONSOLE MESSAGE: line 58: internals.runtimeFlags.isolatedWorldCSPEnabled is false +CONSOLE MESSAGE: PASS: eval allowed as expected. +CONSOLE MESSAGE: line 68: Testing isolated world with permissive csp. +CONSOLE MESSAGE: PASS: eval allowed as expected. +This tests the handling of unsafe-eval CSP checks and its interaction with the isolated world CSP.
diff --git a/third_party/blink/web_tests/http/tests/security/isolatedWorld/isolated-world-eval-csp.html b/third_party/blink/web_tests/http/tests/security/isolatedWorld/isolated-world-eval-csp.html new file mode 100644 index 0000000..5585b518 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/security/isolatedWorld/isolated-world-eval-csp.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Security-Policy" content="script-src 'self'"> +<script src="resources/isolated-world-eval-csp.js"></script> +</head> +<body id="body"> + <p> + This tests the handling of unsafe-eval CSP checks and its interaction + with the isolated world CSP. + </p> +</body> +</html>
diff --git a/third_party/blink/web_tests/http/tests/security/isolatedWorld/resources/isolated-world-eval-csp.js b/third_party/blink/web_tests/http/tests/security/isolatedWorld/resources/isolated-world-eval-csp.js new file mode 100644 index 0000000..617233a3 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/security/isolatedWorld/resources/isolated-world-eval-csp.js
@@ -0,0 +1,100 @@ +function testEval(expectBlocked) { + let evalBlocked; + try { + const x = eval('200'); + evalBlocked = (x != 200); + } catch(e) { + console.log(e); + evalBlocked = true; + } + finally { + if (expectBlocked === evalBlocked) { + if (expectBlocked) + console.log('PASS: eval blocked as expected.'); + else + console.log('PASS: eval allowed as expected.'); + } else { + if (expectBlocked) + console.log('FAIL: eval allowed unexpectedly.'); + else + console.log('FAIL: eval blocked unexpectedly.'); + } + window.postMessage('next', '*'); + } +} + +let isolatedWorldId = 1; +const isolatedWorldSecurityOrigin = 'chrome-extensions://123'; + +function testEvalInIsolatedWorld(expectBlocked) { + const expectBlockedStr = expectBlocked ? 'true' : 'false'; + testRunner.evaluateScriptInIsolatedWorld( + isolatedWorldId, + String(testEval.toString()) + `\ntestEval(${expectBlockedStr});`); +} + +const tests = [ + function() { + console.log( + 'Testing main world. Eval should be blocked by main world CSP.'); + testEval(true); + }, + function() { + // TODO(karandeepb): Ideally we should use the main world CSP in this case. + console.log( + 'Testing isolated world with no csp. Eval should be allowed.'); + testRunner.setIsolatedWorldInfo(isolatedWorldId, null, null); + testEvalInIsolatedWorld(false); + + // We use a different isolated world ID for each test since the eval-based + // CSP checks are set-up when a v8::context is initialized. This happens for + // an isolated world when a script is executed in it for the first time. + isolatedWorldId++; + }, + function() { + console.log('Testing isolated world with strict csp.'); + testRunner.setIsolatedWorldInfo( + isolatedWorldId, isolatedWorldSecurityOrigin, 'script-src \'none\''); + console.log( + 'internals.runtimeFlags.isolatedWorldCSPEnabled is ' + + internals.runtimeFlags.isolatedWorldCSPEnabled); + const expectBlocked = internals.runtimeFlags.isolatedWorldCSPEnabled; + testEvalInIsolatedWorld(expectBlocked); + + testRunner.setIsolatedWorldInfo(isolatedWorldId, null, null); + isolatedWorldId++; + }, + function() { + console.log('Testing isolated world with permissive csp.'); + testRunner.setIsolatedWorldInfo( + isolatedWorldId, isolatedWorldSecurityOrigin, + 'script-src \'unsafe-eval\''); + testEvalInIsolatedWorld(false); + + testRunner.setIsolatedWorldInfo(isolatedWorldId, null, null); + isolatedWorldId++; + }, +]; + +// This test is meaningless without testRunner. +if (window.testRunner) { + testRunner.dumpAsText(); + testRunner.waitUntilDone(); + + let currentTest = 0; + window.addEventListener('message', function(e) { + if (e.data == 'next') { + // Move to the next test. + currentTest++; + if (currentTest == tests.length) { + testRunner.notifyDone(); + return; + } + + // Move to the next sub-test. + tests[currentTest](); + } + }, false); + + tests[0](); +}
diff --git a/third_party/blink/web_tests/images/fallback-when-image-loading-disabled-expected.html b/third_party/blink/web_tests/images/fallback-when-image-loading-disabled-expected.html new file mode 100644 index 0000000..b13eefc --- /dev/null +++ b/third_party/blink/web_tests/images/fallback-when-image-loading-disabled-expected.html
@@ -0,0 +1,3 @@ +<!DOCTYPE html> +<title>Fallback content should be shown when image loading is disabled (reference)</title> +<img src="not-resources/mu.png" alt="Chair spinning">
diff --git a/third_party/blink/web_tests/images/fallback-when-image-loading-disabled.html b/third_party/blink/web_tests/images/fallback-when-image-loading-disabled.html new file mode 100644 index 0000000..4b67062 --- /dev/null +++ b/third_party/blink/web_tests/images/fallback-when-image-loading-disabled.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<title>Fallback content should be shown when image loading is disabled</title> +<script> + if (window.internals) + internals.settings.setLoadsImagesAutomatically(false); +</script> +<body></body> +<script> + let image = new Image(); + image.src = "resources/mu.png?" + Math.random(); + image.alt = "Chair spinning"; + document.body.appendChild(image); +</script>
diff --git a/third_party/blink/web_tests/media/track/track-css-user-settings-override-internal-settings.html b/third_party/blink/web_tests/media/track/track-css-user-settings-override-internal-settings.html index 5627716..f44025a 100644 --- a/third_party/blink/web_tests/media/track/track-css-user-settings-override-internal-settings.html +++ b/third_party/blink/web_tests/media/track/track-css-user-settings-override-internal-settings.html
@@ -13,26 +13,36 @@ video.oncanplaythrough = t.step_func_done(function() { var cue = textTrackCueElementByIndex(video, 0).firstChild; + var displayTree = textTrackCueElementByIndex(video, 0); var cueStyle = getComputedStyle(cue); + var displayTreeStyle = getComputedStyle(displayTree); // These are the expected default cue settings per spec // http://dev.w3.org/html5/webvtt/#applying-css-properties-to-webvtt-node-objects assert_equals(cueStyle.color, "rgb(255, 255, 255)"); assert_equals(cueStyle.backgroundColor, "rgba(0, 0, 0, 0.8)"); assert_equals(cueStyle.fontFamily, "sans-serif"); + assert_equals(displayTreeStyle.backgroundColor, "rgba(0, 0, 0, 0)"); + assert_equals(displayTreeStyle.padding, "0px"); // Apply user settings for color and font-size and verify that the other internal settings are retained. internals.settings.setTextTrackTextColor("purple"); internals.settings.setTextTrackTextSize("14px"); + internals.settings.setTextTrackWindowColor("rgba(0, 0, 0, 0.8)"); + internals.settings.setTextTrackWindowPadding("5px"); video.currentTime = 0.3; - cue = textTrackCueElementByIndex(video, 0).firstChild; - cueStyle = getComputedStyle(cue); + var cue = textTrackCueElementByIndex(video, 0).firstChild; + var displayTree = textTrackCueElementByIndex(video, 0); + var cueStyle = getComputedStyle(cue); + var displayTreeStyle = getComputedStyle(displayTree); assert_equals(cueStyle.color, "rgb(128, 0, 128)"); assert_equals(cueStyle.fontSize, "14px"); + assert_equals(displayTreeStyle.backgroundColor, "rgba(0, 0, 0, 0.8)"); + assert_equals(displayTreeStyle.padding, "5px"); // When there is no user setting specified for background-color and font-family, the internal settings are applied. assert_equals(cueStyle.backgroundColor, "rgba(0, 0, 0, 0.8)"); assert_equals(cueStyle.fontFamily, "sans-serif"); }); }); -</script> \ No newline at end of file +</script>
diff --git a/third_party/blink/web_tests/media/track/track-cue-rendering-snap-to-lines-not-set.html b/third_party/blink/web_tests/media/track/track-cue-rendering-snap-to-lines-not-set.html index d08e1f18..a92b0bc 100644 --- a/third_party/blink/web_tests/media/track/track-cue-rendering-snap-to-lines-not-set.html +++ b/third_party/blink/web_tests/media/track/track-cue-rendering-snap-to-lines-not-set.html
@@ -35,7 +35,7 @@ ]; var cueRenderingPosition = [ // Number of active cues 1. - [[0 ,100, "center"]], + [[0, 100, "center"]], [[0, 50, "center"]], [[0, 0, "start"]], [[0, 0, "end"]],
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png new file mode 100644 index 0000000..302ccbb --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png new file mode 100644 index 0000000..72b8ba2f --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png new file mode 100644 index 0000000..2a2b17a --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-expected.png deleted file mode 100644 index 7df4966..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png deleted file mode 100644 index ca051172..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png deleted file mode 100644 index b9f331a..0000000 --- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png new file mode 100644 index 0000000..302ccbb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png new file mode 100644 index 0000000..72b8ba2f --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png new file mode 100644 index 0000000..2a2b17a --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-image-expected.png deleted file mode 100644 index 9b0aff8d..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-image-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png deleted file mode 100644 index ca051172..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png deleted file mode 100644 index b9f331a..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png new file mode 100644 index 0000000..302ccbb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png new file mode 100644 index 0000000..72b8ba2f --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png new file mode 100644 index 0000000..2a2b17a --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-image-expected.png deleted file mode 100644 index 9b0aff8d..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-image-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png deleted file mode 100644 index ca051172..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png deleted file mode 100644 index b9f331a..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png new file mode 100644 index 0000000..302ccbb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png new file mode 100644 index 0000000..72b8ba2f --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png new file mode 100644 index 0000000..2a2b17a --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-image-expected.png deleted file mode 100644 index 9b0aff8d..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-image-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png deleted file mode 100644 index ca051172..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png deleted file mode 100644 index b9f331a..0000000 --- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png new file mode 100644 index 0000000..302ccbb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png new file mode 100644 index 0000000..72b8ba2f --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png new file mode 100644 index 0000000..2a2b17a --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-image-expected.png deleted file mode 100644 index 9b0aff8d..0000000 --- a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-image-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png deleted file mode 100644 index ca051172..0000000 --- a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png deleted file mode 100644 index b9f331a..0000000 --- a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png index d8c22a3f..1c857e81 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png index d8c22a3f..1c857e81 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png new file mode 100644 index 0000000..302ccbb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png new file mode 100644 index 0000000..72b8ba2f --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png new file mode 100644 index 0000000..2a2b17a --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-expected.png index 9b0aff8d..dfd5dd9b 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png deleted file mode 100644 index ca051172..0000000 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png index 812b4172..a3d35b18 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png deleted file mode 100644 index b9f331a..0000000 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png index 2e8ba71..1708a703 100644 --- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png index 2e8ba71..1708a703 100644 --- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png new file mode 100644 index 0000000..302ccbb --- /dev/null +++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png new file mode 100644 index 0000000..72b8ba2f --- /dev/null +++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png new file mode 100644 index 0000000..2a2b17a --- /dev/null +++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-expected.png index 7df4966..3fb2ae1 100644 --- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-image-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png deleted file mode 100644 index ca051172..0000000 --- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png index 1dde38a..5874dc2 100644 --- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png deleted file mode 100644 index b9f331a..0000000 --- a/third_party/blink/web_tests/platform/win/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png new file mode 100644 index 0000000..302ccbb --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png new file mode 100644 index 0000000..72b8ba2f --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-image-space-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png new file mode 100644 index 0000000..2a2b17a --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-expected.png deleted file mode 100644 index 7df4966..0000000 --- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-image-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png deleted file mode 100644 index ca051172..0000000 --- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/color-profile-mask-image-svg-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png deleted file mode 100644 index b9f331a..0000000 --- a/third_party/blink/web_tests/platform/win7/virtual/gpu-rasterization/images/ycbcr-with-cmyk-color-profile-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/web_tests/svg/custom/rect-calc-corner-radii-expected.svg b/third_party/blink/web_tests/svg/custom/rect-calc-corner-radii-expected.svg new file mode 100644 index 0000000..cbf6053 --- /dev/null +++ b/third_party/blink/web_tests/svg/custom/rect-calc-corner-radii-expected.svg
@@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500"> + <rect x="50" y="50" width="400" height="400" rx="0" ry="0" fill="#00ff00" /> + <rect x="150" y="100" width="200" height="300" rx="50" ry="50" fill="#0000ff" /> + <rect x="200" y="150" width="100" height="200" rx="50" ry="50" fill="#ff0000" /> +</svg>
diff --git a/third_party/blink/web_tests/svg/custom/rect-calc-corner-radii-expected.txt b/third_party/blink/web_tests/svg/custom/rect-calc-corner-radii-expected.txt new file mode 100644 index 0000000..210335f --- /dev/null +++ b/third_party/blink/web_tests/svg/custom/rect-calc-corner-radii-expected.txt
@@ -0,0 +1 @@ +CONSOLE ERROR: line 4: Error: <rect> attribute ry: A negative value is not valid. ("-100")
diff --git a/third_party/blink/web_tests/svg/custom/rect-calc-corner-radii.svg b/third_party/blink/web_tests/svg/custom/rect-calc-corner-radii.svg new file mode 100644 index 0000000..fe98961 --- /dev/null +++ b/third_party/blink/web_tests/svg/custom/rect-calc-corner-radii.svg
@@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500"> + <rect x="50" y="50" width="400" height="400" rx="calc(-50)" ry="calc(-50)" fill="#00ff00" /> + <rect x="150" y="100" width="200" height="300" rx="calc(20% - 50)" ry="50" fill="#0000ff" /> + <rect x="200" y="150" width="100" height="200" rx="50" ry="-100" fill="#ff0000" /> +</svg>
diff --git a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-button-negative-tabindex.html b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-button-negative-tabindex.html new file mode 100644 index 0000000..bccdec77 --- /dev/null +++ b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-button-negative-tabindex.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<script src="../../../../../resources/testharness.js"></script> +<script src="../../../../../resources/testharnessreport.js"></script> +<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/page/spatial_navigation.mojom.js"></script> +<script src="../../../../../fast/spatial-navigation/resources/mock-snav-service.js"></script> +<script src="../../../../../fast/spatial-navigation/resources/snav-testharness.js"></script> + +<style> + div { + width: 130px; + height: 130px; + border: 1px solid black; + } +</style> +<button tabindex="-1" id="unselectable">Unselectable</button> +<br> +<br> +<button id="selectable"">Selectable</button> + +<script> + const unselectable = document.getElementById("unselectable"); + const selectable = document.getElementById("selectable"); + + // This test checks that tabindex="-1" is effective on a button element, + // which overrides Element::IsKeyboardFocusable. + test(() => { + assert_true(!!window.internals); + + snav.triggerMove('Down'); + assert_equals(window.internals.interestedElement, + selectable, + "Expected interest to move to |selectable| button."); + + snav.triggerMove('Up'); + assert_equals(window.internals.interestedElement, + selectable, + "Expected interest to stay on |selectable| button."); + }, "Cannot navigate to button with tabindex'-1'"); +</script>
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png index aeb4daf..bb4b4529 100644 --- a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png +++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png index 8d371ab..e433e7a 100644 --- a/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png +++ b/third_party/blink/web_tests/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/isolated_world_csp/http/tests/security/isolatedWorld/isolated-world-eval-csp-expected.txt b/third_party/blink/web_tests/virtual/isolated_world_csp/http/tests/security/isolatedWorld/isolated-world-eval-csp-expected.txt new file mode 100644 index 0000000..af40f2b54 --- /dev/null +++ b/third_party/blink/web_tests/virtual/isolated_world_csp/http/tests/security/isolatedWorld/isolated-world-eval-csp-expected.txt
@@ -0,0 +1,14 @@ +CONSOLE MESSAGE: line 38: Testing main world. Eval should be blocked by main world CSP. +CONSOLE MESSAGE: line 7: EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'". + +CONSOLE MESSAGE: line 13: PASS: eval blocked as expected. +CONSOLE MESSAGE: line 44: Testing isolated world with no csp. Eval should be allowed. +CONSOLE MESSAGE: PASS: eval allowed as expected. +CONSOLE MESSAGE: line 55: Testing isolated world with strict csp. +CONSOLE MESSAGE: line 58: internals.runtimeFlags.isolatedWorldCSPEnabled is true +CONSOLE MESSAGE: EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'none'". + +CONSOLE MESSAGE: PASS: eval blocked as expected. +CONSOLE MESSAGE: line 68: Testing isolated world with permissive csp. +CONSOLE MESSAGE: PASS: eval allowed as expected. +This tests the handling of unsafe-eval CSP checks and its interaction with the isolated world CSP.
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor.any-expected.txt similarity index 100% rename from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor-expected.txt rename to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor.any-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor.any.worker-expected.txt similarity index 100% copy from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor-expected.txt copy to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-entry-constructor.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-errors-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-errors.any-expected.txt similarity index 100% rename from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-errors-expected.txt rename to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-errors.any-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-errors-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-errors.any.worker-expected.txt similarity index 100% copy from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-errors-expected.txt copy to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-errors.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-l3-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-l3.any-expected.txt similarity index 100% rename from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-l3-expected.txt rename to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-l3.any-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-l3-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-l3.any.worker-expected.txt similarity index 100% copy from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-l3-expected.txt copy to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-l3.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-measure-return-objects-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-measure-return-objects.any-expected.txt similarity index 100% rename from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-measure-return-objects-expected.txt rename to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-measure-return-objects.any-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-measure-return-objects-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-measure-return-objects.any.worker-expected.txt similarity index 100% copy from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-measure-return-objects-expected.txt copy to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/mark-measure-return-objects.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-l3-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-l3.any-expected.txt similarity index 100% rename from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-l3-expected.txt rename to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-l3.any-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-l3-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-l3.any.worker-expected.txt similarity index 100% copy from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-l3-expected.txt copy to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-l3.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-with-dict-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-with-dict.any-expected.txt similarity index 100% rename from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-with-dict-expected.txt rename to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-with-dict.any-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-with-dict-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-with-dict.any.worker-expected.txt similarity index 100% copy from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-with-dict-expected.txt copy to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/measure-with-dict.any.worker-expected.txt
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail.any-expected.txt similarity index 90% rename from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail-expected.txt rename to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail.any-expected.txt index 92ca97d75..40cdb1cd 100644 --- a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail-expected.txt +++ b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail.any-expected.txt
@@ -3,14 +3,14 @@ FAIL The detail property in the mark method should be structured-clone. Cannot read property 'detail' of null FAIL When accessing detail from a mark entry and the detail is not provided, just return a null value. Cannot read property 'detail' of null FAIL Mark: Throw an exception when the detail property cannot be structured-serialized. assert_throws: Trying to structured-serialize a Symbol. function "()=>{ - new PerformanceMark("A", { detail }); - }" did not throw + new PerformanceMark("A", { detail }); + }" did not throw FAIL The detail property in the measure method should be structured-clone. Cannot read property 'detail' of null FAIL The detail property in the measure method should be the same reference. Cannot read property 'detail' of null FAIL When accessing detail from a measure entry and the detail is not provided, just return a null value. Cannot read property 'detail' of null FAIL Measure: Throw an exception when the detail property cannot be structured-serialized. assert_throws: Trying to structured-serialize a Symbol. function "()=>{ - performance.measure("A", { detail }); - }" did not throw + performance.measure("A", { detail }); + }" did not throw FAIL The detail object is cloned when passed to mark API. Cannot read property 'detail' of null Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail-expected.txt b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail.any.worker-expected.txt similarity index 90% copy from third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail-expected.txt copy to third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail.any.worker-expected.txt index 92ca97d75..40cdb1cd 100644 --- a/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail-expected.txt +++ b/third_party/blink/web_tests/virtual/user-timing-l2/external/wpt/user-timing/structured-serialize-detail.any.worker-expected.txt
@@ -3,14 +3,14 @@ FAIL The detail property in the mark method should be structured-clone. Cannot read property 'detail' of null FAIL When accessing detail from a mark entry and the detail is not provided, just return a null value. Cannot read property 'detail' of null FAIL Mark: Throw an exception when the detail property cannot be structured-serialized. assert_throws: Trying to structured-serialize a Symbol. function "()=>{ - new PerformanceMark("A", { detail }); - }" did not throw + new PerformanceMark("A", { detail }); + }" did not throw FAIL The detail property in the measure method should be structured-clone. Cannot read property 'detail' of null FAIL The detail property in the measure method should be the same reference. Cannot read property 'detail' of null FAIL When accessing detail from a measure entry and the detail is not provided, just return a null value. Cannot read property 'detail' of null FAIL Measure: Throw an exception when the detail property cannot be structured-serialized. assert_throws: Trying to structured-serialize a Symbol. function "()=>{ - performance.measure("A", { detail }); - }" did not throw + performance.measure("A", { detail }); + }" did not throw FAIL The detail object is cloned when passed to mark API. Cannot read property 'detail' of null Harness: the test ran to completion.
diff --git a/third_party/libjingle_xmpp/BUILD.gn b/third_party/libjingle_xmpp/BUILD.gn index 6eec6ca..3364a1a3 100644 --- a/third_party/libjingle_xmpp/BUILD.gn +++ b/third_party/libjingle_xmpp/BUILD.gn
@@ -53,11 +53,6 @@ deps = [ "//base", - - # TODO(mbonadei): The dependency on the TQ is not directly - # needed but removing it causes a linker error that it is - # difficult to track down. - "//third_party/webrtc_overrides:task_queue_impl", ] public_deps = [ "//third_party/expat", @@ -104,11 +99,6 @@ "//net", "//third_party/webrtc/rtc_base/third_party/base64", "//third_party/webrtc/rtc_base/third_party/sigslot", - - # TODO(mbonadei): The dependency on the TQ is not directly - # needed but removing it causes a linker error that it is - # difficult to track down. - "//third_party/webrtc_overrides:task_queue_impl", ] public_deps = [ ":rtc_task_runner", @@ -138,7 +128,6 @@ "//base/test:test_support", "//testing/gtest", "//third_party/webrtc/rtc_base:rtc_base", - "//third_party/webrtc_overrides:task_queue_impl", ] sources = [
diff --git a/third_party/metrics_proto/BUILD.gn b/third_party/metrics_proto/BUILD.gn index 2e5c90c..cef117f 100644 --- a/third_party/metrics_proto/BUILD.gn +++ b/third_party/metrics_proto/BUILD.gn
@@ -29,6 +29,7 @@ "ukm/report.proto", "ukm/source.proto", "user_action_event.proto", + "user_demographics.proto", ] proto_in_dir = "." }
diff --git a/third_party/metrics_proto/README.chromium b/third_party/metrics_proto/README.chromium index 03cf8ea..dfaf4d2 100644 --- a/third_party/metrics_proto/README.chromium +++ b/third_party/metrics_proto/README.chromium
@@ -1,8 +1,8 @@ Name: Metrics Protos Short Name: metrics_proto URL: This is the canonical public repository -Version: 255196992 -Date: 2019/06/26 UTC +Version: 257643598 +Date: 2019/07/11 UTC License: BSD Security Critical: Yes
diff --git a/third_party/metrics_proto/chrome_user_metrics_extension.proto b/third_party/metrics_proto/chrome_user_metrics_extension.proto index d4a3920..361aeb7 100644 --- a/third_party/metrics_proto/chrome_user_metrics_extension.proto +++ b/third_party/metrics_proto/chrome_user_metrics_extension.proto
@@ -24,8 +24,9 @@ import "trace_log.proto"; import "translate_event.proto"; import "user_action_event.proto"; +import "user_demographics.proto"; -// Next tag: 21 +// Next tag: 22 message ChromeUserMetricsExtension { // The product (i.e. end user application) for a given UMA log. enum Product { @@ -66,6 +67,11 @@ // Information about the user's browser and system configuration. optional SystemProfileProto system_profile = 3; + // The user's demographic information. This data is made available to Chrome + // via syncable priority pref, so is only available if the user is signed-in + // and syncing. + optional UserDemographicsProto user_demographics = 21; + // This message will log one or more of the following event types: repeated UserActionEventProto user_action_event = 4; repeated OmniboxEventProto omnibox_event = 5;
diff --git a/third_party/metrics_proto/system_profile.proto b/third_party/metrics_proto/system_profile.proto index a17a8ce4..5bee73a 100644 --- a/third_party/metrics_proto/system_profile.proto +++ b/third_party/metrics_proto/system_profile.proto
@@ -15,7 +15,7 @@ // Stores information about the user's brower and system configuration. // The system configuration fields are recorded once per client session. -// Next tag: 30 +// Next tag: 31 message SystemProfileProto { // The time when the client was compiled/linked, in seconds since the epoch. optional int64 build_timestamp = 1; @@ -130,7 +130,7 @@ optional OS os = 5; // Information on the user's hardware. - // Next tag: 19 + // Next tag: 20 message Hardware { // CPU architecture. Taken from uname -m and modified in Chromium logic. // Common options are: x86, x86_64, armv7l, armv8l, aarch64. @@ -184,6 +184,18 @@ optional float max_dpi_x = 9; optional float max_dpi_y = 10; + // Device form factors. + enum FormFactor { + FORM_FACTOR_UNKNOWN = 0; + FORM_FACTOR_DESKTOP = 1; + FORM_FACTOR_PHONE = 2; + FORM_FACTOR_TABLET = 3; + FORM_FACTOR_KIOSK = 4; + } + + // The device form factor. + optional FormFactor form_factor = 19; + // Information on the CPU obtained by CPUID. message CPU { // A 12 character string naming the vendor, e.g. "GeniuneIntel". @@ -298,6 +310,62 @@ } optional Bluetooth bluetooth = 11; + // Information about connected USB devices on Chrome OS systems. + message USB { + // The number of USB buses on the system. + optional uint32 bus_count = 1; + + // Describes an attached USB device. + message USBDevice { + // Vendor ID (assigned by USB-IF). + optional fixed32 vendor_id = 1; + + // Product ID (assigned by manufacturer). + optional fixed32 product_id = 2; + + // Base Class as defined by USB-IF. + optional uint32 device_class = 3; + + // SubClass as defined by USB-IF. + optional uint32 device_subclass = 4; + + // The device release number with the decimal shifted out. The bcdDevice + // field from which this value originates is a 2-byte BCD in the range + // [00.00 - 99.99]. This value is multiplied by 100 to remove the + // decimal (device_release_number = bcdDevice * 100). + optional uint32 device_release_number = 5; + + // A subset of information from the interface descriptors. + message InterfaceDescriptor { + // Base Class as defined by USB-IF. + optional uint32 interface_class = 1; + + // SubClass as defined by USB-IF. + optional uint32 interface_subclass = 2; + + // The configuration value for the configuration that holds this + // interface. Typically, all interfaces will belong to the same + // configuration. + optional uint32 configuration_value = 3; + } + repeated InterfaceDescriptor interface_descriptors = 6; + + // The number of hubs above this device, including the root hub. + optional uint32 hops_from_root = 7; + + // The vendor ID of the parent hub, if present. + optional fixed32 parent_vendor_id = 8; + + // The product ID of the parent hub, if present. + optional fixed32 parent_product_id = 9; + + // If this device is a hub, the number of ports on this hub. + optional uint32 port_count = 10; + } + repeated USBDevice usb_devices = 2; + } + optional USB usb = 30; + // Whether the internal display produces touch events. Omitted if unknown. // Logged on ChromeOS only. optional bool internal_display_supports_touch = 14;
diff --git a/third_party/metrics_proto/user_demographics.proto b/third_party/metrics_proto/user_demographics.proto new file mode 100644 index 0000000..0a1cc7f --- /dev/null +++ b/third_party/metrics_proto/user_demographics.proto
@@ -0,0 +1,46 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +option java_outer_classname = "UserDemographicsProtos"; +option java_package = "org.chromium.components.metrics"; + +package metrics; + +// Demographics information about the user. +// +// This data is drawn from the signed-in user's GAIA id and is provided to +// Chrome via syncable priority pref. +// +// Next tag: 3 +message UserDemographicsProto { + // The (noisy) year of birth specified by the user. The value reported in this + // field cannot safely be interpreted as the true value for the user; it may + // be offset by a randomly chosen number of years from [-2, +2]. + optional int32 birth_year = 1; + + // The supported gender identifiers. These values correspond to those offered + // in the "Gender" section of the Google Account settings. Note that these + // values deliberately do not address the rich spectrum of possible gender + // identies with high granalurity because we do not want these values to be + // highly identifying. + enum Gender { + // The default value for clients that do not have any gender information as + // well as for those users who prefer not to disclose a gender and those who + // provide a custom gender. + GENDER_UNKNOWN_OR_OTHER = 0; + // The user specified that they prefer to be referred to as male. + GENDER_MALE = 1; + // The user specified that they prefer to be referred to as female. + GENDER_FEMALE = 2; + } + + // The gender specified by the user. If the user's gender is unknown or non- + // binary, this field will be omitted, corresponding to a default + // value of GENDER_UNKNOWN_OR_OTHER. + optional Gender gender = 2; +}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple.html b/third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple.html index c170faf..5275d0e 100644 --- a/third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple.html +++ b/third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple.html
@@ -100,8 +100,6 @@ position: absolute; right: 0; top: 0; - /* For rounded corners: http://jsbin.com/temexa/4. */ - transform: translate3d(0, 0, 0); } .ripple {
diff --git a/third_party/webrtc_overrides/BUILD.gn b/third_party/webrtc_overrides/BUILD.gn index 61048ce8..4483d30 100644 --- a/third_party/webrtc_overrides/BUILD.gn +++ b/third_party/webrtc_overrides/BUILD.gn
@@ -61,7 +61,6 @@ ] deps = [ ":metrics", - ":task_queue_impl", "//base", "//third_party/webrtc/rtc_base", "//third_party/webrtc/system_wrappers", @@ -100,19 +99,6 @@ ] } -# TODO(bugs.webrtc.org/10284): Remove when TaskQueue factory is propagated -# explicetely to all components that needs it. -source_set("task_queue_impl") { - sources = [ - "task_queue_impl.cc", - ] - configs += [ "//third_party/webrtc:library_impl_config" ] - deps = [ - ":task_queue_factory", - "//third_party/webrtc/api/task_queue", - ] -} - source_set("task_queue_factory") { sources = [ "task_queue_factory.cc",
diff --git a/third_party/webrtc_overrides/task_queue_impl.cc b/third_party/webrtc_overrides/task_queue_impl.cc deleted file mode 100644 index 0d9b158f..0000000 --- a/third_party/webrtc_overrides/task_queue_impl.cc +++ /dev/null
@@ -1,18 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <memory> - -#include "third_party/webrtc/api/task_queue/task_queue_factory.h" -#include "third_party/webrtc_overrides/task_queue_factory.h" - -namespace webrtc { - -// Temporary link-time injection for the webrtc TaskQueueFactory implementation. -// This will not be needed once bugs.webrtc.org/10284 is resolved. -std::unique_ptr<TaskQueueFactory> CreateDefaultTaskQueueFactory() { - return CreateWebRtcTaskQueueFactory(); -} - -} // namespace webrtc
diff --git a/tools/fuchsia/local-sdk.py b/tools/fuchsia/local-sdk.py index 4cee6b6..a95d6b4c 100755 --- a/tools/fuchsia/local-sdk.py +++ b/tools/fuchsia/local-sdk.py
@@ -64,7 +64,7 @@ EnsureEmptyDir(output_dir) original_dir = os.getcwd() - fuchsia_root = args[0] + fuchsia_root = os.path.abspath(args[0]) merged_manifest = None manifest_parts = set()
diff --git a/tools/grit/grit.py b/tools/grit/grit.py index d8074e4..98b99bb 100755 --- a/tools/grit/grit.py +++ b/tools/grit/grit.py
@@ -6,6 +6,8 @@ '''Bootstrapping for GRIT. ''' +from __future__ import print_function + import sys import grit.grit_runner
diff --git a/tools/grit/grit/clique.py b/tools/grit/grit/clique.py index f5549d8..cd5b44c 100644 --- a/tools/grit/grit/clique.py +++ b/tools/grit/grit/clique.py
@@ -6,6 +6,8 @@ collections of cliques (uber-cliques). ''' +from __future__ import print_function + import re import types @@ -206,10 +208,12 @@ ''' def Callback(id, structure): if id not in self.cliques_: - if debug: print "Ignoring translation #%s" % id + if debug: + print("Ignoring translation #%s" % id) return - if debug: print "Adding translation #%s" % id + if debug: + print("Adding translation #%s" % id) # We fetch placeholder information from the original message (the XTB file # only contains placeholder names). @@ -468,8 +472,8 @@ original = self.MessageForLanguage(self.source_language, False) if len(original.GetPlaceholders()) != len(translation.GetPlaceholders()): - print ("ERROR: '%s' translation of message id %s does not match" % - (language, translation.GetId())) + print("ERROR: '%s' translation of message id %s does not match" % + (language, translation.GetId())) assert False transl_msg = tclib.Translation(id=self.GetId(), @@ -478,7 +482,7 @@ if (self.custom_type and not self.custom_type.ValidateAndModify(language, transl_msg)): - print "WARNING: %s translation failed validation: %s" % ( - language, transl_msg.GetId()) + print("WARNING: %s translation failed validation: %s" % + (language, transl_msg.GetId())) self.clique[language] = transl_msg
diff --git a/tools/grit/grit/clique_unittest.py b/tools/grit/grit/clique_unittest.py index ff2c3a31..99f3f11 100755 --- a/tools/grit/grit/clique_unittest.py +++ b/tools/grit/grit/clique_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grit.clique''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/constants.py b/tools/grit/grit/constants.py index 02f2928..3a05c11 100644 --- a/tools/grit/grit/constants.py +++ b/tools/grit/grit/constants.py
@@ -5,6 +5,7 @@ '''Constant definitions for GRIT. ''' +from __future__ import print_function # This is the Icelandic noun meaning "grit" and is used to check that our # input files are in the correct encoding. The middle character gets encoded
diff --git a/tools/grit/grit/exception.py b/tools/grit/grit/exception.py index 1a1bed34..ad7f087 100644 --- a/tools/grit/grit/exception.py +++ b/tools/grit/grit/exception.py
@@ -5,6 +5,8 @@ '''Exception types for GRIT. ''' +from __future__ import print_function + class Base(Exception): '''A base exception that uses the class's docstring in addition to any user-provided message as the body of the Base.
diff --git a/tools/grit/grit/extern/BogoFP.py b/tools/grit/grit/extern/BogoFP.py index 5af21fd..fc90145 100644 --- a/tools/grit/grit/extern/BogoFP.py +++ b/tools/grit/grit/extern/BogoFP.py
@@ -9,6 +9,7 @@ grit.py -h grit.extern.BogoFP xmb /tmp/foo """ +from __future__ import print_function import grit.extern.FP
diff --git a/tools/grit/grit/extern/FP.py b/tools/grit/grit/extern/FP.py index 0932f75..f4ec4d9 100644 --- a/tools/grit/grit/extern/FP.py +++ b/tools/grit/grit/extern/FP.py
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from __future__ import print_function + try: import hashlib _new_md5 = hashlib.md5 @@ -14,7 +16,7 @@ Usage: from extern import FP - print 'Fingerprint is %ld' % FP.FingerPrint('Hello world!') + print('Fingerprint is %ld' % FP.FingerPrint('Hello world!')) """
diff --git a/tools/grit/grit/extern/tclib.py b/tools/grit/grit/extern/tclib.py index bbefd7f..9952a87 100644 --- a/tools/grit/grit/extern/tclib.py +++ b/tools/grit/grit/extern/tclib.py
@@ -10,6 +10,8 @@ # for creating Windows .rc and .h files. These are the only parts needed by # the Chrome build process. +from __future__ import print_function + from grit.extern import FP # This module assumes that within a bundle no two messages can have the
diff --git a/tools/grit/grit/format/android_xml.py b/tools/grit/grit/format/android_xml.py index 2d878673..c969eae 100644 --- a/tools/grit/grit/format/android_xml.py +++ b/tools/grit/grit/format/android_xml.py
@@ -59,6 +59,8 @@ </plurals> """ +from __future__ import print_function + import os import re import types
diff --git a/tools/grit/grit/format/android_xml_unittest.py b/tools/grit/grit/format/android_xml_unittest.py index 6f496b61..1d1a7847 100755 --- a/tools/grit/grit/format/android_xml_unittest.py +++ b/tools/grit/grit/format/android_xml_unittest.py
@@ -5,6 +5,8 @@ """Unittest for android_xml.py.""" +from __future__ import print_function + import os import StringIO import sys
diff --git a/tools/grit/grit/format/c_format.py b/tools/grit/grit/format/c_format.py index 6d5d9e6..e944b7f 100644 --- a/tools/grit/grit/format/c_format.py +++ b/tools/grit/grit/format/c_format.py
@@ -5,6 +5,8 @@ """Formats as a .C file for compilation. """ +from __future__ import print_function + import os import re import types
diff --git a/tools/grit/grit/format/c_format_unittest.py b/tools/grit/grit/format/c_format_unittest.py index ba1c5c71..dd50788 100755 --- a/tools/grit/grit/format/c_format_unittest.py +++ b/tools/grit/grit/format/c_format_unittest.py
@@ -6,6 +6,8 @@ """Unittest for c_format.py. """ +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/format/chrome_messages_json.py b/tools/grit/grit/format/chrome_messages_json.py index 43853547..6af08b45 100644 --- a/tools/grit/grit/format/chrome_messages_json.py +++ b/tools/grit/grit/format/chrome_messages_json.py
@@ -5,6 +5,8 @@ """Formats as a .json file that can be used to localize Google Chrome extensions.""" +from __future__ import print_function + from json import JSONEncoder import re import types
diff --git a/tools/grit/grit/format/chrome_messages_json_unittest.py b/tools/grit/grit/format/chrome_messages_json_unittest.py index ae9c7a6..87b6588 100755 --- a/tools/grit/grit/format/chrome_messages_json_unittest.py +++ b/tools/grit/grit/format/chrome_messages_json_unittest.py
@@ -6,6 +6,8 @@ """Unittest for chrome_messages_json.py. """ +from __future__ import print_function + import json import os import sys
diff --git a/tools/grit/grit/format/data_pack.py b/tools/grit/grit/format/data_pack.py index 3a39aaf..d54f4aa 100755 --- a/tools/grit/grit/format/data_pack.py +++ b/tools/grit/grit/format/data_pack.py
@@ -7,6 +7,8 @@ files. """ +from __future__ import print_function + import collections import exceptions import os @@ -114,7 +116,7 @@ return struct.unpack('<HI', data[offset:offset + kIndexEntrySize]) prev_resource_id, prev_offset = entry_at_index(0) - for i in xrange(1, resource_count + 1): + for i in range(1, resource_count + 1): resource_id, offset = entry_at_index(i) resources[prev_resource_id] = data[prev_offset:offset] prev_resource_id, prev_offset = resource_id, offset @@ -127,7 +129,7 @@ return struct.unpack('<HH', data[offset:offset + kAliasEntrySize]) aliases = {} - for i in xrange(alias_count): + for i in range(alias_count): resource_id, index = alias_at_index(i) aliased_id = entry_at_index(index)[0] aliases[resource_id] = aliased_id @@ -276,7 +278,7 @@ if key not in whitelist] if not suppress_removed_key_output: for key in removed_keys: - print 'RePackFromDataPackStrings Removed Key:', key + print('RePackFromDataPackStrings Removed Key:', key) else: resources.update(input_resources) @@ -292,7 +294,7 @@ WriteDataPack(data, 'datapack1.pak', UTF8) data2 = {1000: 'test', 5: 'five'} WriteDataPack(data2, 'datapack2.pak', UTF8) - print 'wrote datapack1 and datapack2 to current directory.' + print('wrote datapack1 and datapack2 to current directory.') if __name__ == '__main__':
diff --git a/tools/grit/grit/format/data_pack_unittest.py b/tools/grit/grit/format/data_pack_unittest.py index ba36590..4bb60a2 100755 --- a/tools/grit/grit/format/data_pack_unittest.py +++ b/tools/grit/grit/format/data_pack_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for grit.format.data_pack''' +from __future__ import print_function import os import sys
diff --git a/tools/grit/grit/format/gen_predetermined_ids.py b/tools/grit/grit/format/gen_predetermined_ids.py index 57a6047..1b585f7 100755 --- a/tools/grit/grit/format/gen_predetermined_ids.py +++ b/tools/grit/grit/format/gen_predetermined_ids.py
@@ -9,6 +9,8 @@ a while and its output checked in. See tools/gritsettings/README.md for details. """ +from __future__ import print_function + import fnmatch import os import re @@ -128,7 +130,7 @@ output_resource_map = GenerateResourceMapping(original_resources, ordered_resource_ids) for res_id in sorted(output_resource_map.keys()): - print "{} {}".format(output_resource_map[res_id], res_id) + print(output_resource_map[res_id], res_id) def main(argv):
diff --git a/tools/grit/grit/format/gen_predetermined_ids_unittest.py b/tools/grit/grit/format/gen_predetermined_ids_unittest.py index 0866147..86820efb 100755 --- a/tools/grit/grit/format/gen_predetermined_ids_unittest.py +++ b/tools/grit/grit/format/gen_predetermined_ids_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for the gen_predetermined_ids module.''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/format/gzip_string.py b/tools/grit/grit/format/gzip_string.py index 4f54aac1..4f8bc64 100644 --- a/tools/grit/grit/format/gzip_string.py +++ b/tools/grit/grit/format/gzip_string.py
@@ -3,6 +3,9 @@ # found in the LICENSE file. """Provides gzip utilities for strings. """ + +from __future__ import print_function + import cStringIO import gzip import subprocess
diff --git a/tools/grit/grit/format/gzip_string_unittest.py b/tools/grit/grit/format/gzip_string_unittest.py index a920693..f7e53fd 100755 --- a/tools/grit/grit/format/gzip_string_unittest.py +++ b/tools/grit/grit/format/gzip_string_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grit.format.gzip_string''' +from __future__ import print_function + import gzip import io import os
diff --git a/tools/grit/grit/format/html_inline.py b/tools/grit/grit/format/html_inline.py index 88ad571..7e44da7 100755 --- a/tools/grit/grit/format/html_inline.py +++ b/tools/grit/grit/format/html_inline.py
@@ -10,6 +10,8 @@ dependencies. It recursively inlines the included files. """ +from __future__ import print_function + import os import re import sys @@ -587,8 +589,8 @@ def main(): if len(sys.argv) <= 2: - print "Flattens a HTML file by inlining its external resources.\n" - print "html_inline.py inputfile outputfile" + print("Flattens a HTML file by inlining its external resources.\n") + print("html_inline.py inputfile outputfile") else: InlineToFile(sys.argv[1], sys.argv[2], None)
diff --git a/tools/grit/grit/format/html_inline_unittest.py b/tools/grit/grit/format/html_inline_unittest.py index 96f1e26..37c6339f 100755 --- a/tools/grit/grit/format/html_inline_unittest.py +++ b/tools/grit/grit/format/html_inline_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for grit.format.html_inline''' +from __future__ import print_function import os import re
diff --git a/tools/grit/grit/format/minifier.py b/tools/grit/grit/format/minifier.py index a45b5545..011cbea 100644 --- a/tools/grit/grit/format/minifier.py +++ b/tools/grit/grit/format/minifier.py
@@ -3,6 +3,8 @@ # found in the LICENSE file. """Framework for stripping whitespace and comments from resource files""" +from __future__ import print_function + from os import path import subprocess import sys @@ -26,7 +28,7 @@ stderr=subprocess.PIPE) (stdout, stderr) = p.communicate(source) if p.returncode != 0: - print 'Minification failed for %s' % filename - print stderr + print('Minification failed for %s' % filename) + print(stderr) sys.exit(p.returncode) return stdout
diff --git a/tools/grit/grit/format/policy_templates_json.py b/tools/grit/grit/format/policy_templates_json.py index f4531f5..2f9330b 100644 --- a/tools/grit/grit/format/policy_templates_json.py +++ b/tools/grit/grit/format/policy_templates_json.py
@@ -5,6 +5,8 @@ """Translates policy_templates.json files. """ +from __future__ import print_function + from grit.node import structure
diff --git a/tools/grit/grit/format/policy_templates_json_unittest.py b/tools/grit/grit/format/policy_templates_json_unittest.py index d3816ad30..64eae1b 100755 --- a/tools/grit/grit/format/policy_templates_json_unittest.py +++ b/tools/grit/grit/format/policy_templates_json_unittest.py
@@ -7,6 +7,8 @@ """Unittest for policy_templates_json.py. """ +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/format/rc.py b/tools/grit/grit/format/rc.py index e7d716d3..7037278 100644 --- a/tools/grit/grit/format/rc.py +++ b/tools/grit/grit/format/rc.py
@@ -5,6 +5,8 @@ '''Support for formatting an RC file for compilation. ''' +from __future__ import print_function + import os import types import re @@ -260,7 +262,7 @@ if _LANGUAGE_CHARSET_PAIR.has_key(language): return _LANGUAGE_CHARSET_PAIR[language] if language != 'no-specific-language': - print 'Warning:GetLangCharsetPair() found undefined language %s' % language + print('Warning:GetLangCharsetPair() found undefined language %s' % language) return '' def GetLangDirectivePair(language): @@ -271,7 +273,7 @@ # function should only get called when output is being formatted, # and at that point we would not want to get # 'no-specific-language' passed as the language. - print 'Warning:GetLangDirectivePair() found undefined language %s' % language + print('Warning:GetLangDirectivePair() found undefined language %s' % language) return 'unknown language: see tools/grit/format/rc.py' def GetLangIdHex(language): @@ -280,7 +282,7 @@ lang_id = '0x' + langcharset[0:4] return lang_id if language != 'no-specific-language': - print 'Warning:GetLangIdHex() found undefined language %s' % language + print('Warning:GetLangIdHex() found undefined language %s' % language) return '' @@ -290,7 +292,7 @@ charset_decimal = int(langcharset[4:], 16) return str(charset_decimal) if language != 'no-specific-language': - print 'Warning:GetCharsetIdDecimal() found undefined language %s' % language + print('Warning:GetCharsetIdDecimal() found undefined language %s' % language) return ''
diff --git a/tools/grit/grit/format/rc_header.py b/tools/grit/grit/format/rc_header.py index da2f1565..5a789fb 100644 --- a/tools/grit/grit/format/rc_header.py +++ b/tools/grit/grit/format/rc_header.py
@@ -5,6 +5,8 @@ '''Item formatters for RC headers. ''' +from __future__ import print_function + from grit.node import message
diff --git a/tools/grit/grit/format/rc_header_unittest.py b/tools/grit/grit/format/rc_header_unittest.py index f709f934..ab2d16d 100755 --- a/tools/grit/grit/format/rc_header_unittest.py +++ b/tools/grit/grit/format/rc_header_unittest.py
@@ -8,6 +8,8 @@ # GRD samples exceed the 80 character limit. # pylint: disable-msg=C6310 +from __future__ import print_function + import os import sys import unittest
diff --git a/tools/grit/grit/format/rc_unittest.py b/tools/grit/grit/format/rc_unittest.py index 497f315c..43714ad62 100755 --- a/tools/grit/grit/format/rc_unittest.py +++ b/tools/grit/grit/format/rc_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grit.format.rc''' +from __future__ import print_function + import os import re import sys
diff --git a/tools/grit/grit/format/resource_map.py b/tools/grit/grit/format/resource_map.py index c9a73c46..95a8b83 100644 --- a/tools/grit/grit/format/resource_map.py +++ b/tools/grit/grit/format/resource_map.py
@@ -6,6 +6,8 @@ resource_map_source files. A resource map is a mapping between resource names (string) and the internal resource ID.''' +from __future__ import print_function + import os from functools import partial
diff --git a/tools/grit/grit/format/resource_map_unittest.py b/tools/grit/grit/format/resource_map_unittest.py index cd290a71..ec423193 100755 --- a/tools/grit/grit/format/resource_map_unittest.py +++ b/tools/grit/grit/format/resource_map_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grit.format.resource_map''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/gather/admin_template.py b/tools/grit/grit/gather/admin_template.py index 1b8340a..15876b4 100644 --- a/tools/grit/grit/gather/admin_template.py +++ b/tools/grit/grit/gather/admin_template.py
@@ -5,6 +5,8 @@ '''Gatherer for administrative template files. ''' +from __future__ import print_function + import re from grit.gather import regexp
diff --git a/tools/grit/grit/gather/admin_template_unittest.py b/tools/grit/grit/gather/admin_template_unittest.py index c63c08f..ff065c3 100755 --- a/tools/grit/grit/gather/admin_template_unittest.py +++ b/tools/grit/grit/gather/admin_template_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for the admin template gatherer.''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/gather/chrome_html.py b/tools/grit/grit/gather/chrome_html.py index 5e90980..a0d6c47 100644 --- a/tools/grit/grit/gather/chrome_html.py +++ b/tools/grit/grit/gather/chrome_html.py
@@ -14,6 +14,8 @@ referencing all available images. """ +from __future__ import print_function + import os import re
diff --git a/tools/grit/grit/gather/chrome_html_unittest.py b/tools/grit/grit/gather/chrome_html_unittest.py index f21caf3..5406a8c 100755 --- a/tools/grit/grit/gather/chrome_html_unittest.py +++ b/tools/grit/grit/gather/chrome_html_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for grit.gather.chrome_html''' +from __future__ import print_function import os import re
diff --git a/tools/grit/grit/gather/chrome_scaled_image.py b/tools/grit/grit/gather/chrome_scaled_image.py index 91116ab..d077274 100644 --- a/tools/grit/grit/gather/chrome_scaled_image.py +++ b/tools/grit/grit/gather/chrome_scaled_image.py
@@ -5,6 +5,8 @@ '''Gatherer for <structure type="chrome_scaled_image">. ''' +from __future__ import print_function + import os import struct
diff --git a/tools/grit/grit/gather/chrome_scaled_image_unittest.py b/tools/grit/grit/gather/chrome_scaled_image_unittest.py index 6a6b3a4..cbc5b815 100755 --- a/tools/grit/grit/gather/chrome_scaled_image_unittest.py +++ b/tools/grit/grit/gather/chrome_scaled_image_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for ChromeScaledImage.''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/gather/interface.py b/tools/grit/grit/gather/interface.py index 5d3ef1d..6149167 100644 --- a/tools/grit/grit/gather/interface.py +++ b/tools/grit/grit/gather/interface.py
@@ -5,6 +5,7 @@ '''Interface for all gatherers. ''' +from __future__ import print_function import os.path import types
diff --git a/tools/grit/grit/gather/json_loader.py b/tools/grit/grit/gather/json_loader.py index ca1f435..ee0d932b 100644 --- a/tools/grit/grit/gather/json_loader.py +++ b/tools/grit/grit/gather/json_loader.py
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from __future__ import print_function from grit.gather import interface
diff --git a/tools/grit/grit/gather/policy_json.py b/tools/grit/grit/gather/policy_json.py index 6e67212..0aee2c6d 100644 --- a/tools/grit/grit/gather/policy_json.py +++ b/tools/grit/grit/gather/policy_json.py
@@ -5,6 +5,8 @@ '''Support for "policy_templates.json" format used by the policy template generator as a source for generating ADM,ADMX,etc files.''' +from __future__ import print_function + import json import types import sys @@ -275,7 +277,7 @@ self.text_ = self._LoadInputFile() if util.IsExtraVerbose(): - print self.text_ + print(self.text_) self.data = eval(self.text_)
diff --git a/tools/grit/grit/gather/policy_json_unittest.py b/tools/grit/grit/gather/policy_json_unittest.py index 187dac1c..b48e7fc 100755 --- a/tools/grit/grit/gather/policy_json_unittest.py +++ b/tools/grit/grit/gather/policy_json_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grit.gather.policy_json''' +from __future__ import print_function + import json import os import re
diff --git a/tools/grit/grit/gather/rc.py b/tools/grit/grit/gather/rc.py index a332758..03135bdd 100644 --- a/tools/grit/grit/gather/rc.py +++ b/tools/grit/grit/gather/rc.py
@@ -5,6 +5,7 @@ '''Support for gathering resources from RC files. ''' +from __future__ import print_function import re
diff --git a/tools/grit/grit/gather/rc_unittest.py b/tools/grit/grit/gather/rc_unittest.py index c4be35e..949f109 100755 --- a/tools/grit/grit/gather/rc_unittest.py +++ b/tools/grit/grit/gather/rc_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for grit.gather.rc''' +from __future__ import print_function import os import sys
diff --git a/tools/grit/grit/gather/regexp.py b/tools/grit/grit/gather/regexp.py index de64c17..d06bf9c 100644 --- a/tools/grit/grit/gather/regexp.py +++ b/tools/grit/grit/gather/regexp.py
@@ -5,6 +5,8 @@ '''A baseclass for simple gatherers based on regular expressions. ''' +from __future__ import print_function + import re from grit.gather import skeleton_gatherer
diff --git a/tools/grit/grit/gather/skeleton_gatherer.py b/tools/grit/grit/gather/skeleton_gatherer.py index 564ccce..c6127d11 100644 --- a/tools/grit/grit/gather/skeleton_gatherer.py +++ b/tools/grit/grit/gather/skeleton_gatherer.py
@@ -6,6 +6,8 @@ list. ''' +from __future__ import print_function + import types from grit.gather import interface
diff --git a/tools/grit/grit/gather/tr_html.py b/tools/grit/grit/gather/tr_html.py index f0bd1322..ba59ff65 100644 --- a/tools/grit/grit/gather/tr_html.py +++ b/tools/grit/grit/gather/tr_html.py
@@ -6,6 +6,7 @@ portions. We wanted to reuse extern.tclib.api.handlers.html.TCHTMLParser but this proved impossible due to the fact that the TotalRecall HTML templates are in general quite far from parseable HTML and the TCHTMLParser derives + from HTMLParser.HTMLParser which requires relatively well-formed HTML. Some examples of "HTML" from the TotalRecall HTML templates that wouldn't be parseable include things like: @@ -48,6 +49,7 @@ extern.tclib.api.handlers.html.TCHTMLParser. ''' +from __future__ import print_function import re import types @@ -208,7 +210,7 @@ _DEBUG = 0 def _DebugPrint(text): if _DEBUG: - print text.encode('utf-8') + print(text.encode('utf-8')) class HtmlChunks(object):
diff --git a/tools/grit/grit/gather/tr_html_unittest.py b/tools/grit/grit/gather/tr_html_unittest.py index 3400ad6f..bc4cc61 100755 --- a/tools/grit/grit/gather/tr_html_unittest.py +++ b/tools/grit/grit/gather/tr_html_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for grit.gather.tr_html''' +from __future__ import print_function import os import sys
diff --git a/tools/grit/grit/gather/txt.py b/tools/grit/grit/gather/txt.py index a2a6cfc..e5c10ab 100644 --- a/tools/grit/grit/gather/txt.py +++ b/tools/grit/grit/gather/txt.py
@@ -5,6 +5,8 @@ '''Supports making amessage from a text file. ''' +from __future__ import print_function + from grit.gather import interface from grit import tclib
diff --git a/tools/grit/grit/gather/txt_unittest.py b/tools/grit/grit/gather/txt_unittest.py index 80586526..35150939 100755 --- a/tools/grit/grit/gather/txt_unittest.py +++ b/tools/grit/grit/gather/txt_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for TxtFile gatherer''' +from __future__ import print_function import os import sys
diff --git a/tools/grit/grit/grd_reader.py b/tools/grit/grit/grd_reader.py index e0ccdac..200b6d1 100755 --- a/tools/grit/grit/grd_reader.py +++ b/tools/grit/grit/grd_reader.py
@@ -6,6 +6,8 @@ '''Class for reading GRD files into memory, without processing them. ''' +from __future__ import print_function + import os.path import types import xml.sax @@ -46,14 +48,14 @@ def startElement(self, name, attrs): if self.ignore_depth or name in self.tags_to_ignore: if self.debug and self.ignore_depth == 0: - print "Ignoring element %s and its children" % name + print("Ignoring element %s and its children" % name) self.ignore_depth += 1 return if self.debug: attr_list = ' '.join('%s="%s"' % kv for kv in attrs.items()) - print ("Starting parsing of element %s with attributes %r" % - (name, attr_list or '(none)')) + print("Starting parsing of element %s with attributes %r" % + (name, attr_list or '(none)')) typeattr = attrs.get('type') node = mapping.ElementToClass(name, typeattr)() @@ -98,7 +100,7 @@ self.source = oldsource if self.debug: - print "End parsing of element %s" % name + print("End parsing of element %s" % name) self.stack.pop().EndParsing() if name == self.stop_after: @@ -202,7 +204,7 @@ pass except: if not debug: - print "parse exception: run GRIT with the -x flag to debug .grd problems" + print("parse exception: run GRIT with the -x flag to debug .grd problems") raise if handler.root.name != 'grit': @@ -232,4 +234,4 @@ if __name__ == '__main__': util.ChangeStdoutEncoding() - print unicode(Parse(sys.argv[1])) + print(unicode(Parse(sys.argv[1])))
diff --git a/tools/grit/grit/grd_reader_unittest.py b/tools/grit/grit/grd_reader_unittest.py index 7e98f80..0095355 100755 --- a/tools/grit/grit/grd_reader_unittest.py +++ b/tools/grit/grit/grd_reader_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grd_reader package''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/grit_runner.py b/tools/grit/grit/grit_runner.py index 09994da..8f9f175 100755 --- a/tools/grit/grit/grit_runner.py +++ b/tools/grit/grit/grit_runner.py
@@ -7,6 +7,8 @@ GRIT tools. """ +from __future__ import print_function + import os import sys if __name__ == '__main__': @@ -111,7 +113,7 @@ if not _HIDDEN in info.keys(): tool_list += ' %-12s %s\n' % (tool, info[_FACTORY]().ShortDescription()) - print """GRIT - the Google Resource and Internationalization Tool + print("""GRIT - the Google Resource and Internationalization Tool Usage: grit [GLOBALOPTIONS] TOOL [args to tool] @@ -139,7 +141,7 @@ %s For more information on how to use a particular tool, and the specific arguments you can send to that tool, execute 'grit help TOOL' -""" % (tool_list) +""" % (tool_list)) class Options(object): @@ -203,11 +205,11 @@ try: args = options.ReadOptions(args) # args may be shorter after this except getopt.GetoptError as e: - print "grit:", str(e) - print "Try running 'grit help' for valid options." + print("grit:", str(e)) + print("Try running 'grit help' for valid options.") return 1 if not args: - print "No tool provided. Try running 'grit help' for a list of tools." + print("No tool provided. Try running 'grit help' for a list of tools.") return 2 tool = args[0] @@ -218,29 +220,29 @@ else: tool = args[1] if not _GetToolInfo(tool): - print "No such tool. Try running 'grit help' for a list of tools." + print("No such tool. Try running 'grit help' for a list of tools.") return 2 - print ("Help for 'grit %s' (for general help, run 'grit help'):\n" - % (tool)) + print("Help for 'grit %s' (for general help, run 'grit help'):\n" % + (tool,)) _GetToolInfo(tool)[_FACTORY]().ShowUsage() return 0 if not _GetToolInfo(tool): - print "No such tool. Try running 'grit help' for a list of tools." + print("No such tool. Try running 'grit help' for a list of tools.") return 2 try: if _GetToolInfo(tool)[_REQUIRES_INPUT]: os.stat(options.input) except OSError: - print ('Input file %s not found.\n' - 'To specify a different input file:\n' - ' 1. Use the GRIT_INPUT environment variable.\n' - ' 2. Use the -i command-line option. This overrides ' - 'GRIT_INPUT.\n' - ' 3. Specify neither GRIT_INPUT or -i and GRIT will try to load ' - "'resource.grd'\n" - ' from the current directory.' % options.input) + print('Input file %s not found.\n' + 'To specify a different input file:\n' + ' 1. Use the GRIT_INPUT environment variable.\n' + ' 2. Use the -i command-line option. This overrides ' + 'GRIT_INPUT.\n' + ' 3. Specify neither GRIT_INPUT or -i and GRIT will try to load ' + "'resource.grd'\n" + ' from the current directory.' % options.input) return 2 if options.hash: @@ -255,8 +257,8 @@ else: return toolobject.Run(options, args[1:]) except getopt.GetoptError as e: - print "grit: %s: %s" % (tool, str(e)) - print "Try running 'grit help %s' for valid options." % (tool,) + print("grit: %s: %s" % (tool, str(e))) + print("Try running 'grit help %s' for valid options." % (tool,)) return 1
diff --git a/tools/grit/grit/grit_runner_unittest.py b/tools/grit/grit/grit_runner_unittest.py index 591eeae..be2c64d 100755 --- a/tools/grit/grit/grit_runner_unittest.py +++ b/tools/grit/grit/grit_runner_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grit.py''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/lazy_re.py b/tools/grit/grit/lazy_re.py index ae67d048..5c461e87 100644 --- a/tools/grit/grit/lazy_re.py +++ b/tools/grit/grit/lazy_re.py
@@ -8,6 +8,8 @@ time in some cases. ''' +from __future__ import print_function + import re
diff --git a/tools/grit/grit/lazy_re_unittest.py b/tools/grit/grit/lazy_re_unittest.py index 99fe1ec..8488b454 100755 --- a/tools/grit/grit/lazy_re_unittest.py +++ b/tools/grit/grit/lazy_re_unittest.py
@@ -6,6 +6,8 @@ '''Unit test for lazy_re. ''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/node/base.py b/tools/grit/grit/node/base.py index bd6b207..ca92a91 100644 --- a/tools/grit/grit/node/base.py +++ b/tools/grit/grit/node/base.py
@@ -5,6 +5,8 @@ '''Base types for nodes in a GRIT resource tree. ''' +from __future__ import print_function + import ast import os import sys @@ -54,7 +56,7 @@ def __exit__(self, exc_type, exc_value, traceback): if exc_type is not None: - print u'Error processing node %s' % unicode(self) + print(u'Error processing node %s' % unicode(self)) def __iter__(self): '''A preorder iteration through the tree that this node is the root of.'''
diff --git a/tools/grit/grit/node/base_unittest.py b/tools/grit/grit/node/base_unittest.py index 556c7456..d6dd3c3 100755 --- a/tools/grit/grit/node/base_unittest.py +++ b/tools/grit/grit/node/base_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for base.Node functionality (as used in various subclasses)''' +from __future__ import print_function import os import sys
diff --git a/tools/grit/grit/node/custom/filename.py b/tools/grit/grit/node/custom/filename.py index 416eac5..cee18ec2 100644 --- a/tools/grit/grit/node/custom/filename.py +++ b/tools/grit/grit/node/custom/filename.py
@@ -4,6 +4,8 @@ '''A CustomType for filenames.''' +from __future__ import print_function + from grit import clique from grit import lazy_re
diff --git a/tools/grit/grit/node/custom/filename_unittest.py b/tools/grit/grit/node/custom/filename_unittest.py index 9ea8eb9..8e2a6dd 100755 --- a/tools/grit/grit/node/custom/filename_unittest.py +++ b/tools/grit/grit/node/custom/filename_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for grit.node.custom.filename''' +from __future__ import print_function import os import sys
diff --git a/tools/grit/grit/node/empty.py b/tools/grit/grit/node/empty.py index b821752..e19d2c4 100644 --- a/tools/grit/grit/node/empty.py +++ b/tools/grit/grit/node/empty.py
@@ -5,6 +5,7 @@ '''Container nodes that don't have any logic. ''' +from __future__ import print_function from grit.node import base from grit.node import include
diff --git a/tools/grit/grit/node/include.py b/tools/grit/grit/node/include.py index fd517bdd..fcb805b 100644 --- a/tools/grit/grit/node/include.py +++ b/tools/grit/grit/node/include.py
@@ -5,6 +5,8 @@ """Handling of the <include> element. """ +from __future__ import print_function + import os from grit import exception
diff --git a/tools/grit/grit/node/include_unittest.py b/tools/grit/grit/node/include_unittest.py index b4dcb8a79..5dc2059 100755 --- a/tools/grit/grit/node/include_unittest.py +++ b/tools/grit/grit/node/include_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for include.IncludeNode''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/node/mapping.py b/tools/grit/grit/node/mapping.py index 083f77b..6297f0b 100644 --- a/tools/grit/grit/node/mapping.py +++ b/tools/grit/grit/node/mapping.py
@@ -6,6 +6,7 @@ When adding a new node type, you add to this mapping. ''' +from __future__ import print_function from grit import exception
diff --git a/tools/grit/grit/node/message.py b/tools/grit/grit/node/message.py index ed065bb..a21c38c 100644 --- a/tools/grit/grit/node/message.py +++ b/tools/grit/grit/node/message.py
@@ -5,6 +5,8 @@ '''Handling of the <message> element. ''' +from __future__ import print_function + import re import types @@ -167,7 +169,7 @@ if isinstance(item, types.StringTypes): # Not a <ph> element: fail if any <ph> formatters are detected. if _FORMATTERS.search(item): - print _BAD_PLACEHOLDER_MSG % (item, self.source) + print(_BAD_PLACEHOLDER_MSG % (item, self.source)) raise exception.PlaceholderNotInsidePhNode text += item else: @@ -198,7 +200,7 @@ # Fail if <ph> special chars remain in cdata. if re.search(r'[%\$]', cdata): message_id = self.attrs['name'] + ' ' + original; - print _INVALID_PH_CHAR_MSG % (message_id, self.source) + print(_INVALID_PH_CHAR_MSG % (message_id, self.source)) raise exception.InvalidCharactersInsidePhNode # Otherwise, accept this <ph> placeholder.
diff --git a/tools/grit/grit/node/message_unittest.py b/tools/grit/grit/node/message_unittest.py index 5cf78c12..19fd594c 100755 --- a/tools/grit/grit/node/message_unittest.py +++ b/tools/grit/grit/node/message_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for grit.node.message''' +from __future__ import print_function import os import sys
diff --git a/tools/grit/grit/node/misc.py b/tools/grit/grit/node/misc.py index 5d983ee9..f01bf7bf 100644 --- a/tools/grit/grit/node/misc.py +++ b/tools/grit/grit/node/misc.py
@@ -5,6 +5,8 @@ """Miscellaneous node types. """ +from __future__ import print_function + import os.path import re import sys @@ -191,8 +193,8 @@ % (id, id_reasons[id], reason)) if id < 101: - print ('WARNING: Numeric resource IDs should be greater than 100 to\n' - 'avoid conflicts with system-defined resource IDs.') + print('WARNING: Numeric resource IDs should be greater than 100 to\n' + 'avoid conflicts with system-defined resource IDs.') if tid not in predetermined_tids and id in predetermined_ids: raise exception.IdRangeOverlap('ID %d overlaps between %s and %s' @@ -600,12 +602,12 @@ try: id_list = first_ids[filename][node.name] except KeyError, e: - print '-' * 78 - print 'Resource id not set for %s (%s)!' % (filename, node.name) - print ('Please update %s to include an entry for %s. See the ' - 'comments in resource_ids for information on why you need to ' - 'update that file.' % (first_ids_filename, filename)) - print '-' * 78 + print('-' * 78) + print('Resource id not set for %s (%s)!' % (filename, node.name)) + print('Please update %s to include an entry for %s. See the ' + 'comments in resource_ids for information on why you need to ' + 'update that file.' % (first_ids_filename, filename)) + print('-' * 78) raise e try:
diff --git a/tools/grit/grit/node/misc_unittest.py b/tools/grit/grit/node/misc_unittest.py index 30df9fe..6ed63a9 100755 --- a/tools/grit/grit/node/misc_unittest.py +++ b/tools/grit/grit/node/misc_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for misc.GritNode''' +from __future__ import print_function import StringIO import contextlib
diff --git a/tools/grit/grit/node/node_io.py b/tools/grit/grit/node/node_io.py index 99423ad1..c67add8 100644 --- a/tools/grit/grit/node/node_io.py +++ b/tools/grit/grit/node/node_io.py
@@ -5,6 +5,8 @@ '''The <output> and <file> elements. ''' +from __future__ import print_function + import os from grit import xtb_reader @@ -47,7 +49,7 @@ defs=defs, target_platform=target_platform) except: - print "Exception during parsing of %s" % self.GetInputPath() + print("Exception during parsing of %s" % self.GetInputPath()) raise # Translation console uses non-standard language codes 'iw' and 'no' for # Hebrew and Norwegian Bokmal instead of 'he' and 'nb' used in Chrome.
diff --git a/tools/grit/grit/node/node_io_unittest.py b/tools/grit/grit/node/node_io_unittest.py index f82887e..3b2ae3b 100755 --- a/tools/grit/grit/node/node_io_unittest.py +++ b/tools/grit/grit/node/node_io_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for node_io.FileNode''' +from __future__ import print_function + import StringIO import os import sys
diff --git a/tools/grit/grit/node/structure.py b/tools/grit/grit/node/structure.py index 6b795d0..69784f5 100644 --- a/tools/grit/grit/node/structure.py +++ b/tools/grit/grit/node/structure.py
@@ -5,6 +5,8 @@ '''The <structure> element. ''' +from __future__ import print_function + import os import platform import re @@ -235,8 +237,8 @@ def RunPreSubstitutionGatherer(self, debug=False): if debug: - print 'Running gatherer %s for file %s' % ( - str(type(self.gatherer)), self.GetInputPath()) + print('Running gatherer %s for file %s' % + (type(self.gatherer), self.GetInputPath())) # Note: Parse() is idempotent, therefore this method is also. self.gatherer.Parse()
diff --git a/tools/grit/grit/node/structure_unittest.py b/tools/grit/grit/node/structure_unittest.py index 683a0626..9160edb 100755 --- a/tools/grit/grit/node/structure_unittest.py +++ b/tools/grit/grit/node/structure_unittest.py
@@ -6,6 +6,8 @@ '''Unit tests for <structure> nodes. ''' +from __future__ import print_function + import os import os.path import sys
diff --git a/tools/grit/grit/node/variant.py b/tools/grit/grit/node/variant.py index 7d3a526..ab183f0 100644 --- a/tools/grit/grit/node/variant.py +++ b/tools/grit/grit/node/variant.py
@@ -5,6 +5,7 @@ '''The <skeleton> element. ''' +from __future__ import print_function from grit.node import base
diff --git a/tools/grit/grit/pseudo.py b/tools/grit/grit/pseudo.py index 23b784d..0434026 100644 --- a/tools/grit/grit/pseudo.py +++ b/tools/grit/grit/pseudo.py
@@ -21,6 +21,8 @@ the latin-1 character set which will stress character encoding bugs. ''' +from __future__ import print_function + from grit import lazy_re from grit import tclib
diff --git a/tools/grit/grit/pseudo_rtl.py b/tools/grit/grit/pseudo_rtl.py index f307ea049..2240b57 100644 --- a/tools/grit/grit/pseudo_rtl.py +++ b/tools/grit/grit/pseudo_rtl.py
@@ -7,6 +7,8 @@ More info at https://sites.google.com/a/chromium.org/dev/Home/fake-bidi ''' +from __future__ import print_function + import re from grit import lazy_re
diff --git a/tools/grit/grit/pseudo_unittest.py b/tools/grit/grit/pseudo_unittest.py index ecf34ff04..b1d53ff 100755 --- a/tools/grit/grit/pseudo_unittest.py +++ b/tools/grit/grit/pseudo_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grit.pseudo''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/shortcuts.py b/tools/grit/grit/shortcuts.py index bae61cc..0db2ce4 100644 --- a/tools/grit/grit/shortcuts.py +++ b/tools/grit/grit/shortcuts.py
@@ -5,6 +5,8 @@ '''Stuff to prevent conflicting shortcuts. ''' +from __future__ import print_function + from grit import lazy_re
diff --git a/tools/grit/grit/shortcuts_unittest.py b/tools/grit/grit/shortcuts_unittest.py index ed788e63..4580b2a 100644 --- a/tools/grit/grit/shortcuts_unittest.py +++ b/tools/grit/grit/shortcuts_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grit.shortcuts ''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/tclib.py b/tools/grit/grit/tclib.py index da8ad32..c73664f 100644 --- a/tools/grit/grit/tclib.py +++ b/tools/grit/grit/tclib.py
@@ -5,6 +5,7 @@ '''Adaptation of the extern.tclib classes for our needs. ''' +from __future__ import print_function import re import types
diff --git a/tools/grit/grit/tclib_unittest.py b/tools/grit/grit/tclib_unittest.py index 87849c5..94673a2 100755 --- a/tools/grit/grit/tclib_unittest.py +++ b/tools/grit/grit/tclib_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for grit.tclib''' +from __future__ import print_function import sys import os.path
diff --git a/tools/grit/grit/test_suite_all.py b/tools/grit/grit/test_suite_all.py index 8d7f76b..6e7727cf 100755 --- a/tools/grit/grit/test_suite_all.py +++ b/tools/grit/grit/test_suite_all.py
@@ -5,6 +5,8 @@ '''Unit test suite that collects all test cases for GRIT.''' +from __future__ import print_function + import os import sys
diff --git a/tools/grit/grit/tool/android2grd.py b/tools/grit/grit/tool/android2grd.py index dd47fda..5ef9204 100644 --- a/tools/grit/grit/tool/android2grd.py +++ b/tools/grit/grit/tool/android2grd.py
@@ -4,6 +4,7 @@ """The 'grit android2grd' tool.""" +from __future__ import print_function import getopt import os.path @@ -161,8 +162,8 @@ """ args = self.ParseOptions(args) if len(args) != 1: - print ('Tool requires one argument, the path to the Android ' - 'strings.xml resource file to be converted.') + print('Tool requires one argument, the path to the Android ' + 'strings.xml resource file to be converted.') return 2 self.SetOptions(opts) @@ -243,12 +244,12 @@ description = ' '.join(child.data.split()) elif child.nodeType == Node.ELEMENT_NODE: if child.tagName != 'string': - print 'Warning: ignoring unknown tag <%s>' % child.tagName + print('Warning: ignoring unknown tag <%s>' % child.tagName) else: translatable = self.IsTranslatable(child) raw_name = child.getAttribute('name') if not _STRING_NAME.match(raw_name): - print 'Error: illegal string name: %s' % raw_name + print('Error: illegal string name: %s' % raw_name) grd_name = 'IDS_' + raw_name.upper() # Transform the <string> node contents into a tclib.Message, taking # care to handle whitespace transformations and escaped characters, @@ -291,14 +292,14 @@ placeholder_text = self.__FormatPlaceholderText(node) placeholder_example = node.getAttribute('example') if not placeholder_example: - print ('Info: placeholder does not contain an example: %s' % - node.toxml()) + print('Info: placeholder does not contain an example: %s' % + node.toxml()) placeholder_example = placeholder_id.upper() msg.AppendPlaceholder(tclib.Placeholder(placeholder_id, placeholder_text, placeholder_example)) else: - print ('Warning: removing tag <%s> which must be inside a ' - 'placeholder: %s' % (node.tagName, node.toxml())) + print('Warning: removing tag <%s> which must be inside a ' + 'placeholder: %s' % (node.tagName, node.toxml())) msg.AppendText(self.__FormatPlaceholderText(node)) # Handle other nodes. @@ -348,17 +349,17 @@ output = ''.join(output) if is_quoted_section: - print 'Warning: unbalanced quotes in string: %s' % android_string + print('Warning: unbalanced quotes in string: %s' % android_string) if is_backslash_sequence: - print 'Warning: trailing backslash in string: %s' % android_string + print('Warning: trailing backslash in string: %s' % android_string) # Check for format specifiers outside of placeholder tags. if not inside_placeholder: format_specifier = _FORMAT_SPECIFIER.search(output) if format_specifier: - print ('Warning: format specifiers are not inside a placeholder ' - '<xliff:g/> tag: %s' % output) + print('Warning: format specifiers are not inside a placeholder ' + '<xliff:g/> tag: %s' % output) return output @@ -380,15 +381,15 @@ declare a string resource along with a programmatic id. """ if not description: - print 'Warning: no description for %s' % grd_name + print('Warning: no description for %s' % grd_name) # Check that we actually fit within the character limit we've specified. match = _CHAR_LIMIT.search(description) if match: char_limit = int(match.group(1)) msg_content = msg.GetRealContent() if len(msg_content) > char_limit: - print ('Warning: char-limit for %s is %d, but length is %d: %s' % - (grd_name, char_limit, len(msg_content), msg_content)) + print('Warning: char-limit for %s is %d, but length is %d: %s' % + (grd_name, char_limit, len(msg_content), msg_content)) return message.MessageNode.Construct(parent=messages_node, name=grd_name, message=msg, @@ -476,7 +477,7 @@ if android_string.hasAttribute('translatable'): value = android_string.getAttribute('translatable').lower() if value not in ('true', 'false'): - print 'Warning: translatable attribute has invalid value: %s' % value + print('Warning: translatable attribute has invalid value: %s' % value) return value == 'true' else: return True
diff --git a/tools/grit/grit/tool/android2grd_unittest.py b/tools/grit/grit/tool/android2grd_unittest.py index 0c7ed54a..802d216 100755 --- a/tools/grit/grit/tool/android2grd_unittest.py +++ b/tools/grit/grit/tool/android2grd_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grit.tool.android2grd''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py index 89f94f1..fde614d 100644 --- a/tools/grit/grit/tool/build.py +++ b/tools/grit/grit/tool/build.py
@@ -5,6 +5,8 @@ '''The 'grit build' tool. ''' +from __future__ import print_function + import codecs import filecmp import getopt @@ -210,7 +212,7 @@ sys.exit(0) if len(args): - print 'This tool takes no tool-specific arguments.' + print('This tool takes no tool-specific arguments.') return 2 self.SetOptions(opts) self.VerboseOut('Output directory: %s (absolute path: %s)\n' % @@ -401,7 +403,7 @@ warnings = shortcuts.GenerateDuplicateShortcutsWarnings( self.res.UberClique(), self.res.GetTcProject()) if warnings: - print '\n'.join(warnings) + print('\n'.join(warnings)) # Print out any fallback warnings, and missing translation errors, and # exit with an error code if there are missing translations in a non-pseudo @@ -411,7 +413,7 @@ if warnings: self.VerboseOut(warnings) if self.res.UberClique().HasMissingTranslations(): - print self.res.UberClique().missing_translations_ + print(self.res.UberClique().missing_translations_) sys.exit(-1) @@ -442,8 +444,8 @@ Extra output files: %s ''' - print error % ('\n'.join(asserted), '\n'.join(actual), '\n'.join(missing), - '\n'.join(extra)) + print(error % ('\n'.join(asserted), '\n'.join(actual), '\n'.join(missing), + ' \n'.join(extra))) return False return True
diff --git a/tools/grit/grit/tool/build_unittest.py b/tools/grit/grit/tool/build_unittest.py index 985882c..a4be0876 100755 --- a/tools/grit/grit/tool/build_unittest.py +++ b/tools/grit/grit/tool/build_unittest.py
@@ -6,6 +6,8 @@ '''Unit tests for the 'grit build' tool. ''' +from __future__ import print_function + import codecs import os import sys
diff --git a/tools/grit/grit/tool/buildinfo.py b/tools/grit/grit/tool/buildinfo.py index 5ef1a01..845aea9f 100644 --- a/tools/grit/grit/tool/buildinfo.py +++ b/tools/grit/grit/tool/buildinfo.py
@@ -5,6 +5,8 @@ """Output the list of files to be generated by GRIT from an input. """ +from __future__ import print_function + import getopt import os import sys @@ -41,7 +43,7 @@ self.ShowUsage() sys.exit(0) if len(args) > 0: - print 'This tool takes exactly one argument: the output directory via -o' + print('This tool takes exactly one argument: the output directory via -o') return 2 self.SetOptions(opts) @@ -64,13 +66,13 @@ if path: path = os.path.join(self.output_directory, path) path = os.path.normpath(path) - print '%s|%s' % ('rc_all', path) + print('%s|%s' % ('rc_all', path)) res_tree.SetOutputLanguage(old_output_language) for output in res_tree.GetOutputFiles(): path = os.path.join(self.output_directory, output.GetFilename()) path = os.path.normpath(path) - print '%s|%s' % (output.GetType(), path) + print('%s|%s' % (output.GetType(), path)) for infile in res_tree.GetInputFiles(): - print 'input|%s' % os.path.normpath(infile) + print('input|%s' % os.path.normpath(infile))
diff --git a/tools/grit/grit/tool/buildinfo_unittest.py b/tools/grit/grit/tool/buildinfo_unittest.py index b07bcd62..e7b086d9 100755 --- a/tools/grit/grit/tool/buildinfo_unittest.py +++ b/tools/grit/grit/tool/buildinfo_unittest.py
@@ -6,6 +6,8 @@ """Unit tests for the 'grit buildinfo' tool. """ +from __future__ import print_function + import os import StringIO import sys
diff --git a/tools/grit/grit/tool/count.py b/tools/grit/grit/tool/count.py index 1a45d89..ab37f2d 100644 --- a/tools/grit/grit/tool/count.py +++ b/tools/grit/grit/tool/count.py
@@ -4,6 +4,8 @@ '''Count number of occurrences of a given message ID.''' +from __future__ import print_function + import getopt import sys @@ -32,8 +34,8 @@ def Run(self, opts, args): args = self.ParseOptions(args) if len(args) != 1: - print ('This tool takes a single tool-specific argument, the message ' - 'ID to count.') + print('This tool takes a single tool-specific argument, the message ' + 'ID to count.') return 2 self.SetOptions(opts) @@ -47,4 +49,4 @@ if c.GetId() == id: count += 1 - print "There are %d occurrences of message %s." % (count, id) + print("There are %d occurrences of message %s." % (count, id))
diff --git a/tools/grit/grit/tool/diff_structures.py b/tools/grit/grit/tool/diff_structures.py index 681d01ec..f007d01 100644 --- a/tools/grit/grit/tool/diff_structures.py +++ b/tools/grit/grit/tool/diff_structures.py
@@ -5,6 +5,8 @@ '''The 'grit sdiff' tool. ''' +from __future__ import print_function + import os import getopt import sys @@ -67,11 +69,11 @@ sys.exit(0) if len(args) != 2: - print "Incorrect usage - 'grit help sdiff' for usage details." + print("Incorrect usage - 'grit help sdiff' for usage details.") return 2 if 'P4DIFF' not in os.environ: - print "Environment variable P4DIFF not set; defaulting to 'windiff'." + print("Environment variable P4DIFF not set; defaulting to 'windiff'.") diff_program = 'windiff' else: diff_program = os.environ['P4DIFF']
diff --git a/tools/grit/grit/tool/interface.py b/tools/grit/grit/tool/interface.py index 27fbbb7..e9232052 100644 --- a/tools/grit/grit/tool/interface.py +++ b/tools/grit/grit/tool/interface.py
@@ -5,6 +5,7 @@ '''Base class and interface for tools. ''' +from __future__ import print_function class Tool(object): '''Base class for all tools. Tools should use their docstring (i.e. the @@ -40,7 +41,7 @@ def ShowUsage(self): '''Show usage text for this tool.''' - print self.__doc__ + print(self.__doc__) def SetOptions(self, opts): self.o = opts
diff --git a/tools/grit/grit/tool/menu_from_parts.py b/tools/grit/grit/tool/menu_from_parts.py index c8c3619c..b8371ab 100644 --- a/tools/grit/grit/tool/menu_from_parts.py +++ b/tools/grit/grit/tool/menu_from_parts.py
@@ -4,6 +4,8 @@ '''The 'grit menufromparts' tool.''' +from __future__ import print_function + import types from grit import grd_reader @@ -63,7 +65,8 @@ if isinstance(part, types.StringTypes): id = grit.extern.tclib.GenerateMessageId(part) if id not in xtb: - print "WARNING didn't find all translations for menu %s" % node.attrs['name'] + print("WARNING didn't find all translations for menu %s" % + (node.attrs['name'],)) translation = [] break translation.append(xtb[id])
diff --git a/tools/grit/grit/tool/newgrd.py b/tools/grit/grit/tool/newgrd.py index 385a806..18579596 100644 --- a/tools/grit/grit/tool/newgrd.py +++ b/tools/grit/grit/tool/newgrd.py
@@ -5,6 +5,8 @@ '''Tool to create a new, empty .grd file with all the basic sections. ''' +from __future__ import print_function + import getopt import sys @@ -74,9 +76,10 @@ def Run(self, opts, args): args = self.ParseOptions(args) if len(args) != 1: - print 'This tool requires exactly one argument, the name of the output file.' + print('This tool requires exactly one argument, the name of the output ' + 'file.') return 2 filename = args[0] with util.WrapOutputStream(open(filename, 'w'), 'utf-8') as out: out.write(_FILE_CONTENTS) - print "Wrote file %s" % filename + print("Wrote file %s" % filename)
diff --git a/tools/grit/grit/tool/postprocess_interface.py b/tools/grit/grit/tool/postprocess_interface.py index 08566eb..4bb8c5871 100644 --- a/tools/grit/grit/tool/postprocess_interface.py +++ b/tools/grit/grit/tool/postprocess_interface.py
@@ -5,6 +5,7 @@ ''' Base class for postprocessing of RC files. ''' +from __future__ import print_function class PostProcessor(object): ''' Base class for postprocessing of the RC file data before being
diff --git a/tools/grit/grit/tool/postprocess_unittest.py b/tools/grit/grit/tool/postprocess_unittest.py index 91f02d69..77fe228b 100755 --- a/tools/grit/grit/tool/postprocess_unittest.py +++ b/tools/grit/grit/tool/postprocess_unittest.py
@@ -8,6 +8,8 @@ modify the grd data tree, changing the message name attributes. ''' +from __future__ import print_function + import os import re import sys
diff --git a/tools/grit/grit/tool/preprocess_interface.py b/tools/grit/grit/tool/preprocess_interface.py index 97404e9f..67974e7 100644 --- a/tools/grit/grit/tool/preprocess_interface.py +++ b/tools/grit/grit/tool/preprocess_interface.py
@@ -5,6 +5,7 @@ ''' Base class for preprocessing of RC files. ''' +from __future__ import print_function class PreProcessor(object): ''' Base class for preprocessing of the RC file data before being
diff --git a/tools/grit/grit/tool/preprocess_unittest.py b/tools/grit/grit/tool/preprocess_unittest.py index da4242b..40b95cd 100755 --- a/tools/grit/grit/tool/preprocess_unittest.py +++ b/tools/grit/grit/tool/preprocess_unittest.py
@@ -8,6 +8,8 @@ provide the actual rctext data. ''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/tool/rc2grd.py b/tools/grit/grit/tool/rc2grd.py index 4850e824..f11560d5 100644 --- a/tools/grit/grit/tool/rc2grd.py +++ b/tools/grit/grit/tool/rc2grd.py
@@ -4,6 +4,7 @@ '''The 'grit rc2grd' tool.''' +from __future__ import print_function import os.path import getopt @@ -189,8 +190,8 @@ def Run(self, opts, args): args = self.ParseOptions(args) if len(args) != 1: - print ('This tool takes a single tool-specific argument, the path to the\n' - '.rc file to process.') + print('This tool takes a single tool-specific argument, the path to the\n' + '.rc file to process.') return 2 self.SetOptions(opts) @@ -203,7 +204,8 @@ with util.WrapOutputStream(file(out_path, 'w'), 'utf-8') as outfile: outfile.write(grd_text) - print 'Wrote output file %s.\nPlease check for TODO items in the file.' % out_path + print('Wrote output file %s.\nPlease check for TODO items in the file.' % + (out_path,)) def Process(self, rctext, rc_path): @@ -411,5 +413,5 @@ return msg except: - print 'Exception processing message with text "%s"' % text + print('Exception processing message with text "%s"' % text) raise
diff --git a/tools/grit/grit/tool/rc2grd_unittest.py b/tools/grit/grit/tool/rc2grd_unittest.py index 0e48f07f..9976df7 100755 --- a/tools/grit/grit/tool/rc2grd_unittest.py +++ b/tools/grit/grit/tool/rc2grd_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for grit.tool.rc2grd''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/tool/resize.py b/tools/grit/grit/tool/resize.py index 3891717..d44160d 100644 --- a/tools/grit/grit/tool/resize.py +++ b/tools/grit/grit/tool/resize.py
@@ -5,6 +5,8 @@ '''The 'grit resize' tool. ''' +from __future__ import print_function + import getopt import os import sys @@ -253,7 +255,7 @@ ).replace('[[DIALOG_NAME]]', project_name) fname = os.path.join(dir_path, '%s.vcproj' % project_name) self.WriteFile(fname, project_text) - print "Wrote %s" % fname + print("Wrote %s" % fname) # Create the .rc file # Output all <include> nodes since the dialogs might depend on them (e.g. @@ -277,14 +279,14 @@ fname = os.path.join(dir_path, '%s.rc' % project_name) self.WriteFile(fname, rc_text, self.GetEncoding()) - print "Wrote %s" % fname + print("Wrote %s" % fname) # Create the resource.h file header_defines = ''.join(rc_header.FormatDefines(grd)) header_text = HEADER_TEMPLATE.replace('[[DEFINES]]', header_defines) fname = os.path.join(dir_path, 'resource.h') self.WriteFile(fname, header_text) - print "Wrote %s" % fname + print("Wrote %s" % fname) def WriteFile(self, filename, contents, encoding='cp1252'): with open(filename, 'wb') as f:
diff --git a/tools/grit/grit/tool/test.py b/tools/grit/grit/tool/test.py index 1fcf23c..241a976 100644 --- a/tools/grit/grit/tool/test.py +++ b/tools/grit/grit/tool/test.py
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from __future__ import print_function + from grit.tool import interface class TestTool(interface.Tool): @@ -14,9 +16,9 @@ return 'A do-nothing tool for testing command-line parsing.' def Run(self, global_options, my_arguments): - print 'NOTE This tool is only for testing the parsing of global options and' - print 'tool-specific arguments that it receives. You may have intended to' - print 'run "grit unit" which is the unit-test suite for GRIT.' - print 'Options: %s' % repr(global_options) - print 'Arguments: %s' % repr(my_arguments) + print('NOTE This tool is only for testing the parsing of global options and') + print('tool-specific arguments that it receives. You may have intended to') + print('run "grit unit" which is the unit-test suite for GRIT.') + print('Options: %s' % repr(global_options)) + print('Arguments: %s' % repr(my_arguments)) return 0
diff --git a/tools/grit/grit/tool/transl2tc.py b/tools/grit/grit/tool/transl2tc.py index d75e2b5c..2302682d 100644 --- a/tools/grit/grit/tool/transl2tc.py +++ b/tools/grit/grit/tool/transl2tc.py
@@ -5,6 +5,8 @@ '''The 'grit transl2tc' tool. ''' +from __future__ import print_function + import sys from grit import grd_reader
diff --git a/tools/grit/grit/tool/transl2tc_unittest.py b/tools/grit/grit/tool/transl2tc_unittest.py index db64d10..61f1dad 100755 --- a/tools/grit/grit/tool/transl2tc_unittest.py +++ b/tools/grit/grit/tool/transl2tc_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for the 'grit transl2tc' tool.''' +from __future__ import print_function import os import sys
diff --git a/tools/grit/grit/tool/unit.py b/tools/grit/grit/tool/unit.py index c78ae0b9..3b6f45d 100644 --- a/tools/grit/grit/tool/unit.py +++ b/tools/grit/grit/tool/unit.py
@@ -4,6 +4,8 @@ '''GRIT tool that runs the unit test suite for GRIT.''' +from __future__ import print_function + import getopt import sys import unittest @@ -31,7 +33,7 @@ def Run(self, opts, args): args = self.ParseOptions(args) if args: - print 'This tool takes no arguments.' + print('This tool takes no arguments.') return 2 return unittest.TextTestRunner(verbosity=2).run(
diff --git a/tools/grit/grit/tool/xmb.py b/tools/grit/grit/tool/xmb.py index 150652b4..c2f5a87 100644 --- a/tools/grit/grit/tool/xmb.py +++ b/tools/grit/grit/tool/xmb.py
@@ -5,6 +5,8 @@ """The 'grit xmb' tool. """ +from __future__ import print_function + import getopt import os import sys @@ -192,8 +194,8 @@ self.ShowUsage() sys.exit(0) if not len(args) == 1: - print ('grit xmb takes exactly one argument, the path to the XMB file ' - 'to output.') + print('grit xmb takes exactly one argument, the path to the XMB file ' + 'to output.') return 2 xmb_path = args[0] @@ -208,7 +210,7 @@ res_tree, output_file, limit_file, limit_is_grd, limit_file_dir) if limit_file: limit_file.close() - print "Wrote %s" % xmb_path + print("Wrote %s" % xmb_path) def Process(self, res_tree, output_file, limit_file=None, limit_is_grd=False, dir=None):
diff --git a/tools/grit/grit/tool/xmb_unittest.py b/tools/grit/grit/tool/xmb_unittest.py index 200ecd9a..2df5951b 100755 --- a/tools/grit/grit/tool/xmb_unittest.py +++ b/tools/grit/grit/tool/xmb_unittest.py
@@ -5,6 +5,8 @@ '''Unit tests for 'grit xmb' tool.''' +from __future__ import print_function + import os import sys if __name__ == '__main__':
diff --git a/tools/grit/grit/util.py b/tools/grit/grit/util.py index d98a0bf..3b8a3db 100644 --- a/tools/grit/grit/util.py +++ b/tools/grit/grit/util.py
@@ -5,6 +5,8 @@ '''Utilities used by GRIT. ''' +from __future__ import print_function + import codecs import htmlentitydefs import os @@ -434,7 +436,7 @@ if lang in _LANG_TO_CODEPAGE: return _LANG_TO_CODEPAGE[lang] else: - print "Not sure which codepage to use for %s, assuming cp1252" % lang + print("Not sure which codepage to use for %s, assuming cp1252" % lang) return 1252 def NewClassInstance(class_name, class_type):
diff --git a/tools/grit/grit/util_unittest.py b/tools/grit/grit/util_unittest.py index ecadfa3c..a88a032 100755 --- a/tools/grit/grit/util_unittest.py +++ b/tools/grit/grit/util_unittest.py
@@ -6,6 +6,8 @@ '''Unit test that checks some of util functions. ''' +from __future__ import print_function + import os import sys if __name__ == '__main__': @@ -82,7 +84,7 @@ with open('testfile', 'wb') as f: f.write(data) if util.ReadFile('testfile', encoding) != expected_result: - print (util.ReadFile('testfile', encoding), expected_result) + print(util.ReadFile('testfile', encoding), expected_result) self.failUnless(util.ReadFile('testfile', encoding) == expected_result) test_std_newline = '\xEF\xBB\xBFabc\ndef' # EF BB BF is UTF-8 BOM
diff --git a/tools/grit/grit/xtb_reader.py b/tools/grit/grit/xtb_reader.py index 8d5f58f..ac2f1eae 100644 --- a/tools/grit/grit/xtb_reader.py +++ b/tools/grit/grit/xtb_reader.py
@@ -5,6 +5,7 @@ '''Fast and efficient parser for XTB files. ''' +from __future__ import print_function import sys import xml.sax
diff --git a/tools/grit/grit/xtb_reader_unittest.py b/tools/grit/grit/xtb_reader_unittest.py index bab019c..a6d6ad61 100755 --- a/tools/grit/grit/xtb_reader_unittest.py +++ b/tools/grit/grit/xtb_reader_unittest.py
@@ -5,6 +5,7 @@ '''Unit tests for grit.xtb_reader''' +from __future__ import print_function import os import sys
diff --git a/tools/grit/grit_info.py b/tools/grit/grit_info.py index 7c57aff..4e08c3b 100755 --- a/tools/grit/grit_info.py +++ b/tools/grit/grit_info.py
@@ -6,6 +6,8 @@ '''Tool to determine inputs and outputs of a grit file. ''' +from __future__ import print_function + import optparse import os import posixpath @@ -104,9 +106,9 @@ def PrintUsage(): - print 'USAGE: ./grit_info.py --inputs [-D foo] [-f resource_ids] <grd-file>' - print (' ./grit_info.py --outputs [-D foo] [-f resource_ids] ' + - '<out-prefix> <grd-file>') + print('USAGE: ./grit_info.py --inputs [-D foo] [-f resource_ids] <grd-file>') + print(' ./grit_info.py --outputs [-D foo] [-f resource_ids] ' + + '<out-prefix> <grd-file>') def DoMain(argv): @@ -175,9 +177,9 @@ result = DoMain(argv[1:]) except WrongNumberOfArguments, e: PrintUsage() - print e + print(e) return 1 - print result + print(result) return 0
diff --git a/tools/grit/pak_util.py b/tools/grit/pak_util.py index b71a20d..bd38dce1 100755 --- a/tools/grit/pak_util.py +++ b/tools/grit/pak_util.py
@@ -9,6 +9,8 @@ https://dev.chromium.org/developers/design-documents/linuxresourcesandlocalizedstrings """ +from __future__ import print_function + import argparse import hashlib import os
diff --git a/tools/grit/stamp_grit_sources.py b/tools/grit/stamp_grit_sources.py index d43d4b8..bc7265c6 100644 --- a/tools/grit/stamp_grit_sources.py +++ b/tools/grit/stamp_grit_sources.py
@@ -12,6 +12,8 @@ # Usage: # stamp_grit_sources.py <directory> <stamp-file> <.d-file> +from __future__ import print_function + import os import sys @@ -39,7 +41,7 @@ def main(argv): if len(argv) != 4: - print "Error: expecting 3 args." + print("Error: expecting 3 args.") return 1 grit_root_dir = sys.argv[1]
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 9b0e724..4cab0957 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -814,6 +814,7 @@ }, 'tryserver.chromium.win': { + 'gpu-fyi-try-win-xr-builder': 'gpu_fyi_tests_release_trybot_x86', 'gpu-fyi-try-win7-amd-dbg': 'gpu_fyi_tests_debug_trybot_x86', 'gpu-fyi-try-win7-amd-dqp': 'deqp_release_trybot_x86', 'gpu-fyi-try-win7-amd-rel': 'gpu_fyi_tests_release_trybot_x86', @@ -1181,11 +1182,11 @@ # Cast Linux takes very long in linking, possibly due to being on GCE # (crbug/794423). 'cast_release_bot': [ - 'cast', 'release_bot', 'minimal_symbols', + 'cast', 'cast_exo', 'release_bot', 'minimal_symbols', ], 'cast_release_trybot': [ - 'cast', 'release_trybot', + 'cast', 'cast_exo', 'release_trybot', ], 'cast_audio_release_bot': [ @@ -1955,6 +1956,10 @@ 'gn_args': 'is_cast_audio_only=true' }, + 'cast_exo': { + 'gn_args': 'enable_cast_wayland_server=true', + }, + 'cfi': { 'gn_args': 'is_cfi=true', },
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index f8a6504..2e288dac 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -9344,7 +9344,9 @@ <int value="15" label="RESOURCE_TYPE_SERVICE_WORKER"/> <int value="16" label="RESOURCE_TYPE_CSP_REPORT"/> <int value="17" label="RESOURCE_TYPE_PLUGIN_RESOURCE"/> - <int value="18" label="RESOURCE_TYPE_NAVIGATION_PRELOAD"/> + <int value="18" label="RESOURCE_TYPE_NAVIGATION_PRELOAD (obsolete)"/> + <int value="19" label="RESOURCE_TYPE_NAVIGATION_PRELOAD_MAIN_FRAME"/> + <int value="20" label="RESOURCE_TYPE_NAVIGATION_PRELOAD_SUB_FRAME"/> </enum> <enum name="ContentSetting"> @@ -34198,6 +34200,7 @@ <int value="-1250611337" label="ChromeVoxArcSupport:disabled"/> <int value="-1248478422" label="enable-zip-archiver-packer"/> <int value="-1246840031" label="OptInImeMenu:disabled"/> + <int value="-1243694853" label="DeferAllScript:disabled"/> <int value="-1241747717" label="enable-android-password-link"/> <int value="-1241002324" label="FocusMode:enabled"/> <int value="-1239262870" label="TextFragmentAnchor:enabled"/> @@ -34881,9 +34884,11 @@ <int value="-262122630" label="ArcEnableDocumentsProviderInFilesApp:enabled"/> <int value="-260355779" label="UnfilteredBluetoothDevices:enabled"/> <int value="-258081634" label="AutofillAssistantDirectActions:disabled"/> + <int value="-255264176" label="OmniboxSearchEngineLogo:disabled"/> <int value="-254887599" label="google-profile-info"/> <int value="-250822813" label="PwaImprovedSplashScreen:enabled"/> <int value="-250721831" label="AndroidAutofillAccessibility:disabled"/> + <int value="-250543540" label="DeferAllScript:enabled"/> <int value="-248223420" label="AutofillKeyboardAccessory:disabled"/> <int value="-243323793" label="OmniboxOnDeviceHeadProvider:enabled"/> <int value="-241353344" label="MidiManagerWinrt:disabled"/> @@ -35135,6 +35140,7 @@ <int value="98134240" label="material-design-ink-drop-animation-speed"/> <int value="98218116" label="ContextualSearchLongpressResolve:disabled"/> <int value="99177659" label="OmniboxUICuesForSearchHistoryMatches:disabled"/> + <int value="103347629" label="WinrtSensorsImplementation:enabled"/> <int value="103932290" label="show-autofill-type-predictions"/> <int value="105046382" label="ParallelDownloading:disabled"/> <int value="106840653" label="mus"/> @@ -35395,6 +35401,7 @@ label="AutofillEnforceMinRequiredFieldsForQuery:enabled"/> <int value="510814146" label="OfflineBookmarks:enabled"/> <int value="511179195" label="ShoppingAssist:disabled"/> + <int value="513258875" label="WinrtSensorsImplementation:disabled"/> <int value="513356954" label="InstantTethering:disabled"/> <int value="513372959" label="ViewsProfileChooser:enabled"/> <int value="517429103" label="AutofillImportDynamicForms:enabled"/> @@ -36505,6 +36512,7 @@ <int value="2126203058" label="force-show-update-menu-badge"/> <int value="2129184006" label="NTPOfflinePageDownloadSuggestions:enabled"/> <int value="2129929643" label="enable-use-zoom-for-dsf"/> + <int value="2132595171" label="OmniboxSearchEngineLogo:enabled"/> <int value="2134480727" label="MediaSessionAccelerators:disabled"/> <int value="2135408204" label="OverscrollHistoryNavigation:disabled"/> <int value="2137113620"
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 4a3ecc5..1d7fc19 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -4923,8 +4923,9 @@ </histogram> <histogram name="Apps.LockScreen.AppsProfile.Creation.Duration" units="ms" - expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> The amount of time needed to create a lock screen apps profile. This metric is recorded only if the profile creation was successful. The lock screen @@ -4935,8 +4936,9 @@ </histogram> <histogram name="Apps.LockScreen.AppsProfile.Creation.Success" - units="BooleanSuccess" expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + units="BooleanSuccess" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> Boolean indicating whether the lock screen apps profile creation succeeded. The lock screen apps profile is created if the user has an app enabled on @@ -4946,8 +4948,9 @@ </histogram> <histogram name="Apps.LockScreen.DataItemStorage.ClearTextItemSize" - units="bytes" expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + units="bytes" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> The size of a data item stored in the lock screen data item storage using chrome.lockScreen.data API as sent from the app - the item will be encrypted @@ -4956,8 +4959,9 @@ </histogram> <histogram name="Apps.LockScreen.DataItemStorage.EncryptedItemSize" - units="bytes" expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + units="bytes" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> The size of an encrypted data item stored in the lock screen data item storage using chrome.lockScreen.data API. @@ -4965,8 +4969,10 @@ </histogram> <histogram base="true" - name="Apps.LockScreen.DataItemStorage.FailedOperationDuration" units="ms"> - <owner>tbarzic@chromium.org</owner> + name="Apps.LockScreen.DataItemStorage.FailedOperationDuration" units="ms" + expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> The amount of time it took to complete a lock screen data item storage operation. Reported only on the operation failure. @@ -4974,8 +4980,9 @@ </histogram> <histogram base="true" name="Apps.LockScreen.DataItemStorage.OperationDuration" - units="ms"> - <owner>tbarzic@chromium.org</owner> + units="ms" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> The amount of time it took to complete a lock screen data item storage operation. Reported only on the operation success. @@ -4983,8 +4990,9 @@ </histogram> <histogram base="true" name="Apps.LockScreen.DataItemStorage.OperationResult" - enum="LockScreenDataItemOperationResult"> - <owner>tbarzic@chromium.org</owner> + enum="LockScreenDataItemOperationResult" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> The result of a lock screen data item storage operation returned through chrome.lockScreen.data extension API. @@ -4992,8 +5000,9 @@ </histogram> <histogram name="Apps.LockScreen.DataItemStorage.RegisteredItemsCount" - expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> The number of data items saved in the lock screen data item storage per app. This is recorded on startup, when the app attempts to use the @@ -5002,8 +5011,9 @@ </histogram> <histogram name="Apps.LockScreen.NoteTakingApp.AppStatusOnNoteLaunch" - enum="LockScreenNoteAppStatusOnLaunch" expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + enum="LockScreenNoteAppStatusOnLaunch" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> Reported when a user attempts to launch a note taking app on the lock screen. It reports the note taking app state in the lock screen apps profile @@ -5013,8 +5023,9 @@ </histogram> <histogram base="true" name="Apps.LockScreen.NoteTakingApp.AppWindowLifeTime" - units="ms"> - <owner>tbarzic@chromium.org</owner> + units="ms" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> The amount of time a lock screen enabled app window spent in a certain state @@ -5025,8 +5036,8 @@ </histogram> <histogram name="Apps.LockScreen.NoteTakingApp.AvailabilityOnScreenLock" - enum="LockScreenActionAvailability" expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + enum="LockScreenActionAvailability" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> The note taking action availability state on the lock screen, recorded when @@ -5035,8 +5046,8 @@ </histogram> <histogram name="Apps.LockScreen.NoteTakingApp.FinalAppSessionState" - enum="LockScreenAppSessionState" expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + enum="LockScreenAppSessionState" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> The state in which lock screen enabled note taking app was when the note @@ -5045,8 +5056,8 @@ </histogram> <histogram name="Apps.LockScreen.NoteTakingApp.LaunchDurationAtLaunchCancel" - units="ms"> - <owner>tbarzic@chromium.org</owner> + units="ms" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> The amount time a lock screen app had been launching when the app launch was @@ -5055,8 +5066,9 @@ </summary> </histogram> -<histogram name="Apps.LockScreen.NoteTakingApp.LaunchRequestOrdinalNumber"> - <owner>tbarzic@chromium.org</owner> +<histogram name="Apps.LockScreen.NoteTakingApp.LaunchRequestOrdinalNumber" + expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> Ordinal number of a note taking app launch request from a lock screen within @@ -5067,8 +5079,8 @@ </histogram> <histogram name="Apps.LockScreen.NoteTakingApp.LaunchRequestReason" - enum="NewLockScreenNoteRequestType" expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + enum="NewLockScreenNoteRequestType" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> The user action that launched note taking from the lock screen. @@ -5076,8 +5088,9 @@ </histogram> <histogram name="Apps.LockScreen.NoteTakingApp.LockScreenAppUnloaded" - enum="LockScreenAppUnloadStatus" expires_after="M78"> - <owner>tbarzic@chromium.org</owner> + enum="LockScreenAppUnloadStatus" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> Reported when a note taking app is unloaded from the lock screen apps profile while lock screen note taking is available. Reports the unload @@ -5089,8 +5102,8 @@ </histogram> <histogram name="Apps.LockScreen.NoteTakingApp.LockScreenInstallationDuration" - units="ms" expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + units="ms" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> Amount of time needed to install a copy of a lock screen note taking app @@ -5099,8 +5112,8 @@ </histogram> <histogram name="Apps.LockScreen.NoteTakingApp.NoteTakingExitReason" - enum="LockScreenNoteTakingExitReason" expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + enum="LockScreenNoteTakingExitReason" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> The reason the note taking on lock screen was ended (and lock screen app @@ -5109,8 +5122,9 @@ </histogram> <histogram name="Apps.LockScreen.NoteTakingApp.ReloadCountOnAppTermination" - expires_after="M78"> - <owner>tbarzic@chromium.org</owner> + expires_after="M85"> + <owner>dstockwell@chromium.org</owner> + <owner>tbuckley@chromium.org</owner> <summary> Reported when a note taking app is terminated in the lock screen apps profile. It reports the number of times the app was reloaded in the lock @@ -5120,8 +5134,8 @@ </histogram> <histogram name="Apps.LockScreen.NoteTakingApp.TimeToLoadAppWindowContents" - units="ms"> - <owner>tbarzic@chromium.org</owner> + units="ms" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> The amount of time needed to load a note taking app window contents on the @@ -5130,8 +5144,9 @@ </summary> </histogram> -<histogram name="Apps.LockScreen.NoteTakingApp.TimeToShowWindow" units="ms"> - <owner>tbarzic@chromium.org</owner> +<histogram name="Apps.LockScreen.NoteTakingApp.TimeToShowWindow" units="ms" + expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> The amount of time needed to launch a note taking app window from the lock @@ -5142,6 +5157,9 @@ <histogram name="Apps.LockScreen.NoteTakingApp.UnlockUIAction" enum="LockScreenNoteTakingUnlockUIAction"> + <obsolete> + Obsolete - tracks actions in UI that did not launch. + </obsolete> <owner>tbarzic@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> @@ -5162,8 +5180,8 @@ </histogram> <histogram name="Apps.NoteTakingApp.DefaultLaunchResult" - enum="NoteTakingAppLaunchResult"> - <owner>tbarzic@chromium.org</owner> + enum="NoteTakingAppLaunchResult" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> The result of attempting to launch a default note-taking app on Chrome OS. @@ -5172,8 +5190,8 @@ </histogram> <histogram name="Apps.NoteTakingApp.PreferredLaunchResult" - enum="NoteTakingAppLaunchResult" expires_after="M77"> - <owner>tbarzic@chromium.org</owner> + enum="NoteTakingAppLaunchResult" expires_after="M85"> + <owner>dstockwell@chromium.org</owner> <owner>tbuckley@chromium.org</owner> <summary> The result of attempting to launch the user-specified preferred note-taking @@ -11828,8 +11846,9 @@ </summary> </histogram> -<histogram name="BackgroundSync.Event.BatchSize" expires_after="M77"> - <owner>iclelland@chromium.org</owner> +<histogram name="BackgroundSync.Event.BatchSize" expires_after="M85"> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Records the number of sync events which were fired in a batch. A batch is defined as the set of sync events dispatched at the same time by the @@ -11850,8 +11869,9 @@ </histogram> <histogram name="BackgroundSync.Event.OneShotResultPattern" - enum="BackgroundSyncResultPattern" expires_after="M77"> - <owner>jkarlin@chromium.org</owner> + enum="BackgroundSyncResultPattern" expires_after="M85"> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Records whether a periodic sync event succeeded or failed and whether the sync event finished in the foreground or background. @@ -11863,8 +11883,9 @@ </histogram> <histogram name="BackgroundSync.Event.OneShotStartedInForeground" - enum="BooleanInForeground" expires_after="M77"> - <owner>jkarlin@chromium.org</owner> + enum="BooleanInForeground" expires_after="M85"> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Records whether a one-shot sync started firing in the foreground or background. Called shortly before the event is fired. @@ -11909,8 +11930,9 @@ </summary> </histogram> -<histogram name="BackgroundSync.Event.Time" units="ms"> - <owner>iclelland@chromium.org</owner> +<histogram name="BackgroundSync.Event.Time" units="ms" expires_after="M85"> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Time taken to execute a batch of sync events. A batch is defined as the set of sync events dispatched at the same time by the BackgroundSyncManager. @@ -11921,8 +11943,9 @@ </histogram> <histogram name="BackgroundSync.LaunchTask.CancelSuccess" enum="BooleanSuccess" - expires_after="M77"> - <owner>iclelland@chromium.org</owner> + expires_after="M80"> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Records the result of attempting to cancel a future browser launch using the GCM Network Manager on Android. @@ -11930,8 +11953,9 @@ </histogram> <histogram name="BackgroundSync.LaunchTask.PlayServicesAvailable" - enum="Boolean" expires_after="M77"> - <owner>iclelland@chromium.org</owner> + enum="Boolean" expires_after="M80"> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Records whether Google Play Services is available to the Background Sync system on Android, for scheduling future sync events when the browser is not @@ -11941,7 +11965,8 @@ <histogram name="BackgroundSync.LaunchTask.ScheduleSuccess" enum="BooleanSuccess"> - <owner>iclelland@chromium.org</owner> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Records the result of attempting to schedule a future browser launch using the GCM Network Manager on Android. @@ -11950,7 +11975,8 @@ <histogram name="BackgroundSync.NetworkObserver.HasPermission" enum="Boolean" expires_after="M78"> - <owner>iclelland@chromium.org</owner> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Records whether the browser has sufficient permissions to create a BackgroundSyncNetworkObserver object on Android, at the point when it tries @@ -11986,7 +12012,8 @@ <histogram name="BackgroundSync.Registration.OneShot" enum="BackgroundSyncStatus"> - <owner>iclelland@chromium.org</owner> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Records the result of attempting to register a one-shot sync. </summary> @@ -11994,7 +12021,8 @@ <histogram name="BackgroundSync.Registration.OneShot.CouldFire" enum="BooleanCouldFireImmediately"> - <owner>iclelland@chromium.org</owner> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Records the result of attempting to register a one-shot sync in a situation where the sync could fire immediately. @@ -12015,7 +12043,8 @@ <histogram name="BackgroundSync.Registration.OneShot.IsDuplicate" enum="BooleanRegistrationIsDuplicate" expires_after="M78"> - <owner>iclelland@chromium.org</owner> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> Records whether a one-shot sync registration exactly duplicates an existing registered sync. @@ -20646,8 +20675,9 @@ </histogram> <histogram name="ContentSettings.ExceptionScheme" enum="ContentSettingScheme" - expires_after="M77"> - <owner>lshang@chromium.org</owner> + expires_after="M87"> + <owner>alexmos@chromium.org</owner> + <owner>engedy@chromium.org</owner> <summary> Records the schemes of content setting exceptions at browser start. Each exception provides one sample. @@ -20655,8 +20685,9 @@ </histogram> <histogram name="ContentSettings.ExceptionSchemeFile.HasPath" - enum="BooleanHasPath" expires_after="M77"> + enum="BooleanHasPath" expires_after="M87"> <owner>alexmos@chromium.org</owner> + <owner>engedy@chromium.org</owner> <summary> Records how often a content settings exception for the file: scheme has a non-empty path. Recorded once per exception at browser start. @@ -20664,8 +20695,9 @@ </histogram> <histogram name="ContentSettings.ExceptionSchemeFile.Type.WithoutPath" - enum="ContentType" expires_after="M77"> + enum="ContentType" expires_after="M87"> <owner>alexmos@chromium.org</owner> + <owner>engedy@chromium.org</owner> <summary> Count of how often a specific content type has a content settings exception defined for a file: scheme with no path (i.e., wildcard path). Recorded once @@ -20677,8 +20709,9 @@ </histogram> <histogram name="ContentSettings.ExceptionSchemeFile.Type.WithPath" - enum="ContentType" expires_after="M77"> + enum="ContentType" expires_after="M87"> <owner>alexmos@chromium.org</owner> + <owner>engedy@chromium.org</owner> <summary> Count of how often a specific content type has a content settings exception defined for a file: scheme with a valid, non-empty path. Recorded once per @@ -20733,7 +20766,7 @@ </histogram> <histogram name="ContentSettings.MixedScript" - enum="ContentSettingMixedScriptAction" expires_after="M77"> + enum="ContentSettingMixedScriptAction" expires_after="M80"> <owner>estark@chromium.org</owner> <summary> Tracks whether the mixed content shield was shown, and how the user @@ -40241,6 +40274,20 @@ </summary> </histogram> +<histogram name="Extensions.ForceInstalledTotalCandidateCount" + expires_after="2019-11-01"> + <owner>poromov@chromium.org</owner> + <owner>askaraitzhan@google.com</owner> + <owner>burunduk@chromium.org</owner> + <summary> + Total amount of extensions in force installed list. Gets recorded on profile + open (which happens on every startup and when user logs in) and tries to + load extensions. Number of records should correspond to the sum of records + in "Extensions.ForceInstalledLoadTime" and records in + "Extensions.ForceInstalledTimedOutAndNotInstalledCount". + </summary> +</histogram> + <histogram name="Extensions.FromWebstoreInconsistency" enum="ExtensionFromWebstoreInconcistencyEnum" expires_after="2018-08-30"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> @@ -44112,6 +44159,9 @@ <histogram name="FileSystem.OriginFailedCanCommitURL" enum="BooleanHit" expires_after="M77"> + <obsolete> + Removed July 2019. + </obsolete> <owner>alexmos@chromium.org</owner> <summary> Logged when we fail the permission validation of the filesystem URL origin, @@ -52154,7 +52204,7 @@ </histogram> <histogram name="IOS.RepeatedExternalAppPromptResponse" - enum="IOSRepeatedExternalAppPromptResponse" expires_after="M77"> + enum="IOSRepeatedExternalAppPromptResponse" expires_after="2020-07-01"> <owner>mrefaat@chromium.org</owner> <summary> The user reaction to the prompt that appears when a website tries to open an @@ -52290,7 +52340,7 @@ </histogram> <histogram name="IOS.StoreKit.ITunesURLsHandlingResult" - enum="IOSITunesURLsStoreKitHandlingResult" expires_after="M77"> + enum="IOSITunesURLsStoreKitHandlingResult" expires_after="2020-07-01"> <owner>mrefaat@chromium.org</owner> <owner>eugenebut@chromium.org</owner> <summary> @@ -52302,7 +52352,7 @@ </histogram> <histogram name="IOS.StoreKitLoadedSuccessfully" enum="BooleanSuccess" - expires_after="M77"> + expires_after="2020-07-01"> <owner>mrefaat@chromium.org</owner> <summary> Whether the StoreKit loaded the required iTunes product successfully or not. @@ -52587,6 +52637,9 @@ <histogram name="Keyboard.Shortcuts.CrosSearchKeyDelay" units="ms" expires_after="M77"> + <obsolete> + Deprecated 2019-07. Search key shortcut analysis is done. + </obsolete> <owner>xiaohuic@chromium.org</owner> <owner>zalcorn@chromium.org</owner> <summary> @@ -56428,7 +56481,11 @@ </histogram> <histogram name="Media.DetectedTrackCount.Audio" expires_after="M77"> + <obsolete> + Deprecated 07/2019 in issue 975315. + </obsolete> <owner>wolenetz@chromium.org</owner> + <owner>media-dev@chromium.org</owner> <summary> Number of detected audio tracks in HTML5 media. Not all may be usable by the player. @@ -56436,15 +56493,23 @@ </histogram> <histogram name="Media.DetectedTrackCount.Text" expires_after="M77"> + <obsolete> + Deprecated 07/2019 in issue 975315. + </obsolete> <owner>wolenetz@chromium.org</owner> + <owner>media-dev@chromium.org</owner> <summary> Number of detected text tracks in HTML5 media. Not all may be usable by the player. </summary> </histogram> -<histogram name="Media.DetectedTrackCount.Video"> +<histogram name="Media.DetectedTrackCount.Video" expires_after="M77"> + <obsolete> + Deprecated 07/2019 in issue 975315. + </obsolete> <owner>wolenetz@chromium.org</owner> + <owner>media-dev@chromium.org</owner> <summary> Number of detected video tracks in HTML5 media. Not all may be usable by the player. @@ -57692,8 +57757,12 @@ <owner>wolenetz@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> - Audio codec used in Media Source Extensions playback. Set when AddId() is - called during playback. + Audio codec used in Media Source Extensions playback. Set when MediaSource + addSourceBuffer() is successfully called during playback. Also set twice + during a successful SourceBuffer changeType() operation. See issue 535738 + for reworking MSE codec histograms to record on each successfully parsed + initialization segment (possibly filtered to record only when actual new + codec configurations are parsed). </summary> </histogram> @@ -57743,7 +57812,11 @@ </histogram> <histogram name="Media.MSE.DetectedTrackCount.Audio" expires_after="M77"> + <obsolete> + Deprecated 07/2019 in issue 975090. + </obsolete> <owner>wolenetz@chromium.org</owner> + <owner>media-dev@chromium.org</owner> <summary> Number of detected audio tracks in Media Source Extensions playback. Not all may be usable by the player. @@ -57751,7 +57824,11 @@ </histogram> <histogram name="Media.MSE.DetectedTrackCount.Text" expires_after="M77"> + <obsolete> + Deprecated 07/2019 in issue 975090. + </obsolete> <owner>wolenetz@chromium.org</owner> + <owner>media-dev@chromium.org</owner> <summary> Number of detected text tracks in Media Source Extensions playback. Not all may be usable by the player. This count includes only explicitly signalled @@ -57760,8 +57837,12 @@ </summary> </histogram> -<histogram name="Media.MSE.DetectedTrackCount.Video"> +<histogram name="Media.MSE.DetectedTrackCount.Video" expires_after="M77"> + <obsolete> + Deprecated 07/2019 in issue 975090. + </obsolete> <owner>wolenetz@chromium.org</owner> + <owner>media-dev@chromium.org</owner> <summary> Number of detected video tracks in Media Source Extensions playback. Not all may be usable by the player. @@ -57855,7 +57936,11 @@ </histogram> <histogram name="Media.MSE.NumberOfTracks" expires_after="M77"> - <owner>acolwell@chromium.org</owner> + <obsolete> + Deprecated 07/2019 in issue 975898. + </obsolete> + <owner>wolenetz@chromium.org</owner> + <owner>media-dev@chromium.org</owner> <summary> Number of tracks specified to AddId() for Media Source Extensions playback. May be called multiple times per element if playback is dynamically altered. @@ -57909,8 +57994,12 @@ <owner>wolenetz@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> - Video codec used in Media Source Extensions playback. Set when AddId() is - called during playback. + Video codec used in Media Source Extensions playback. Set when MediaSource + addSourceBuffer() is successfully called during playback. Also set twice + during a successful SourceBuffer changeType() operation. See issue 535738 + for reworking MSE codec histograms to record on each successfully parsed + initialization segment (possibly filtered to record only when actual new + codec configurations are parsed). </summary> </histogram> @@ -57922,7 +58011,11 @@ <owner>media-dev@chromium.org</owner> <summary> Video codec used in Media Source Extensions playback if the media container - is MP4. Set when AddId() is called during playback. + is MP4. Set when MediaSource addSourceBuffer() is successfully called during + playback. Also set twice during a successful SourceBuffer changeType() + operation. See issue 535738 for reworking MSE codec histograms to record on + each successfully parsed initialization segment (possibly filtered to record + only when actual new codec configurations are parsed). </summary> </histogram> @@ -57934,7 +58027,11 @@ <owner>media-dev@chromium.org</owner> <summary> Video codec used in Media Source Extensions playback if the media container - is WebM. Set when AddId() is called during playback. + is WebM. Set when MediaSource addSourceBuffer() is successfully called + during playback. Also set twice during a successful SourceBuffer + changeType() operation. See issue 535738 for reworking MSE codec histograms + to record on each successfully parsed initialization segment (possibly + filtered to record only when actual new codec configurations are parsed). </summary> </histogram> @@ -58530,6 +58627,9 @@ <histogram name="Media.SRC.PreloadAutoHasPoster" enum="Boolean" expires_after="M77"> + <obsolete> + Deprecated 07/2019 in issue 975367. + </obsolete> <owner>media-dev@chromium.org</owner> <summary> Whether a SRC= playback had a poster set at load() when the effective @@ -58541,6 +58641,9 @@ <histogram name="Media.SRC.PreloadMetaDataHasPoster" enum="Boolean" expires_after="M77"> + <obsolete> + Deprecated 07/2019 in issue 975367. + </obsolete> <owner>media-dev@chromium.org</owner> <summary> Whether a SRC= playback had a poster set at load() when the effective @@ -59077,6 +59180,9 @@ <histogram name="Media.Video.FullscreenOrientationLock.LockResult" enum="VideoFullscreenOrientationLockResult" expires_after="M77"> + <obsolete> + Removed from code as of 07/2019. + </obsolete> <owner>mlamouri@chromium.org</owner> <summary> Result of the orientation lock attempt when a video enters fullscreen. @@ -68520,6 +68626,16 @@ </summary> </histogram> +<histogram name="Net.CertVerifier.PathBuilderIterationCount" + expires_after="2020-07-01"> + <owner>mattm@chromium.org</owner> + <owner>net-dev@chromium.org</owner> + <summary> + When using the builtin cert verifier, records the number of iterations taken + during path building for each attempted verification. + </summary> +</histogram> + <histogram name="Net.CertVerifier_First_Job_Latency" units="ms" expires_after="M83"> <owner>mattm@chromium.org</owner> @@ -78578,16 +78694,20 @@ </histogram> <histogram name="Network.Shill.DarkResumeActionResult" - enum="ShillSuspendTerminationDarkResumeActionResult" expires_after="M77"> + enum="ShillSuspendTerminationDarkResumeActionResult" + expires_after="2020-06-01"> <owner>benchan@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network diagnostic metric sampling the number of dark resume actions that successfully complete or fail when shill suspends. </summary> </histogram> -<histogram name="Network.Shill.DarkResumeActionsTimeTaken" units="ms"> +<histogram name="Network.Shill.DarkResumeActionsTimeTaken" units="ms" + expires_after="2020-06-01"> <owner>benchan@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network diagnostic metric sampling the time in milliseconds it takes dark resume actions to complete when shill suspends. @@ -78606,8 +78726,10 @@ </summary> </histogram> -<histogram name="Network.Shill.DarkResumeScanNumRetries"> +<histogram name="Network.Shill.DarkResumeScanNumRetries" + expires_after="2020-06-01"> <owner>benchan@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network metric sampling the number of times a dark resume scan is retried in a single dark resume. @@ -78615,8 +78737,9 @@ </histogram> <histogram name="Network.Shill.DarkResumeScanRetryResult" - enum="DarkResumeScanRetryResult"> + enum="DarkResumeScanRetryResult" expires_after="2020-06-01"> <owner>benchan@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network metric that tracks whether dark resume scan retries led to the system suspending from dark resume in a connected state. This metric is @@ -78646,8 +78769,8 @@ </histogram> <histogram name="Network.Shill.DHCPClientMTUValue" units="bytes" - expires_after="M77"> - <owner>pstew@chromium.org</owner> + expires_after="2020-06-01"> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network diagnostic metric sampling the MTU value proposed by the DHCP server. A sample is emitted each time the DHCP client completes @@ -78655,8 +78778,9 @@ </summary> </histogram> -<histogram name="Network.Shill.DHCPClientStatus" enum="NetworkDhcpClientStatus"> - <owner>pstew@chromium.org</owner> +<histogram name="Network.Shill.DHCPClientStatus" enum="NetworkDhcpClientStatus" + expires_after="2020-06-01"> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network diagnostic metric sampling the current state of the DHCP client. A sample is emitted each time the DHCP client state changes. @@ -78664,8 +78788,9 @@ </histogram> <histogram name="Network.Shill.DHCPOptionFailureDetected" - enum="NetworkTechnology"> + enum="NetworkTechnology" expires_after="2020-06-01"> <owner>benchan@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network metric that tracks the number of DHCP option failures encountered by Shill for each network technology. This indicates that Shill @@ -78987,8 +79112,10 @@ <summary>Chrome OS connection manager service errors seen.</summary> </histogram> -<histogram name="Network.Shill.ServicesOnSameNetwork" expires_after="M77"> +<histogram name="Network.Shill.ServicesOnSameNetwork" + expires_after="2020-06-01"> <owner>benchan@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network metric sampling the number of services that are connected to the currently connected network. @@ -78996,16 +79123,20 @@ </histogram> <histogram name="Network.Shill.SuspendActionResult" - enum="ShillSuspendTerminationDarkResumeActionResult" expires_after="M77"> + enum="ShillSuspendTerminationDarkResumeActionResult" + expires_after="2020-06-01"> <owner>benchan@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network diagnostic metric sampling the number of suspend actions that successfully complete or fail when shill suspends. </summary> </histogram> -<histogram name="Network.Shill.SuspendActionsTimeTaken" units="ms"> +<histogram name="Network.Shill.SuspendActionsTimeTaken" units="ms" + expires_after="2020-06-01"> <owner>benchan@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network diagnostic metric sampling the time in milliseconds it takes suspend actions to complete when shill suspends. @@ -79025,8 +79156,10 @@ </histogram> <histogram name="Network.Shill.TerminationActionResult" - enum="ShillSuspendTerminationDarkResumeActionResult" expires_after="M77"> + enum="ShillSuspendTerminationDarkResumeActionResult" + expires_after="2020-06-01"> <owner>benchan@chromium.org</owner> + <owner>cros-network-metrics@google.com</owner> <summary> Chrome OS network diagnostic metric sampling the number of termination actions that successfully complete or fail when shill terminates. Previously @@ -89654,6 +89787,9 @@ <histogram name="PageLoad.Clients.AMP.InteractiveTiming.FirstInputDelay3.Subframe" units="ms"> + <obsolete> + Removed July 2019 in favor of FirstInputDelay4. + </obsolete> <owner>bmcquade@chromium.org</owner> <summary> Measures First Input Delay, the duration between the hardware timestamp and @@ -89667,6 +89803,35 @@ <histogram name="PageLoad.Clients.AMP.InteractiveTiming.FirstInputDelay3.Subframe.FullNavigation" units="ms" expires_after="M78"> + <obsolete> + Removed July 2019 in favor of FirstInputDelay4. + </obsolete> + <owner>bmcquade@chromium.org</owner> + <summary> + Measures First Input Delay, the duration between the hardware timestamp and + the start of event processing on the main thread for the first meaningful + input per navigation, in an AMP subframe document. Recorded on first page + interaction. See https://goo.gl/tr1oTZ for a detailed explanation. Excludes + scrolls. Only non-same-document navigations are included. + </summary> +</histogram> + +<histogram + name="PageLoad.Clients.AMP.InteractiveTiming.FirstInputDelay4.Subframe" + units="ms"> + <owner>bmcquade@chromium.org</owner> + <summary> + Measures First Input Delay, the duration between the hardware timestamp and + the start of event processing on the main thread for the first meaningful + input per navigation, in an AMP subframe document. Recorded on first page + interaction. See https://goo.gl/tr1oTZ for a detailed explanation. Excludes + scrolls. Only same-document navigations are included. + </summary> +</histogram> + +<histogram + name="PageLoad.Clients.AMP.InteractiveTiming.FirstInputDelay4.Subframe.FullNavigation" + units="ms"> <owner>bmcquade@chromium.org</owner> <summary> Measures First Input Delay, the duration between the hardware timestamp and @@ -110602,6 +110767,19 @@ </summary> </histogram> +<histogram + name="ResourceScheduler.BrowserInitiatedHeavyRequest.QueuingDuration" + units="ms" expires_after="M82"> + <owner>tbansal@chromium.org</owner> + <summary> + The amount of time the ResourceScheduler queued a browser initiated request + that was expected to be heavy (i.e., has large request/response sizes). + Recorded when the request is dispatched by the resource scheduler to the + network stack. Recorded only when the traffic annotation tag of the request + is present in the set of annotation tags that can be throttled. + </summary> +</histogram> + <histogram name="ResourceScheduler.ClientLoadedTime.Active" expires_after="2016-01-29"> <obsolete> @@ -119014,8 +119192,9 @@ </histogram> <histogram name="ServiceWorker.BackgroundSyncEvent.Time" units="ms" - expires_after="M77"> - <owner>jkarlin@chromium.org</owner> + expires_after="M85"> + <owner>nator@chromium.org</owner> + <owner>rayankans@chromium.org</owner> <summary> The time taken between dispatching a SyncEvent to a Service Worker and receiving a message that it finished handling the event. Includes the time @@ -125347,6 +125526,21 @@ </summary> </histogram> +<histogram base="true" + name="SiteIsolation.CORBProtection.CacheHeuristic.ProtectedMimeType" + enum="BooleanSupported" expires_after="M79"> +<!-- suffixed with Block*WithRangeSupport --> + + <owner>krstnmnlsn@chromium.org</owner> + <owner>creis@chromium.org</owner> + <summary> + True if the response has an Accept-Ranges header, which indicates the server + supports range requests on the resource and could be used to bypass CORB. + Only reported if the resource looked sensitive under the Cache heuristic and + was a protected MIME type. + </summary> +</histogram> + <histogram base="true" name="SiteIsolation.CORBProtection.CORSHeuristic" enum="CrossOriginProtectionDecision" expires_after="M79"> <owner>krstnmnlsn@chromium.org</owner> @@ -125359,6 +125553,21 @@ </summary> </histogram> +<histogram base="true" + name="SiteIsolation.CORBProtection.CORSHeuristic.ProtectedMimeType" + enum="BooleanSupported" expires_after="M79"> +<!-- suffixed with Block*WithRangeSupport --> + + <owner>krstnmnlsn@chromium.org</owner> + <owner>creis@chromium.org</owner> + <summary> + True if the response has an Accept-Ranges header, which indicates the server + supports range requests on the resource and could be used to bypass CORB. + Only reported if the resource looked sensitive under the CORS heuristic and + was a protected MIME type. + </summary> +</histogram> + <histogram name="SiteIsolation.CORBProtection.SensitiveResource" enum="BooleanSensitive" expires_after="M79"> <owner>krstnmnlsn@chromium.org</owner> @@ -125376,7 +125585,7 @@ <summary> True if the response has an Accept-Ranges header, which indicates the server supports range requests on the resource. Only reported if the response - looked sensitive under the CORS or CORB heuristics. + looked sensitive under the cache or CORS heuristics. </summary> </histogram> @@ -134067,7 +134276,7 @@ </histogram> <histogram name="Tab.ExternalApplicationOpened" enum="ExternalLauncherOption" - expires_after="M77"> + expires_after="2020-07-01"> <owner>mrefaat@chromium.org</owner> <summary> [iOS] Used on External App launcher Prompt to determine if the user clicked @@ -134747,7 +134956,7 @@ <histogram name="TabManager.BackgroundTabOpening.ForegroundTab.ExpectedTaskQueueingDuration" - units="ms"> + units="ms" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135010,7 +135219,7 @@ <histogram name="TabManager.Experimental.BackgroundTabOpening.CompressedPagesPerSecond" - units="pages/s"> + units="pages/s" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135028,7 +135237,7 @@ <histogram name="TabManager.Experimental.BackgroundTabOpening.DecompressedPagesPerSecond" - units="pages/s"> + units="pages/s" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135045,7 +135254,7 @@ </histogram> <histogram name="TabManager.Experimental.BackgroundTabOpening.SwapInPerSecond" - units="swaps/s"> + units="swaps/s" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135061,7 +135270,7 @@ </histogram> <histogram name="TabManager.Experimental.BackgroundTabOpening.SwapOutPerSecond" - units="swaps/s"> + units="swaps/s" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135124,7 +135333,7 @@ <histogram name="TabManager.Experimental.SessionRestore.CompressedPagesPerSecond" - units="pages/s" expires_after="M78"> + units="pages/s" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135143,7 +135352,7 @@ <histogram name="TabManager.Experimental.SessionRestore.DecompressedPagesPerSecond" - units="pages/s" expires_after="M78"> + units="pages/s" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135162,7 +135371,7 @@ <histogram name="TabManager.Experimental.SessionRestore.ForegroundTab.FirstContentfulPaint" - units="ms" expires_after="M78"> + units="ms" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135173,7 +135382,7 @@ <histogram name="TabManager.Experimental.SessionRestore.ForegroundTab.FirstMeaningfulPaint" - units="ms"> + units="ms" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135184,7 +135393,7 @@ <histogram name="TabManager.Experimental.SessionRestore.ForegroundTab.FirstPaint" - units="ms" expires_after="M78"> + units="ms" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135194,7 +135403,7 @@ </histogram> <histogram name="TabManager.Experimental.SessionRestore.SwapInPerSecond" - units="swaps/s" expires_after="M77"> + units="swaps/s" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135211,7 +135420,7 @@ </histogram> <histogram name="TabManager.Experimental.SessionRestore.SwapOutPerSecond" - units="swaps/s" expires_after="M77"> + units="swaps/s" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135255,7 +135464,7 @@ <histogram name="TabManager.Experimental.SessionRestore.TabSwitchLoadTime.UntilTabIsLoaded" - units="ms" expires_after="M78"> + units="ms" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135401,7 +135610,7 @@ <histogram name="TabManager.SessionRestore.ForegroundTab.ExpectedTaskQueueingDuration" - units="ms"> + units="ms" expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -135449,7 +135658,7 @@ </histogram> <histogram name="TabManager.SessionRestore.SwitchToTab" enum="TabLoadingState" - expires_after="M77"> + expires_after="M79"> <owner>shaseley@chromium.org</owner> <owner>panicker@chromium.org</owner> <summary> @@ -139642,6 +139851,10 @@ </histogram> <histogram name="UMA.PersistentHistograms.TmpRemovals" expires_after="M77"> + <obsolete> + Data showed many files being deleted during rollout and then tapering off to + near zero. Removed 2019/07. + </obsolete> <owner>bcwhite@chromium.org</owner> <owner>asvitkine@chromium.org</owner> <summary> @@ -145245,7 +145458,7 @@ </histogram> <histogram name="WebController.ExternalURLRequestBlocking" - enum="IOSExternalURLRequestStatus" expires_after="M77"> + enum="IOSExternalURLRequestStatus" expires_after="2020-07-01"> <owner>mrefaat@chromium.org</owner> <summary> [iOS] Measures the proportion of external URL requests that originate from a @@ -153893,6 +154106,17 @@ <affected-histogram name="Cookie.AllAgesForSecure"/> </histogram_suffixes> +<histogram_suffixes name="CORBProtectionDecision" separator="."> + <suffix name="BlockedAfterSniffingWithRangeSupport" + label="Here the CORB protection decision was kBlockedAfterSniffing."/> + <suffix name="BlockedWithRangeSupport" + label="Here the CORB protection decision was kBlock."/> + <affected-histogram + name="SiteIsolation.CORBProtection.CacheHeuristic.ProtectedMimeType"/> + <affected-histogram + name="SiteIsolation.CORBProtection.CORSHeuristic.ProtectedMimeType"/> +</histogram_suffixes> + <histogram_suffixes name="CreditCardScanSuccess" separator="_"> <suffix name="Cancelled" label="Credit card scan was cancelled."/> <suffix name="Completed" label="Credit card scan completed."/> @@ -162884,14 +163108,6 @@ <affected-histogram name="Net.QuicSession.VerifyProofTime"/> </histogram_suffixes> -<histogram_suffixes name="RangeRequestSupportedCase" separator="."> - <suffix name="ProtectedMimeType.BlockedWithRangeSupport" - label="The response had a protected MIME type and the CORB protection - decision was kBlock."/> - <affected-histogram name="SiteIsolation.CORBProtection.CacheHeuristic"/> - <affected-histogram name="SiteIsolation.CORBProtection.CORSHeuristic"/> -</histogram_suffixes> - <histogram_suffixes name="RasterBufferProvider" separator="."> <suffix name="Gpu" label="The GpuRasterBufferProvider was in use."/> <suffix name="OneCopy" label="The OneCopyRasterBufferProvider was in use."/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index 554d967d..b7f062cf 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -269,6 +269,17 @@ </summary> </metric> <metric name="SubFrame.InteractiveTiming.FirstInputDelay3"> + <obsolete> + Removed July 2019 in favor of FirstInputDelay4. + </obsolete> + <summary> + Measures First Input Delay, the duration between the hardware timestamp + and the start of event processing on the main thread for the first + meaningful input per navigation, in the AMP subframe. See + https://goo.gl/tr1oTZ for a detailed explanation. In milliseconds. + </summary> + </metric> + <metric name="SubFrame.InteractiveTiming.FirstInputDelay4"> <summary> Measures First Input Delay, the duration between the hardware timestamp and the start of event processing on the main thread for the first
diff --git a/ui/events/blink/blink_features.cc b/ui/events/blink/blink_features.cc index a2423c48..54864b1 100644 --- a/ui/events/blink/blink_features.cc +++ b/ui/events/blink/blink_features.cc
@@ -29,7 +29,7 @@ "DontSendKeyEventsToJavascript", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kSkipTouchEventFilter{"SkipTouchEventFilter", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const char kSkipTouchEventFilterTypeParamName[] = "type"; const char kSkipTouchEventFilterTypeParamValueDiscrete[] = "discrete"; const char kSkipTouchEventFilterTypeParamValueAll[] = "all"; @@ -38,4 +38,4 @@ const char kSkipTouchEventFilterFilteringProcessParamValueBrowser[] = "browser"; const char kSkipTouchEventFilterFilteringProcessParamValueBrowserAndRenderer[] = "browser_and_renderer"; -} +} // namespace features
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc index 9783b72..73a509b 100644 --- a/ui/gl/swap_chain_presenter.cc +++ b/ui/gl/swap_chain_presenter.cc
@@ -474,6 +474,11 @@ clip_visual_->SetClip(nullptr); } } + + if (visual_info_.z_order != params.z_order) { + visual_info_.z_order = params.z_order; + layer_tree_->SetNeedsCommit(); + } } bool SwapChainPresenter::TryPresentToDecodeSwapChain(
diff --git a/ui/gl/swap_chain_presenter.h b/ui/gl/swap_chain_presenter.h index 7f31696..8758db11 100644 --- a/ui/gl/swap_chain_presenter.h +++ b/ui/gl/swap_chain_presenter.h
@@ -185,6 +185,7 @@ gfx::Transform transform; bool is_clipped = false; gfx::Rect clip_rect; + int z_order = 0; } visual_info_; // Direct composition visual containing the swap chain content. Child of
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc index 21d2931..245e7024 100644 --- a/ui/message_center/views/notification_view_md.cc +++ b/ui/message_center/views/notification_view_md.cc
@@ -803,16 +803,20 @@ header_row_->SetTimestamp(notification.timestamp()); header_row_->SetAppNameElideBehavior(gfx::ELIDE_TAIL); - base::string16 app_name = notification.display_source(); - if (notification.origin_url().is_valid() && - notification.origin_url().SchemeIsHTTPOrHTTPS()) { + base::string16 app_name; + if (notification.UseOriginAsContextMessage()) { app_name = url_formatter::FormatUrlForSecurityDisplay( notification.origin_url(), url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS); header_row_->SetAppNameElideBehavior(gfx::ELIDE_HEAD); - } else if (app_name.empty() && notification.notifier_id().type == - NotifierType::SYSTEM_COMPONENT) { + } else if (notification.display_source().empty() && + notification.notifier_id().type == + NotifierType::SYSTEM_COMPONENT) { app_name = MessageCenter::Get()->GetSystemNotificationAppName(); + } else if (!notification.context_message().empty()) { + app_name = notification.context_message(); + } else { + app_name = notification.display_source(); } header_row_->SetAppName(app_name); }
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h index fb280a8..d9d9b35 100644 --- a/ui/message_center/views/notification_view_md.h +++ b/ui/message_center/views/notification_view_md.h
@@ -207,6 +207,9 @@ const base::string16& text) override; private: + FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, AppNameExtension); + FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, AppNameSystemNotification); + FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, AppNameWebNotification); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, CreateOrUpdateTest); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, ExpandLongMessage); FRIEND_TEST_ALL_PREFIXES(NotificationViewMDTest, InlineSettings);
diff --git a/ui/message_center/views/notification_view_md_unittest.cc b/ui/message_center/views/notification_view_md_unittest.cc index 7054701..271de35c 100644 --- a/ui/message_center/views/notification_view_md_unittest.cc +++ b/ui/message_center/views/notification_view_md_unittest.cc
@@ -1316,4 +1316,40 @@ EXPECT_EQ(message_height, notification_view()->message_view_->height()); } +TEST_F(NotificationViewMDTest, AppNameExtension) { + base::string16 app_name = base::UTF8ToUTF16("extension name"); + std::unique_ptr<Notification> notification = CreateSimpleNotification(); + notification->set_context_message(app_name); + + UpdateNotificationViews(*notification); + + EXPECT_EQ(app_name, notification_view()->header_row_->app_name_for_testing()); +} + +TEST_F(NotificationViewMDTest, AppNameSystemNotification) { + base::string16 app_name = base::UTF8ToUTF16("system notification"); + message_center::MessageCenter::Get()->SetSystemNotificationAppName(app_name); + RichNotificationData data; + data.settings_button_handler = SettingsButtonHandler::INLINE; + auto notification = std::make_unique<Notification>( + NOTIFICATION_TYPE_BASE_FORMAT, std::string(kDefaultNotificationId), + base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message"), gfx::Image(), + base::string16(), GURL(), + NotifierId(NotifierType::SYSTEM_COMPONENT, "system"), data, nullptr); + + UpdateNotificationViews(*notification); + + EXPECT_EQ(app_name, notification_view()->header_row_->app_name_for_testing()); +} + +TEST_F(NotificationViewMDTest, AppNameWebNotification) { + std::unique_ptr<Notification> notification = CreateSimpleNotification(); + notification->set_origin_url(GURL("http://example.com")); + + UpdateNotificationViews(*notification); + + EXPECT_EQ(base::UTF8ToUTF16("example.com"), + notification_view()->header_row_->app_name_for_testing()); +} + } // namespace message_center
diff --git a/ui/native_theme/caption_style.h b/ui/native_theme/caption_style.h index c5084a1..811a6dd 100644 --- a/ui/native_theme/caption_style.h +++ b/ui/native_theme/caption_style.h
@@ -36,6 +36,9 @@ std::string text_shadow; std::string font_family; std::string font_variant; + std::string window_color; + std::string window_padding; + std::string window_radius; }; } // namespace ui
diff --git a/ui/native_theme/caption_style_mac.mm b/ui/native_theme/caption_style_mac.mm index c39d09d..1e20188 100644 --- a/ui/native_theme/caption_style_mac.mm +++ b/ui/native_theme/caption_style_mac.mm
@@ -121,6 +121,33 @@ *font_variant = base::SysCFStringRefToUTF8(ct_font_face_name); } +std::string GetMAWindowColorAsCSSColor() { + base::ScopedCFTypeRef<CGColorRef> cg_color( + MACaptionAppearanceCopyWindowColor(kUserDomain, nullptr)); + float opacity = MACaptionAppearanceGetWindowOpacity(kUserDomain, nullptr); + + SkColor rgba_color = + SkColorSetA(skia::CGColorRefToSkColor(cg_color.get()), 0xff * opacity); + return color_utils::SkColorToRgbaString(rgba_color); +} + +// If the window is visible (its opacity is greater than 0), give it padding so +// it surrounds the text track cue. If it is not visible, its padding should be +// 0. Webkit uses 0.4em padding so we match that here. +std::string GetMAWindowPaddingAsCSSNumberInEm() { + float opacity = MACaptionAppearanceGetWindowOpacity(kUserDomain, nullptr); + if (opacity > 0) + return "0.4em"; + + return ""; +} + +std::string GetMAWindowRadiusAsCSSNumberInPixels() { + float radius = + MACaptionAppearanceGetWindowRoundedCornerRadius(kUserDomain, nullptr); + return base::StringPrintf("%fpx", radius); +} + } // namespace // static @@ -134,6 +161,9 @@ style.background_color = GetMABackgroundColorAndOpacityAsCSSColor(); style.text_size = GetMATextScaleAsCSSPercent(); style.text_shadow = GetMATextEdgeStyleAsCSSShadow(); + style.window_color = GetMAWindowColorAsCSSColor(); + style.window_padding = GetMAWindowPaddingAsCSSNumberInEm(); + style.window_radius = GetMAWindowRadiusAsCSSNumberInPixels(); GetMAFontAsCSSFontSpecifiers(&style.font_family, &style.font_variant);
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.cc b/ui/ozone/platform/drm/gpu/drm_thread.cc index 02f98a6..2164b74 100644 --- a/ui/ozone/platform/drm/gpu/drm_thread.cc +++ b/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -181,6 +181,19 @@ } } +void DrmThread::CreateBufferAsync(gfx::AcceleratedWidget widget, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + uint32_t client_flags, + CreateBufferAsyncCallback callback) { + std::unique_ptr<GbmBuffer> buffer; + scoped_refptr<DrmFramebuffer> framebuffer; + CreateBuffer(widget, size, format, usage, client_flags, &buffer, + &framebuffer); + std::move(callback).Run(std::move(buffer), std::move(framebuffer)); +} + void DrmThread::CreateBufferFromHandle( gfx::AcceleratedWidget widget, const gfx::Size& size,
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.h b/ui/ozone/platform/drm/gpu/drm_thread.h index 2764633c..7ae9c04 100644 --- a/ui/ozone/platform/drm/gpu/drm_thread.h +++ b/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -72,6 +72,15 @@ uint32_t flags, std::unique_ptr<GbmBuffer>* buffer, scoped_refptr<DrmFramebuffer>* framebuffer); + using CreateBufferAsyncCallback = + base::OnceCallback<void(std::unique_ptr<GbmBuffer>, + scoped_refptr<DrmFramebuffer>)>; + void CreateBufferAsync(gfx::AcceleratedWidget widget, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + uint32_t flags, + CreateBufferAsyncCallback callback); void CreateBufferFromHandle(gfx::AcceleratedWidget widget, const gfx::Size& size, gfx::BufferFormat format,
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc index 8395a45..a63dadd 100644 --- a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc +++ b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
@@ -15,6 +15,20 @@ namespace ui { +namespace { + +void OnBufferCreatedOnDrmThread( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + DrmThreadProxy::CreateBufferAsyncCallback callback, + std::unique_ptr<GbmBuffer> buffer, + scoped_refptr<DrmFramebuffer> framebuffer) { + task_runner->PostTask(FROM_HERE, + base::BindOnce(std::move(callback), std::move(buffer), + std::move(framebuffer))); +} + +} // namespace + DrmThreadProxy::DrmThreadProxy() = default; DrmThreadProxy::~DrmThreadProxy() = default; @@ -49,6 +63,24 @@ widget, size, format, usage, flags, buffer, framebuffer)); } +void DrmThreadProxy::CreateBufferAsync(gfx::AcceleratedWidget widget, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + uint32_t flags, + CreateBufferAsyncCallback callback) { + DCHECK(drm_thread_.task_runner()) + << "no task runner! in DrmThreadProxy::CreateBufferAsync"; + drm_thread_.task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&DrmThread::CreateBufferAsync, + base::Unretained(&drm_thread_), widget, size, format, + usage, flags, + base::BindOnce(OnBufferCreatedOnDrmThread, + base::ThreadTaskRunnerHandle::Get(), + std::move(callback)))); +} + void DrmThreadProxy::CreateBufferFromHandle( gfx::AcceleratedWidget widget, const gfx::Size& size,
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_proxy.h b/ui/ozone/platform/drm/gpu/drm_thread_proxy.h index f3c54595..6c6f064 100644 --- a/ui/ozone/platform/drm/gpu/drm_thread_proxy.h +++ b/ui/ozone/platform/drm/gpu/drm_thread_proxy.h
@@ -48,6 +48,16 @@ std::unique_ptr<GbmBuffer>* buffer, scoped_refptr<DrmFramebuffer>* framebuffer); + using CreateBufferAsyncCallback = + base::OnceCallback<void(std::unique_ptr<GbmBuffer>, + scoped_refptr<DrmFramebuffer>)>; + void CreateBufferAsync(gfx::AcceleratedWidget widget, + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + uint32_t flags, + CreateBufferAsyncCallback callback); + void CreateBufferFromHandle(gfx::AcceleratedWidget widget, const gfx::Size& size, gfx::BufferFormat format,
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc index b40c911..04c6d02a5 100644 --- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc +++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -135,6 +135,18 @@ return supported_buffer_formats; } +void OnNativePixmapCreated(GbmSurfaceFactory::NativePixmapCallback callback, + base::WeakPtr<GbmSurfaceFactory> weak_ptr, + std::unique_ptr<GbmBuffer> buffer, + scoped_refptr<DrmFramebuffer> framebuffer) { + if (!weak_ptr || !buffer) { + std::move(callback).Run(nullptr); + } else { + std::move(callback).Run(base::MakeRefCounted<GbmPixmap>( + weak_ptr.get(), std::move(buffer), std::move(framebuffer))); + } +} + } // namespace GbmSurfaceFactory::GbmSurfaceFactory(DrmThreadProxy* drm_thread_proxy) @@ -281,6 +293,18 @@ std::move(framebuffer)); } +void GbmSurfaceFactory::CreateNativePixmapAsync(gfx::AcceleratedWidget widget, + VkDevice vk_device, + gfx::Size size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + NativePixmapCallback callback) { + drm_thread_proxy_->CreateBufferAsync( + widget, size, format, usage, 0 /* flags */, + base::BindOnce(OnNativePixmapCreated, std::move(callback), + weak_factory_.GetWeakPtr())); +} + scoped_refptr<gfx::NativePixmap> GbmSurfaceFactory::CreateNativePixmapFromHandleInternal( gfx::AcceleratedWidget widget,
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h index b2bbb8e4..0329952f 100644 --- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h +++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
@@ -60,6 +60,12 @@ gfx::Size size, gfx::BufferFormat format, gfx::BufferUsage usage) override; + void CreateNativePixmapAsync(gfx::AcceleratedWidget widget, + VkDevice vk_device, + gfx::Size size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + NativePixmapCallback callback) override; scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandle( gfx::AcceleratedWidget widget, gfx::Size size, @@ -94,6 +100,8 @@ GetProtectedNativePixmapCallback get_protected_native_pixmap_callback_; + base::WeakPtrFactory<GbmSurfaceFactory> weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(GbmSurfaceFactory); };
diff --git a/ui/ozone/public/surface_factory_ozone.cc b/ui/ozone/public/surface_factory_ozone.cc index 24809d9..2d5a0fd3 100644 --- a/ui/ozone/public/surface_factory_ozone.cc +++ b/ui/ozone/public/surface_factory_ozone.cc
@@ -78,6 +78,16 @@ return nullptr; } +void SurfaceFactoryOzone::CreateNativePixmapAsync( + gfx::AcceleratedWidget widget, + VkDevice vk_device, + gfx::Size size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + NativePixmapCallback callback) { + std::move(callback).Run(nullptr); +} + scoped_refptr<gfx::NativePixmap> SurfaceFactoryOzone::CreateNativePixmapFromHandle( gfx::AcceleratedWidget widget,
diff --git a/ui/ozone/public/surface_factory_ozone.h b/ui/ozone/public/surface_factory_ozone.h index 229ff0f4..4ef2487 100644 --- a/ui/ozone/public/surface_factory_ozone.h +++ b/ui/ozone/public/surface_factory_ozone.h
@@ -121,6 +121,16 @@ gfx::BufferFormat format, gfx::BufferUsage usage); + // Similar to CreateNativePixmap, but returns the result asynchronously. + using NativePixmapCallback = + base::OnceCallback<void(scoped_refptr<gfx::NativePixmap>)>; + virtual void CreateNativePixmapAsync(gfx::AcceleratedWidget widget, + VkDevice vk_device, + gfx::Size size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + NativePixmapCallback callback); + // Create a single native buffer from an existing handle. Takes ownership of // |handle| and can be called on any thread. virtual scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandle(
diff --git a/ui/views/animation/installable_ink_drop.cc b/ui/views/animation/installable_ink_drop.cc index d7d0caa..89ecb2f 100644 --- a/ui/views/animation/installable_ink_drop.cc +++ b/ui/views/animation/installable_ink_drop.cc
@@ -14,13 +14,16 @@ #include "ui/compositor/layer.h" #include "ui/compositor/paint_context.h" #include "ui/compositor/paint_recorder.h" +#include "ui/gfx/animation/animation_container.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/skia_util.h" +#include "ui/views/animation/compositor_animation_runner.h" #include "ui/views/view.h" #include "ui/views/view_class_properties.h" +#include "ui/views/widget/widget.h" namespace views { @@ -31,7 +34,9 @@ : view_(view), layer_(std::make_unique<ui::Layer>()), event_handler_(view_, this), + animation_container_(base::MakeRefCounted<gfx::AnimationContainer>()), animator_(&painter_, + animation_container_.get(), base::Bind(&InstallableInkDrop::SchedulePaint, base::Unretained(this))) { // Catch if |view_| is destroyed out from under us. @@ -48,6 +53,14 @@ layer_->SetBounds(gfx::Rect(view_->size()) + layer_->bounds().OffsetFromOrigin()); layer_->SchedulePaint(gfx::Rect(layer_->size())); + + if (view_->GetWidget()) { + // Using CompositorAnimationRunner keeps our animation updates in sync with + // compositor frames and avoids jank. + animation_container_->SetAnimationRunner( + std::make_unique<CompositorAnimationRunner>( + view_->GetWidget()->GetCompositor())); + } } InstallableInkDrop::~InstallableInkDrop() { @@ -89,12 +102,12 @@ void InstallableInkDrop::SetHovered(bool is_hovered) { is_hovered_ = is_hovered; - UpdatePainterForCurrentState(); + UpdateAnimatorHighlight(); } void InstallableInkDrop::SetFocused(bool is_focused) { is_focused_ = is_focused; - UpdatePainterForCurrentState(); + UpdateAnimatorHighlight(); } bool InstallableInkDrop::IsHighlightFadingInOrVisible() const { @@ -162,9 +175,8 @@ layer_->SchedulePaint(gfx::Rect(layer_->size())); } -void InstallableInkDrop::UpdatePainterForCurrentState() { - painter_.SetHighlighted(IsHighlightFadingInOrVisible()); - SchedulePaint(); +void InstallableInkDrop::UpdateAnimatorHighlight() { + animator_.AnimateHighlight(is_hovered_ || is_focused_); } } // namespace views
diff --git a/ui/views/animation/installable_ink_drop.h b/ui/views/animation/installable_ink_drop.h index 5fea597f..13d3e5f2 100644 --- a/ui/views/animation/installable_ink_drop.h +++ b/ui/views/animation/installable_ink_drop.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/feature_list.h" +#include "base/memory/scoped_refptr.h" #include "ui/compositor/layer_delegate.h" #include "ui/views/animation/ink_drop.h" #include "ui/views/animation/ink_drop_event_handler.h" @@ -20,6 +21,7 @@ class SkPath; namespace gfx { +class AnimationContainer; class Size; } // namespace gfx @@ -87,7 +89,7 @@ private: void SchedulePaint(); - void UpdatePainterForCurrentState(); + void UpdateAnimatorHighlight(); // The view this ink drop is showing for. |layer_| is added to the layer // hierarchy that |view_| belongs to. We track events on |view_| to update our @@ -100,6 +102,11 @@ // Observes |view_| and updates our visual state accordingly. InkDropEventHandler event_handler_; + // Used to synchronize the hover and activation animations within this ink + // drop. Since we use |views::CompositorAnimationRunner|, this also + // synchronizes them with compositor frames. + scoped_refptr<gfx::AnimationContainer> animation_container_; + InstallableInkDropPainter painter_; InstallableInkDropAnimator animator_;
diff --git a/ui/views/animation/installable_ink_drop_animator.cc b/ui/views/animation/installable_ink_drop_animator.cc index b205c5b..33810c0 100644 --- a/ui/views/animation/installable_ink_drop_animator.cc +++ b/ui/views/animation/installable_ink_drop_animator.cc
@@ -14,8 +14,14 @@ InstallableInkDropAnimator::InstallableInkDropAnimator( InstallableInkDropPainter* painter, + gfx::AnimationContainer* animation_container, base::RepeatingClosure repaint_callback) - : painter_(painter), repaint_callback_(repaint_callback) {} + : painter_(painter), + repaint_callback_(repaint_callback), + highlight_animation_(this) { + highlight_animation_.SetContainer(animation_container); + highlight_animation_.SetSlideDuration(kAnimationDuration.InMilliseconds()); +} InstallableInkDropAnimator::~InstallableInkDropAnimator() { transition_delay_timer_.Stop(); @@ -29,23 +35,23 @@ case InkDropState::HIDDEN: case InkDropState::DEACTIVATED: target_state_ = InkDropState::HIDDEN; - painter_->SetActivated(false); + painter_->set_activated(false); break; case InkDropState::ACTION_PENDING: case InkDropState::ALTERNATE_ACTION_PENDING: case InkDropState::ACTIVATED: target_state_ = target_state; - painter_->SetActivated(true); + painter_->set_activated(true); break; case InkDropState::ACTION_TRIGGERED: case InkDropState::ALTERNATE_ACTION_TRIGGERED: if (last_state == InkDropState::ACTION_PENDING || last_state == InkDropState::ALTERNATE_ACTION_PENDING) { target_state_ = InkDropState::HIDDEN; - painter_->SetActivated(false); + painter_->set_activated(false); } else { target_state_ = target_state; - painter_->SetActivated(true); + painter_->set_activated(true); transition_delay_timer_.Start( FROM_HERE, kAnimationDuration, base::Bind(&InstallableInkDropAnimator::AnimateToState, @@ -57,4 +63,18 @@ repaint_callback_.Run(); } +void InstallableInkDropAnimator::AnimateHighlight(bool fade_in) { + if (fade_in) { + highlight_animation_.Show(); + } else { + highlight_animation_.Hide(); + } +} + +void InstallableInkDropAnimator::AnimationProgressed( + const gfx::Animation* animation) { + painter_->set_highlighted_ratio(highlight_animation_.GetCurrentValue()); + repaint_callback_.Run(); +} + } // namespace views
diff --git a/ui/views/animation/installable_ink_drop_animator.h b/ui/views/animation/installable_ink_drop_animator.h index 2e3f0c2..bcb8ba8f 100644 --- a/ui/views/animation/installable_ink_drop_animator.h +++ b/ui/views/animation/installable_ink_drop_animator.h
@@ -8,8 +8,14 @@ #include "base/callback.h" #include "base/time/time.h" #include "base/timer/timer.h" +#include "ui/gfx/animation/animation_delegate.h" +#include "ui/gfx/animation/slide_animation.h" #include "ui/views/animation/ink_drop_state.h" +namespace gfx { +class AnimationContainer; +} + namespace views { class InstallableInkDropPainter; @@ -17,21 +23,34 @@ // Manages animating the ink drop's visual state. This class is essentially a // state machine, using the current and target InkDropStates to affect the // InstallableInkDropPainter passed in. The animations are currently minimal. -class VIEWS_EXPORT InstallableInkDropAnimator { +class VIEWS_EXPORT InstallableInkDropAnimator : public gfx::AnimationDelegate { public: static constexpr base::TimeDelta kAnimationDuration = base::TimeDelta::FromMilliseconds(500); - explicit InstallableInkDropAnimator(InstallableInkDropPainter* painter, - base::RepeatingClosure repaint_callback); - ~InstallableInkDropAnimator(); + // We use a shared gfx::AnimationContainer for our animations to allow them to + // update in sync. It is passed in at construction for two reasons: it allows + // |views::CompositorAnimationRunner| to be used for more efficient and less + // janky animations, and it enables easier unit testing. + explicit InstallableInkDropAnimator( + InstallableInkDropPainter* painter, + gfx::AnimationContainer* animation_container, + base::RepeatingClosure repaint_callback); + ~InstallableInkDropAnimator() override; // Set the target state and animate to it. void AnimateToState(InkDropState target_state); + // Animates the hover highlight in or out. Animates in if |fade_in| is true, + // and out otherwise. + void AnimateHighlight(bool fade_in); + InkDropState target_state() const { return target_state_; } private: + // gfx::AnimationDelegate: + void AnimationProgressed(const gfx::Animation* animation) override; + // The painter whose state we are controlling. InstallableInkDropPainter* const painter_; @@ -40,6 +59,9 @@ InkDropState target_state_ = InkDropState::HIDDEN; + // Used to animate the painter's highlight value in and out. + gfx::SlideAnimation highlight_animation_; + base::OneShotTimer transition_delay_timer_; };
diff --git a/ui/views/animation/installable_ink_drop_animator_unittest.cc b/ui/views/animation/installable_ink_drop_animator_unittest.cc index 71280cab..19a81b1 100644 --- a/ui/views/animation/installable_ink_drop_animator_unittest.cc +++ b/ui/views/animation/installable_ink_drop_animator_unittest.cc
@@ -5,9 +5,11 @@ #include "ui/views/animation/installable_ink_drop_animator.h" #include "base/bind_helpers.h" +#include "base/memory/scoped_refptr.h" #include "base/run_loop.h" #include "base/test/scoped_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/animation/animation_test_api.h" #include "ui/views/animation/ink_drop_state.h" #include "ui/views/animation/installable_ink_drop_painter.h" @@ -29,7 +31,7 @@ TEST_F(InstallableInkDropAnimatorTest, UpdatesTargetState) { InstallableInkDropPainter painter; - InstallableInkDropAnimator animator(&painter, base::DoNothing()); + InstallableInkDropAnimator animator(&painter, nullptr, base::DoNothing()); EXPECT_EQ(InkDropState::HIDDEN, animator.target_state()); animator.AnimateToState(InkDropState::ACTIVATED); @@ -42,7 +44,7 @@ bool callback_called = false; base::RepeatingClosure callback = base::Bind( [](bool* callback_called) { *callback_called = true; }, &callback_called); - InstallableInkDropAnimator animator(&painter, callback); + InstallableInkDropAnimator animator(&painter, nullptr, callback); EXPECT_EQ(InkDropState::HIDDEN, animator.target_state()); EXPECT_FALSE(painter.activated()); EXPECT_FALSE(callback_called); @@ -78,7 +80,7 @@ bool callback_called = false; base::RepeatingClosure callback = base::Bind( [](bool* callback_called) { *callback_called = true; }, &callback_called); - InstallableInkDropAnimator animator(&painter, callback); + InstallableInkDropAnimator animator(&painter, nullptr, callback); EXPECT_EQ(InkDropState::HIDDEN, animator.target_state()); EXPECT_FALSE(painter.activated()); EXPECT_FALSE(callback_called); @@ -97,4 +99,39 @@ EXPECT_TRUE(callback_called); } +TEST_F(InstallableInkDropAnimatorTest, HighlightAnimationFadesInAndOut) { + InstallableInkDropPainter painter; + + auto animation_container = base::MakeRefCounted<gfx::AnimationContainer>(); + gfx::AnimationContainerTestApi animation_test_api(animation_container.get()); + + bool callback_called = false; + base::RepeatingClosure callback = base::Bind( + [](bool* callback_called) { *callback_called = true; }, &callback_called); + InstallableInkDropAnimator animator(&painter, animation_container.get(), + callback); + EXPECT_EQ(0.0f, painter.highlighted_ratio()); + EXPECT_FALSE(callback_called); + + animator.AnimateHighlight(true); + EXPECT_EQ(0.0f, painter.highlighted_ratio()); + + callback_called = false; + animation_test_api.IncrementTime( + InstallableInkDropAnimator::kAnimationDuration); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1.0f, painter.highlighted_ratio()); + EXPECT_TRUE(callback_called); + + animator.AnimateHighlight(false); + EXPECT_EQ(1.0f, painter.highlighted_ratio()); + + callback_called = false; + animation_test_api.IncrementTime( + InstallableInkDropAnimator::kAnimationDuration); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(0.0f, painter.highlighted_ratio()); + EXPECT_TRUE(callback_called); +} + } // namespace views
diff --git a/ui/views/animation/installable_ink_drop_painter.cc b/ui/views/animation/installable_ink_drop_painter.cc index 421f5318..a4b15fc 100644 --- a/ui/views/animation/installable_ink_drop_painter.cc +++ b/ui/views/animation/installable_ink_drop_painter.cc
@@ -13,8 +13,8 @@ // these and make colors configurable, with same defaults as existing // ink drops. constexpr SkColor kInstallableInkDropBaseColor = SK_ColorBLACK; -constexpr SkAlpha kInstallableInkDropHighlightedOpacity = 0.08 * SK_AlphaOPAQUE; -constexpr SkAlpha kInstallableInkDropActivatedOpacity = 0.16 * SK_AlphaOPAQUE; +constexpr float kInstallableInkDropHighlightedOpacity = 0.08; +constexpr float kInstallableInkDropActivatedOpacity = 0.16; } // namespace namespace views { @@ -26,13 +26,15 @@ void InstallableInkDropPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) { if (activated_) { + canvas->FillRect( + gfx::Rect(size), + SkColorSetA(kInstallableInkDropBaseColor, + kInstallableInkDropActivatedOpacity * SK_AlphaOPAQUE)); + } else if (highlighted_ratio_ > 0.0f) { canvas->FillRect(gfx::Rect(size), SkColorSetA(kInstallableInkDropBaseColor, - kInstallableInkDropActivatedOpacity)); - } else if (highlighted_) { - canvas->FillRect(gfx::Rect(size), - SkColorSetA(kInstallableInkDropBaseColor, - kInstallableInkDropHighlightedOpacity)); + kInstallableInkDropHighlightedOpacity * + highlighted_ratio_ * SK_AlphaOPAQUE)); } }
diff --git a/ui/views/animation/installable_ink_drop_painter.h b/ui/views/animation/installable_ink_drop_painter.h index e5c3d76..9b5bb37 100644 --- a/ui/views/animation/installable_ink_drop_painter.h +++ b/ui/views/animation/installable_ink_drop_painter.h
@@ -18,19 +18,21 @@ InstallableInkDropPainter() = default; ~InstallableInkDropPainter() override = default; - void SetActivated(bool activated) { activated_ = activated; } + void set_activated(bool activated) { activated_ = activated; } bool activated() const { return activated_; } - void SetHighlighted(bool highlighted) { highlighted_ = highlighted; } - bool highlighted() const { return highlighted_; } + void set_highlighted_ratio(float highlighted_ratio) { + highlighted_ratio_ = highlighted_ratio; + } + bool highlighted_ratio() const { return highlighted_ratio_; } // Painter: gfx::Size GetMinimumSize() const override; void Paint(gfx::Canvas* canvas, const gfx::Size& size) override; private: + float highlighted_ratio_ = 0.0f; bool activated_ = false; - bool highlighted_ = false; }; } // namespace views
diff --git a/ui/views/metadata/metadata_types.cc b/ui/views/metadata/metadata_types.cc index 8550cc9..34cbd93 100644 --- a/ui/views/metadata/metadata_types.cc +++ b/ui/views/metadata/metadata_types.cc
@@ -77,6 +77,15 @@ return tmp; } +bool ClassMetaData::ClassMemberIterator::IsLastMember() const { + return current_vector_index_ == current_collection_->members().size() - 1; +} + +std::string ClassMetaData::ClassMemberIterator::GetCurrentCollectionName() + const { + return current_collection_->type_name(); +} + void ClassMetaData::ClassMemberIterator::IncrementHelper() { DCHECK_LT(current_vector_index_, SIZE_MAX); ++current_vector_index_;
diff --git a/ui/views/metadata/metadata_types.h b/ui/views/metadata/metadata_types.h index bdf4fa0..90cf132 100644 --- a/ui/views/metadata/metadata_types.h +++ b/ui/views/metadata/metadata_types.h
@@ -90,6 +90,12 @@ return current_collection_->members()[current_vector_index_]; } + // Returns true if iterator currently on last member for that current + // collection. + bool IsLastMember() const; + + std::string GetCurrentCollectionName() const; + private: friend class ClassMetaData; explicit ClassMemberIterator(ClassMetaData* starting_container);
diff --git a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js index 877b67e..e6b6502 100644 --- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js +++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
@@ -186,17 +186,6 @@ return this.$.dialog; }, - /** - * @return {!Array<!Element>} - * @private - */ - getOptions_: function() { - return Array - .from(this.querySelectorAll( - '.dropdown-item:not([hidden]):not([disabled])')) - .map(cr.ui.FocusRow.getFocusableElement); - }, - /** @private */ removeListeners_: function() { window.removeEventListener('resize', this.boundClose_); @@ -248,19 +237,29 @@ */ onKeyDown_: function(e) { e.stopPropagation(); - if (e.key == 'Tab' || e.key == 'Escape') { this.close(); e.preventDefault(); return; } - let selectNext = e.key == 'ArrowDown'; + if (e.key != 'Enter' && e.key != 'ArrowUp' && e.key != 'ArrowDown') { + return; + } + + const query = '.dropdown-item:not([disabled]):not([hidden])'; + const options = Array.from(this.querySelectorAll(query)); + if (options.length == 0) { + return; + } + + const focused = getDeepActiveElement(); + const index = options.findIndex( + option => cr.ui.FocusRow.getFocusableElement(option) == focused); + if (e.key == 'Enter') { // If a menu item has focus, don't change focus or close menu on 'Enter'. - const focusedIndex = - this.getOptions_().indexOf(assert(getDeepActiveElement())); - if (focusedIndex != -1) { + if (index != -1) { return; } @@ -269,26 +268,18 @@ e.preventDefault(); return; } - selectNext = true; - } - - if (e.key !== 'ArrowUp' && !selectNext) { - return; - } - - const nextOption = this.getNextOption_(selectNext ? 1 : -1); - if (nextOption) { - if (!this.hasMousemoveListener_) { - this.hasMousemoveListener_ = true; - listenOnce(this, 'mousemove', e => { - this.onMouseover_(e); - this.hasMousemoveListener_ = false; - }); - } - nextOption.focus(); } e.preventDefault(); + this.updateFocus_(options, index, e.key != 'ArrowUp'); + + if (!this.hasMousemoveListener_) { + this.hasMousemoveListener_ = true; + this.addEventListener('mousemove', e => { + this.onMouseover_(e); + this.hasMousemoveListener_ = false; + }, {once: true}); + } }, /** @@ -296,49 +287,28 @@ * @private */ onMouseover_: function(e) { - let i = 0; - let target; - do { - target = e.path[i++]; - if (target.classList && target.classList.contains('dropdown-item') && - !target.disabled) { - target.focus(); - return; - } - } while (this != target); - - // The user moved the mouse off the options. Reset focus to the dialog. - this.$.dialog.focus(); + const query = '.dropdown-item:not([disabled])'; + const item = e.composedPath().find(el => el.matches && el.matches(query)); + (item || this.$.dialog).focus(); }, /** - * @param {number} step -1 for getting previous option (up), 1 for getting - * next option (down). - * @return {?Element} The next focusable option, taking into account - * disabled/hidden attributes, or null if no focusable option exists. + * @param {!Array<!HTMLElement>} options + * @param {number} focusedIndex + * @param {boolean} next * @private */ - getNextOption_: function(step) { - // Using a counter to ensure no infinite loop occurs if all elements are - // hidden/disabled. - let counter = 0; - let nextOption = null; - const options = this.getOptions_(); + updateFocus_: function(options, focusedIndex, next) { const numOptions = options.length; - let focusedIndex = options.indexOf(assert(getDeepActiveElement())); - - // Handle case where nothing is focused and up is pressed. - if (focusedIndex === -1 && step === -1) { - focusedIndex = 0; + assert(numOptions > 0); + let index; + if (focusedIndex == -1) { + index = next ? 0 : numOptions - 1; + } else { + const delta = next ? 1 : -1; + index = (numOptions + focusedIndex + delta) % numOptions; } - - do { - focusedIndex = (numOptions + focusedIndex + step) % numOptions; - nextOption = options[focusedIndex]; - counter++; - } while (!nextOption && counter < numOptions); - - return nextOption; + options[index].focus(); }, close: function() {
diff --git a/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js b/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js index e40548a..bfff87451 100644 --- a/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js +++ b/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js
@@ -64,7 +64,9 @@ /** @private */ hideRipple_: function() { - this.getRipple().clear(); + if (this.hasRipple()) { + this.getRipple().clear(); + } }, /** @private */ @@ -112,6 +114,9 @@ element.icon = icon; this.$.icon.appendChild(element); }); + if (!this.hasRipple()) { + return; + } if (icons.length > 1) { this.getRipple().classList.remove('circle'); } else {
diff --git a/ui/webui/resources/js/list_property_update_behavior.js b/ui/webui/resources/js/list_property_update_behavior.js index 653c3cec..0986cbd 100644 --- a/ui/webui/resources/js/list_property_update_behavior.js +++ b/ui/webui/resources/js/list_property_update_behavior.js
@@ -21,17 +21,15 @@ * @param {string} propertyPath * @param {function(!Object): string} itemUidGetter * @param {!Array<!Object>} updatedList + * @param {boolean} uidBasedUpdate * @returns {boolean} True if notifySplices was called. */ - updateList: function(propertyPath, itemUidGetter, updatedList) { + updateList: function( + propertyPath, itemUidGetter, updatedList, uidBasedUpdate = false) { const list = this.get(propertyPath); const splices = Polymer.ArraySplice.calculateSplices( updatedList.map(itemUidGetter), list.map(itemUidGetter)); - if (splices.length == 0) { - return false; - } - splices.forEach(splice => { const index = splice.index; const deleteCount = splice.removed.length; @@ -45,7 +43,21 @@ const spliceParams = [index, deleteCount].concat(added); list.splice.apply(list, spliceParams); }); - this.notifySplices(propertyPath, splices); - return true; + + let updated = splices.length > 0; + if (!uidBasedUpdate) { + list.forEach((item, index) => { + const updatedItem = updatedList[index]; + if (JSON.stringify(item) != JSON.stringify(updatedItem)) { + this.set([propertyPath, index], updatedItem); + updated = true; + } + }); + } + + if (splices.length > 0) { + this.notifySplices(propertyPath, splices); + } + return updated; }, };