diff --git a/BUILD.gn b/BUILD.gn index 6943ee4..39aace08 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -546,7 +546,6 @@ deps += [ "//third_party/breakpad:crash_inspector", "//third_party/breakpad:dump_syms", - "//third_party/molokocacao", ] deps -= [ # Mojo in GN contains some things which are never compiled in GYP on Mac,
diff --git a/DEPS b/DEPS index 211d474f..8795c742 100644 --- a/DEPS +++ b/DEPS
@@ -105,7 +105,7 @@ # 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': 'd37570b325e2a8c78aa232d13e502c8d24de7d46', + 'skia_revision': 'f18c297cfb74a48b748bc7909991f98dabb8d460', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -117,7 +117,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'b36a4816a5460120249e89258af3c5741301de40', + 'angle_revision': '299bdfe75173549470981d70e88dd55c02123abb', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -129,7 +129,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'fed6e124109f089a38e24e37b104d983231bee78', + 'pdfium_revision': '072d829e2cd1586645022498a01a61db83a2db4d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -620,7 +620,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8e64369342f22b0541d438bac748c93fe4b8d14e', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c4a7356a469b3b6267965d7bcc318cf35cdd3b62', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -1137,7 +1137,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@be0a57bc9068ed15b2c91555ab9c5622baf18a36', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d57b80dd25bd5e5766a2efa2f7b602c7588de818', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index 7b89949b..48b0bc0 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -1082,12 +1082,7 @@ version_name = chrome_version_name android_manifest = system_webview_android_manifest android_manifest_dep = ":system_webview_manifest" - deps = [ - ":platform_service_bridge_upstream_implementation_java", - ":system_webview_resources", - "//android_webview/glue", - "//android_webview/support_library:support_lib_glue_java", - ] + deps = upstream_only_webview_deps apk_name = "SystemWebView" } }
diff --git a/android_webview/browser/aw_autofill_client.cc b/android_webview/browser/aw_autofill_client.cc index e60f6db8..4c9dbc2 100644 --- a/android_webview/browser/aw_autofill_client.cc +++ b/android_webview/browser/aw_autofill_client.cc
@@ -290,7 +290,7 @@ void AwAutofillClient::ConfirmSaveCreditCardLocally( const autofill::CreditCard& card, - const base::Closure& callback) { + base::OnceClosure callback) { NOTIMPLEMENTED(); } @@ -309,7 +309,7 @@ } void AwAutofillClient::LoadRiskData( - const base::Callback<void(const std::string&)>& callback) { + base::OnceCallback<void(const std::string&)> callback) { NOTIMPLEMENTED(); }
diff --git a/android_webview/browser/aw_autofill_client.h b/android_webview/browser/aw_autofill_client.h index 610de1e5..311542f 100644 --- a/android_webview/browser/aw_autofill_client.h +++ b/android_webview/browser/aw_autofill_client.h
@@ -83,7 +83,7 @@ void ConfirmSaveAutofillProfile(const autofill::AutofillProfile& profile, base::OnceClosure callback) override; void ConfirmSaveCreditCardLocally(const autofill::CreditCard& card, - const base::Closure& callback) override; + base::OnceClosure callback) override; void ConfirmSaveCreditCardToCloud( const autofill::CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, @@ -92,7 +92,7 @@ void ConfirmCreditCardFillAssist(const autofill::CreditCard& card, const base::Closure& callback) override; void LoadRiskData( - const base::Callback<void(const std::string&)>& callback) override; + base::OnceCallback<void(const std::string&)> callback) override; bool HasCreditCardScanFeature() override; void ScanCreditCard(const CreditCardScanCallback& callback) override; void ShowAutofillPopup(
diff --git a/android_webview/support_library/java/src/org/chromium/support_lib_glue/IsomorphicAdapter.java b/android_webview/support_library/java/src/org/chromium/support_lib_glue/IsomorphicAdapter.java index a2ac025..0fc210f0 100644 --- a/android_webview/support_library/java/src/org/chromium/support_lib_glue/IsomorphicAdapter.java +++ b/android_webview/support_library/java/src/org/chromium/support_lib_glue/IsomorphicAdapter.java
@@ -18,6 +18,9 @@ @Override public Object getOrCreatePeer(Callable<Object> creationCallable) throws Exception { AwSupportLibIsomorphic peeredObject = getPeeredObject(); + if (peeredObject == null) { + return null; + } Object peer = peeredObject.getSupportLibObject(); if (peer == null) { peeredObject.setSupportLibObject(peer = creationCallable.call());
diff --git a/android_webview/system_webview_apk_tmpl.gni b/android_webview/system_webview_apk_tmpl.gni index 37ca66e..759173f 100644 --- a/android_webview/system_webview_apk_tmpl.gni +++ b/android_webview/system_webview_apk_tmpl.gni
@@ -15,6 +15,8 @@ "//android_webview:assets", "//android_webview/apk:webview_license_activity_java", "//android_webview/apk:webview_license_provider_java", + "//android_webview/glue", + "//android_webview/support_library:support_lib_glue_java", "//base:base_java", ]
diff --git a/android_webview/variables.gni b/android_webview/variables.gni index 656c14fb..94b8559 100644 --- a/android_webview/variables.gni +++ b/android_webview/variables.gni
@@ -4,3 +4,8 @@ system_webview_android_manifest = "$root_gen_dir/android_webview/system_webview_apk/AndroidManifest.xml" + +upstream_only_webview_deps = [ + "//android_webview:platform_service_bridge_upstream_implementation_java", + "//android_webview:system_webview_resources", +]
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 3269965..243a270 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -239,6 +239,8 @@ "assistant/util/views_util.h", "autoclick/autoclick_controller.cc", "autoclick/autoclick_controller.h", + "bluetooth_devices_observer.cc", + "bluetooth_devices_observer.h", "cancel_mode.cc", "cancel_mode.h", "cast_config_controller.cc", @@ -1775,6 +1777,7 @@ "login/ui/login_keyboard_test_base.h", "login/ui/login_password_view_test.cc", "login/ui/login_pin_view_unittest.cc", + "login/ui/login_public_account_user_view_unittest.cc", "login/ui/login_test_base.cc", "login/ui/login_test_base.h", "login/ui/login_test_utils.cc",
diff --git a/ash/bluetooth_devices_observer.cc b/ash/bluetooth_devices_observer.cc new file mode 100644 index 0000000..e301b12a --- /dev/null +++ b/ash/bluetooth_devices_observer.cc
@@ -0,0 +1,56 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/bluetooth_devices_observer.h" + +#include "base/bind.h" +#include "device/bluetooth/bluetooth_adapter_factory.h" + +namespace ash { + +BluetoothDevicesObserver::BluetoothDevicesObserver( + const DeviceChangedCallback& device_changed_callback) + : device_changed_callback_(device_changed_callback), weak_factory_(this) { + device::BluetoothAdapterFactory::GetAdapter( + base::Bind(&BluetoothDevicesObserver::InitializeOnAdapterReady, + weak_factory_.GetWeakPtr())); +} + +BluetoothDevicesObserver::~BluetoothDevicesObserver() { + if (bluetooth_adapter_) + bluetooth_adapter_->RemoveObserver(this); +} + +void BluetoothDevicesObserver::DeviceChanged(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) { + device_changed_callback_.Run(device); +} + +void BluetoothDevicesObserver::InitializeOnAdapterReady( + scoped_refptr<device::BluetoothAdapter> adapter) { + bluetooth_adapter_ = std::move(adapter); + bluetooth_adapter_->AddObserver(this); +} + +bool BluetoothDevicesObserver::IsConnectedBluetoothDevice( + const ui::InputDevice& input_device) const { + if (!bluetooth_adapter_ || !bluetooth_adapter_->IsPowered()) + return false; + + // Since there is no map from an InputDevice to a BluetoothDevice. We just + // comparing their vendor id and product id to guess a match. + for (auto* device : bluetooth_adapter_->GetDevices()) { + if (!device->IsConnected()) + continue; + + if (device->GetVendorID() == input_device.vendor_id && + device->GetProductID() == input_device.product_id) { + return true; + } + } + + return false; +} + +} // namespace ash
diff --git a/ash/bluetooth_devices_observer.h b/ash/bluetooth_devices_observer.h new file mode 100644 index 0000000..5612ec1c --- /dev/null +++ b/ash/bluetooth_devices_observer.h
@@ -0,0 +1,63 @@ +// 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 ASH_BLUETOOTH_DEVICES_OBSERVER_H_ +#define ASH_BLUETOOTH_DEVICES_OBSERVER_H_ + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "device/bluetooth/bluetooth_adapter.h" +#include "ui/events/devices/input_device.h" + +namespace ash { + +// This class observes the bluetooth devices and sends out notification when +// bluetooth device changes. It's used as a supplementary to the class +// ui::InputDeviceEventObserver as InputDeviceEventObserver does not have +// knowledge about bluetooth device status thus does not send notifications of +// bluetooth device changes. +class BluetoothDevicesObserver : public device::BluetoothAdapter::Observer { + public: + using DeviceChangedCallback = + base::RepeatingCallback<void(device::BluetoothDevice* device)>; + + explicit BluetoothDevicesObserver( + const DeviceChangedCallback& device_changed_callback); + ~BluetoothDevicesObserver() override; + + // device::BluetoothAdapter::Observer: + void DeviceChanged(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) override; + + // Returns true if |input_device| is a connected bluetooth device. Note this + // function may not work well if there are more than one identical Bluetooth + // devices: the function might return true even if it should return false. + // E.g., Connect two idential bluetooth devices (Input device A & input device + // B, thus the same vendor id and same product id) to Chrome OS, and then + // disconnect device A, calling IsConnectedBluetoothDevice(Input device A) + // still returns true although it should return false as Input device B is + // still connected. Unfortunately there is no good map from an InputDevice to + // a BluetoothDevice, thus we can only guess a match. + bool IsConnectedBluetoothDevice(const ui::InputDevice& input_device) const; + + private: + void InitializeOnAdapterReady( + scoped_refptr<device::BluetoothAdapter> adapter); + + // Reference to the underlying Bluetooth Adapter. Used to listen for bluetooth + // device change event. + scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_; + + // Callback function to be called when a bluetooth device status changes. + DeviceChangedCallback device_changed_callback_; + + base::WeakPtrFactory<BluetoothDevicesObserver> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothDevicesObserver); +}; + +} // namespace ash + +#endif // ASH_BLUETOOTH_DEVICES_OBSERVER_H_
diff --git a/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc b/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc index a9636cb..efad1e5 100644 --- a/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc +++ b/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc
@@ -137,9 +137,8 @@ // redundant child label text is not also spoken. GetViewAccessibility().OverrideRole(ax::mojom::Role::kListItem); GetViewAccessibility().OverrideIsLeaf(); - accessible_name_ = GetStringForCategory(category_) + - description_label_view_->text() + - shortcut_label_view_->text(); + accessible_name_ = description_label_view_->text() + + base::ASCIIToUTF16(", ") + shortcut_label_view_->text(); } void KeyboardShortcutItemView::GetAccessibleNodeData(
diff --git a/ash/display/cros_display_config_unittest.cc b/ash/display/cros_display_config_unittest.cc index 66a23a0..a2990d9c 100644 --- a/ash/display/cros_display_config_unittest.cc +++ b/ash/display/cros_display_config_unittest.cc
@@ -36,9 +36,9 @@ } void InitExternalTouchDevices(int64_t display_id) { - ui::TouchscreenDevice touchdevice( - 123, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, - std::string("test external touch device"), gfx::Size(1000, 1000), 1); + ui::TouchscreenDevice touchdevice(123, ui::InputDeviceType::INPUT_DEVICE_USB, + std::string("test external touch device"), + gfx::Size(1000, 1000), 1); ws::InputDeviceClientTestApi().SetTouchscreenDevices({touchdevice}); std::vector<ui::TouchDeviceTransform> transforms;
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc index c50fb0e..276afb4 100644 --- a/ash/display/display_manager_unittest.cc +++ b/ash/display/display_manager_unittest.cc
@@ -1190,7 +1190,7 @@ display::test::TouchDeviceManagerTestApi tdm_test_api(touch_device_manager); const ui::TouchscreenDevice touchdevice( - 11, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + 11, ui::InputDeviceType::INPUT_DEVICE_USB, std::string("test touch device"), gfx::Size(123, 456), 1); const display::TouchDeviceIdentifier touch_device_identifier_2 = display::TouchDeviceIdentifier::FromDevice(touchdevice); @@ -1265,7 +1265,7 @@ touchdevice, GetDisplayInfoAt(1).id())); const ui::TouchscreenDevice touchdevice_2( - 12, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + 12, ui::InputDeviceType::INPUT_DEVICE_USB, std::string("test touch device 2"), gfx::Size(234, 567), 1); display::TouchDeviceIdentifier touch_device_identifier_2_2 = display::TouchDeviceIdentifier::FromDevice(touchdevice_2);
diff --git a/ash/display/touch_calibrator_controller_unittest.cc b/ash/display/touch_calibrator_controller_unittest.cc index 7ed9452..f50c6d1 100644 --- a/ash/display/touch_calibrator_controller_unittest.cc +++ b/ash/display/touch_calibrator_controller_unittest.cc
@@ -38,7 +38,7 @@ ui::TouchscreenDevice GetExternalTouchDevice(int touch_device_id) { return ui::TouchscreenDevice( - touch_device_id, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + touch_device_id, ui::InputDeviceType::INPUT_DEVICE_USB, std::string("test external touch device"), gfx::Size(1000, 1000), 1); } @@ -338,7 +338,7 @@ display_manager()->GetDisplayInfo(touch_display.id()); ui::TouchscreenDevice random_touchdevice( - 15, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + 15, ui::InputDeviceType::INPUT_DEVICE_USB, std::string("random touch device"), gfx::Size(123, 456), 1); EXPECT_EQ(calibration_data, touch_device_manager()->GetCalibrationData( random_touchdevice, info.id())); @@ -400,7 +400,7 @@ kInternalTouchId, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, std::string("internal touch device"), gfx::Size(1000, 1000), 1); ui::TouchscreenDevice external_touchdevice( - kExternalTouchId, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + kExternalTouchId, ui::InputDeviceType::INPUT_DEVICE_USB, std::string("external touch device"), gfx::Size(1000, 1000), 1); ws::InputDeviceClientTestApi().SetTouchscreenDevices( @@ -492,7 +492,7 @@ kInternalTouchId, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, std::string("internal touch device"), gfx::Size(1000, 1000), 1); ui::TouchscreenDevice external_touchdevice( - kExternalTouchId, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + kExternalTouchId, ui::InputDeviceType::INPUT_DEVICE_USB, std::string("external touch device"), gfx::Size(1000, 1000), 1); ws::InputDeviceClientTestApi().SetTouchscreenDevices(
diff --git a/ash/keyboard/virtual_keyboard_controller.cc b/ash/keyboard/virtual_keyboard_controller.cc index aefff26..a57a0b7 100644 --- a/ash/keyboard/virtual_keyboard_controller.cc +++ b/ash/keyboard/virtual_keyboard_controller.cc
@@ -102,6 +102,10 @@ chromeos::input_method::mojom::ImeKeyset::kEmoji)); keyboard::KeyboardController::Get()->AddObserver(this); + + bluetooth_devices_observer_ = std::make_unique<BluetoothDevicesObserver>( + base::BindRepeating(&VirtualKeyboardController::UpdateBluetoothDevice, + base::Unretained(this))); } VirtualKeyboardController::~VirtualKeyboardController() { @@ -213,8 +217,11 @@ ui::InputDeviceType type = device.type; if (type == ui::InputDeviceType::INPUT_DEVICE_INTERNAL) has_internal_keyboard_ = true; - if (type == ui::InputDeviceType::INPUT_DEVICE_EXTERNAL) + if (type == ui::InputDeviceType::INPUT_DEVICE_USB || + (type == ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH && + bluetooth_devices_observer_->IsConnectedBluetoothDevice(device))) { has_external_keyboard_ = true; + } } // Update keyboard state. UpdateKeyboardEnabled(); @@ -293,4 +300,16 @@ Shell::Get()->EnableKeyboard(); } +void VirtualKeyboardController::UpdateBluetoothDevice( + device::BluetoothDevice* device) { + // We only care about keyboard type bluetooth device change. + if (device->GetDeviceType() != device::BluetoothDeviceType::KEYBOARD && + device->GetDeviceType() != + device::BluetoothDeviceType::KEYBOARD_MOUSE_COMBO) { + return; + } + + UpdateDevices(); +} + } // namespace ash
diff --git a/ash/keyboard/virtual_keyboard_controller.h b/ash/keyboard/virtual_keyboard_controller.h index 5ad4c51a..49bb8e5 100644 --- a/ash/keyboard/virtual_keyboard_controller.h +++ b/ash/keyboard/virtual_keyboard_controller.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include "ash/ash_export.h" +#include "ash/bluetooth_devices_observer.h" #include "ash/session/session_observer.h" #include "ash/wm/tablet_mode/tablet_mode_observer.h" #include "base/macros.h" @@ -56,7 +57,7 @@ void OnKeyboardDisabled() override; void OnKeyboardHidden(bool is_temporary_hide) override; - // SessionObserver + // SessionObserver: void OnActiveUserSessionChanged(const AccountId& account_id) override; private: @@ -72,6 +73,10 @@ // Force enable the keyboard and show it, even in laptop mode. void ForceShowKeyboard(); + // Callback function of |bluetooth_devices_observer_|. Called when |device| + // changes. + void UpdateBluetoothDevice(device::BluetoothDevice* device); + // True if an external keyboard is connected. bool has_external_keyboard_; // True if an internal keyboard is connected. @@ -81,6 +86,9 @@ // True if the presence of an external keyboard should be ignored. bool ignore_external_keyboard_; + // Observer to observe the bluetooth devices. + std::unique_ptr<BluetoothDevicesObserver> bluetooth_devices_observer_; + DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardController); };
diff --git a/ash/keyboard/virtual_keyboard_controller_unittest.cc b/ash/keyboard/virtual_keyboard_controller_unittest.cc index 9d6d4dc7..b2621b6 100644 --- a/ash/keyboard/virtual_keyboard_controller_unittest.cc +++ b/ash/keyboard/virtual_keyboard_controller_unittest.cc
@@ -285,7 +285,7 @@ std::vector<ui::TouchscreenDevice> devices; // Add a touchscreen. Keyboard should deploy. devices.push_back( - ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "Touchscreen", gfx::Size(800, 600), 0)); ws::InputDeviceClientTestApi().SetTouchscreenDevices(devices); EXPECT_TRUE(keyboard::IsKeyboardEnabled()); @@ -301,8 +301,8 @@ gfx::Size(1024, 768), 0, false /* has_stylus */)); ws::InputDeviceClientTestApi().SetTouchscreenDevices(screens); std::vector<ui::InputDevice> keyboard_devices; - keyboard_devices.push_back(ui::InputDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard")); + keyboard_devices.push_back( + ui::InputDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")); ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices); ASSERT_FALSE(keyboard::IsKeyboardEnabled()); ASSERT_TRUE(notified()); @@ -333,10 +333,10 @@ std::vector<ui::InputDevice> keyboards; keyboards.push_back(ui::InputDevice( 1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "keyboard")); - keyboards.push_back(ui::InputDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard")); - keyboards.push_back(ui::InputDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard")); + keyboards.push_back( + ui::InputDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")); + keyboards.push_back( + ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")); ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboards); ASSERT_FALSE(keyboard::IsKeyboardEnabled()); } @@ -371,8 +371,8 @@ std::vector<ui::InputDevice> keyboard_devices; keyboard_devices.push_back(ui::InputDevice( 1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, "Keyboard")); - keyboard_devices.push_back(ui::InputDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "Keyboard")); + keyboard_devices.push_back( + ui::InputDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "Keyboard")); ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices); // Toggle tablet mode on. TabletModeControllerTestApi().EnterTabletMode(); @@ -430,8 +430,8 @@ "Touchscreen", gfx::Size(1024, 768), 0)); ws::InputDeviceClientTestApi().SetTouchscreenDevices(screens); std::vector<ui::InputDevice> keyboard_devices; - keyboard_devices.push_back(ui::InputDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard")); + keyboard_devices.push_back( + ui::InputDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")); ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices); ASSERT_TRUE(keyboard::IsKeyboardEnabled()); }
diff --git a/ash/login/ui/login_expanded_public_account_view.cc b/ash/login/ui/login_expanded_public_account_view.cc index 73e23bb..3cba5a0 100644 --- a/ash/login/ui/login_expanded_public_account_view.cc +++ b/ash/login/ui/login_expanded_public_account_view.cc
@@ -12,7 +12,6 @@ #include "ash/login/ui/arrow_button_view.h" #include "ash/login/ui/login_bubble.h" #include "ash/login/ui/login_button.h" -#include "ash/login/ui/login_menu_view.h" #include "ash/login/ui/login_user_view.h" #include "ash/login/ui/public_account_warning_dialog.h" #include "ash/resources/vector_icons/vector_icons.h" @@ -560,6 +559,34 @@ return view_->right_pane_->learn_more_label_; } +views::View* +LoginExpandedPublicAccountView::TestApi::language_selection_button() { + return view_->right_pane_->language_selection_; +} + +views::View* +LoginExpandedPublicAccountView::TestApi::keyboard_selection_button() { + return view_->right_pane_->keyboard_selection_; +} + +LoginBubble* LoginExpandedPublicAccountView::TestApi::language_menu() { + return view_->right_pane_->language_menu_.get(); +} + +LoginBubble* LoginExpandedPublicAccountView::TestApi::keyboard_menu() { + return view_->right_pane_->keyboard_menu_.get(); +} + +LoginMenuView::Item +LoginExpandedPublicAccountView::TestApi::selected_language_item() { + return view_->right_pane_->selected_language_item_; +} + +LoginMenuView::Item +LoginExpandedPublicAccountView::TestApi::selected_keyboard_item() { + return view_->right_pane_->selected_keyboard_item_; +} + LoginExpandedPublicAccountView::LoginExpandedPublicAccountView( const OnPublicSessionViewDismissed& on_dismissed) : NonAccessibleView(kLoginExpandedPublicAccountViewClassName),
diff --git a/ash/login/ui/login_expanded_public_account_view.h b/ash/login/ui/login_expanded_public_account_view.h index 76884d8..e865ea2 100644 --- a/ash/login/ui/login_expanded_public_account_view.h +++ b/ash/login/ui/login_expanded_public_account_view.h
@@ -6,6 +6,7 @@ #define ASH_LOGIN_UI_LOGIN_EXPANDED_PUBLIC_ACCOUNT_VIEW_H_ #include "ash/ash_export.h" +#include "ash/login/ui/login_menu_view.h" #include "ash/login/ui/non_accessible_view.h" #include "ash/public/interfaces/login_user_info.mojom.h" #include "ui/events/event_handler.h" @@ -15,6 +16,7 @@ namespace ash { class ArrowButtonView; +class LoginBubble; class LoginUserView; class RightPaneView; class PublicAccountWarningDialog; @@ -34,6 +36,12 @@ views::View* advanced_view(); PublicAccountWarningDialog* warning_dialog(); views::StyledLabel* learn_more_label(); + views::View* language_selection_button(); + views::View* keyboard_selection_button(); + LoginBubble* language_menu(); + LoginBubble* keyboard_menu(); + LoginMenuView::Item selected_language_item(); + LoginMenuView::Item selected_keyboard_item(); private: LoginExpandedPublicAccountView* const view_;
diff --git a/ash/login/ui/login_expanded_public_account_view_unittest.cc b/ash/login/ui/login_expanded_public_account_view_unittest.cc index a46048d..d944411 100644 --- a/ash/login/ui/login_expanded_public_account_view_unittest.cc +++ b/ash/login/ui/login_expanded_public_account_view_unittest.cc
@@ -3,9 +3,13 @@ // found in the LICENSE file. #include "ash/login/ui/login_expanded_public_account_view.h" +#include "ash/login/mock_login_screen_client.h" +#include "ash/login/ui/arrow_button_view.h" +#include "ash/login/ui/login_bubble.h" #include "ash/login/ui/login_test_base.h" #include "ash/login/ui/login_test_utils.h" #include "ash/login/ui/public_account_warning_dialog.h" +#include "ash/login/ui/views_utils.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/test/event_generator.h" #include "ui/views/layout/box_layout.h" @@ -20,6 +24,17 @@ // Total height of the expanded view. constexpr int kBubbleTotalHeightDp = 324; +// Fake language and keyboard information. +constexpr char kEnglishLanguageCode[] = "language_code1"; +constexpr char kEnglishLanguageName[] = "English"; +constexpr char kFrenchLanguageCode[] = "language_code2"; +constexpr char kFrenchLanguageName[] = "French"; + +constexpr char kKeyboardIdForItem1[] = "keyboard_id1"; +constexpr char kKeyboardNameForItem1[] = "keyboard1"; +constexpr char kKeyboardIdForItem2[] = "keyboard_id2"; +constexpr char kKeyboardNameForItem2[] = "keyboard2"; + class LoginExpandedPublicAccountViewTest : public LoginTestBase { protected: LoginExpandedPublicAccountViewTest() = default; @@ -28,8 +43,10 @@ // LoginTestBase: void SetUp() override { LoginTestBase::SetUp(); - user_ = CreatePublicAccountUser("user@domain.com"); + SetupLanguageInfo(); + SetupKeyboardInfo(); + public_account_ = new LoginExpandedPublicAccountView(base::DoNothing()); public_account_->UpdateForUser(user_); @@ -43,6 +60,47 @@ SetWidget(CreateWidgetWithContent(container_)); } + // Add two fake language items, the first item is selected by default. + void SetupLanguageInfo() { + std::vector<ash::mojom::LocaleItemPtr> result; + ash::mojom::LocaleItemPtr locale_item1 = ash::mojom::LocaleItem::New(); + locale_item1->language_code = kEnglishLanguageCode; + locale_item1->title = kEnglishLanguageName; + + ash::mojom::LocaleItemPtr locale_item2 = ash::mojom::LocaleItem::New(); + locale_item2->language_code = kFrenchLanguageCode; + locale_item2->title = kFrenchLanguageName; + result.push_back(std::move(locale_item1)); + result.push_back(std::move(locale_item2)); + user_->public_account_info->available_locales = std::move(result); + user_->public_account_info->default_locale = kEnglishLanguageCode; + } + + // Add two fake keyboard items, the second item is selected by default. + void SetupKeyboardInfo() { + std::vector<ash::mojom::InputMethodItemPtr> result; + ash::mojom::InputMethodItemPtr keyboard_item1 = + ash::mojom::InputMethodItem::New(); + keyboard_item1->ime_id = kKeyboardIdForItem1; + keyboard_item1->title = kKeyboardNameForItem1; + + ash::mojom::InputMethodItemPtr keyboard_item2 = + ash::mojom::InputMethodItem::New(); + keyboard_item2->ime_id = kKeyboardIdForItem2; + keyboard_item2->title = kKeyboardNameForItem2; + keyboard_item2->selected = true; + result.push_back(std::move(keyboard_item1)); + result.push_back(std::move(keyboard_item2)); + + user_->public_account_info->keyboard_layouts = std::move(result); + } + + void TapOnView(views::View* tap_target) { + GetEventGenerator()->MoveMouseTo( + tap_target->GetBoundsInScreen().CenterPoint()); + GetEventGenerator()->ClickLeftButton(); + } + mojom::LoginUserInfoPtr user_; // Owned by test widget view hierarchy. @@ -76,10 +134,7 @@ EXPECT_EQ(public_account_->height(), kBubbleTotalHeightDp); // Click on the show advanced button. - ui::test::EventGenerator* generator = GetEventGenerator(); - generator->MoveMouseTo( - test_api.advanced_view_button()->GetBoundsInScreen().CenterPoint()); - generator->ClickLeftButton(); + TapOnView(test_api.advanced_view_button()); // Advanced view is hidden and the overall size does not change. EXPECT_FALSE(test_api.advanced_view()->visible()); @@ -123,4 +178,118 @@ EXPECT_FALSE(public_account_->visible()); } +// Verifies tap on submit button will try to launch public session. +TEST_F(LoginExpandedPublicAccountViewTest, LaunchPublicSession) { + LoginExpandedPublicAccountView::TestApi test_api(public_account_); + + // Verify the language and keyboard information is populated correctly. + std::string selected_language = test_api.selected_language_item().value; + std::string selected_keyboard = test_api.selected_keyboard_item().value; + EXPECT_EQ(selected_language, kEnglishLanguageCode); + EXPECT_EQ(selected_keyboard, kKeyboardIdForItem2); + + // Expect LanuchPublicSession mojo call when the submit button is clicked. + std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient(); + EXPECT_CALL(*client, + LaunchPublicSession(user_->basic_user_info->account_id, + selected_language, selected_keyboard)); + + // Click on the submit button. + TapOnView(test_api.submit_button()); + base::RunLoop().RunUntilIdle(); +} + +// Verifies both language and keyboard menus shows up correctly. +TEST_F(LoginExpandedPublicAccountViewTest, ShowLanguageAndKeyboardMenu) { + LoginExpandedPublicAccountView::TestApi test_api(public_account_); + EXPECT_FALSE(user_->public_account_info->show_advanced_view); + EXPECT_FALSE(test_api.advanced_view()->visible()); + + // Toggle show_advanced_view. + user_->public_account_info->show_advanced_view = true; + public_account_->UpdateForUser(user_); + EXPECT_TRUE(test_api.advanced_view()->visible()); + + // Tap on language selection button should bring up the language menu. + EXPECT_FALSE(test_api.language_menu()->IsVisible()); + TapOnView(test_api.language_selection_button()); + EXPECT_TRUE(test_api.language_menu()->IsVisible()); + + // First language item is selected, and selected item should have focus. + EXPECT_EQ(test_api.selected_language_item().value, kEnglishLanguageCode); + auto* language_menu_view = + static_cast<LoginMenuView*>(test_api.language_menu()->bubble_view()); + LoginMenuView::TestApi language_test_api(language_menu_view); + EXPECT_TRUE(language_test_api.contents()->child_count() == 2); + EXPECT_TRUE(language_test_api.contents()->child_at(0)->HasFocus()); + + // Select language item should close the language menu. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0); + EXPECT_FALSE(test_api.language_menu()->IsVisible()); + + // Tap on keyboard selection button should bring up the keyboard menu. + EXPECT_FALSE(test_api.keyboard_menu()->IsVisible()); + TapOnView(test_api.keyboard_selection_button()); + EXPECT_TRUE(test_api.keyboard_menu()->IsVisible()); + + // Second keyboard item is selected, and selected item should have focus. + EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem2); + auto* keyboard_menu_view = + static_cast<LoginMenuView*>(test_api.keyboard_menu()->bubble_view()); + LoginMenuView::TestApi keyboard_test_api(keyboard_menu_view); + EXPECT_TRUE(keyboard_test_api.contents()->child_count() == 2); + EXPECT_TRUE(keyboard_test_api.contents()->child_at(1)->HasFocus()); + + // Select keyboard item should close the keyboard menu. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0); + EXPECT_FALSE(test_api.keyboard_menu()->IsVisible()); +} + +TEST_F(LoginExpandedPublicAccountViewTest, ChangeMenuSelection) { + LoginExpandedPublicAccountView::TestApi test_api(public_account_); + user_->public_account_info->show_advanced_view = true; + public_account_->UpdateForUser(user_); + EXPECT_TRUE(test_api.advanced_view()->visible()); + + // Try to change language selection. + // Open language menu. + TapOnView(test_api.language_selection_button()); + EXPECT_TRUE(test_api.language_menu()->IsVisible()); + + // Select second language item: + // 1. Language menu will be closed automatically. + // 2. Selected language item will change. + // 3. Expect RequestPublicSessionKeyboardLayouts mojo call with the selected + // language item. + std::unique_ptr<MockLoginScreenClient> client = BindMockLoginScreenClient(); + EXPECT_CALL(*client, + RequestPublicSessionKeyboardLayouts( + user_->basic_user_info->account_id, kFrenchLanguageCode)); + + EXPECT_EQ(test_api.selected_language_item().value, kEnglishLanguageCode); + auto* language_menu_view = + static_cast<LoginMenuView*>(test_api.language_menu()->bubble_view()); + LoginMenuView::TestApi language_test_api(language_menu_view); + TapOnView(language_test_api.contents()->child_at(1)); + EXPECT_FALSE(test_api.language_menu()->IsVisible()); + EXPECT_EQ(test_api.selected_language_item().value, kFrenchLanguageCode); + base::RunLoop().RunUntilIdle(); + + // Try to change keyboard selection. + // Open keyboard menu. + TapOnView(test_api.keyboard_selection_button()); + EXPECT_TRUE(test_api.keyboard_menu()->IsVisible()); + + // Select first keyboard item: + // 1. Keyboard menu will be closed automatically. + // 2. Selected keyboard item will change. + EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem2); + auto* keyboard_menu_view = + static_cast<LoginMenuView*>(test_api.keyboard_menu()->bubble_view()); + LoginMenuView::TestApi keyboard_test_api(keyboard_menu_view); + TapOnView(keyboard_test_api.contents()->child_at(0)); + EXPECT_FALSE(test_api.keyboard_menu()->IsVisible()); + EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem1); +} + } // namespace ash
diff --git a/ash/login/ui/login_public_account_user_view.cc b/ash/login/ui/login_public_account_user_view.cc index 31d8ae6f..5ad7ee7 100644 --- a/ash/login/ui/login_public_account_user_view.cc +++ b/ash/login/ui/login_public_account_user_view.cc
@@ -41,6 +41,15 @@ } // namespace +LoginPublicAccountUserView::TestApi::TestApi(LoginPublicAccountUserView* view) + : view_(view) {} + +LoginPublicAccountUserView::TestApi::~TestApi() = default; + +views::View* LoginPublicAccountUserView::TestApi::arrow_button() const { + return view_->arrow_button_; +} + LoginPublicAccountUserView::Callbacks::Callbacks() = default; LoginPublicAccountUserView::Callbacks::Callbacks(const Callbacks& other) =
diff --git a/ash/login/ui/login_public_account_user_view.h b/ash/login/ui/login_public_account_user_view.h index b2f56b9..5bd46a4 100644 --- a/ash/login/ui/login_public_account_user_view.h +++ b/ash/login/ui/login_public_account_user_view.h
@@ -19,10 +19,21 @@ // This is the big user view for the public account user. It wraps a UserView // and a arrow button below. -// TODO(crbug.com/809635): Add test for this class. class ASH_EXPORT LoginPublicAccountUserView : public NonAccessibleView, public views::ButtonListener { public: + // TestApi is used for tests to get internal implementation details. + class ASH_EXPORT TestApi { + public: + explicit TestApi(LoginPublicAccountUserView* view); + ~TestApi(); + + views::View* arrow_button() const; + + private: + LoginPublicAccountUserView* const view_; + }; + using OnPublicAccountTapped = base::RepeatingClosure; struct Callbacks {
diff --git a/ash/login/ui/login_public_account_user_view_unittest.cc b/ash/login/ui/login_public_account_user_view_unittest.cc new file mode 100644 index 0000000..91ebd04 --- /dev/null +++ b/ash/login/ui/login_public_account_user_view_unittest.cc
@@ -0,0 +1,171 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/login/ui/login_public_account_user_view.h" +#include "ash/login/ui/login_test_base.h" +#include "ash/login/ui/login_test_utils.h" +#include "ash/login/ui/login_user_view.h" +#include "ui/events/test/event_generator.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +namespace { + +// Used to trigger hover event in LoginPublicAccountUserView. +constexpr int kNonEmptySize = 20; + +class LoginPublicAccountUserViewTest : public LoginTestBase { + protected: + LoginPublicAccountUserViewTest() = default; + ~LoginPublicAccountUserViewTest() override = default; + + // LoginTestBase: + void SetUp() override { + LoginTestBase::SetUp(); + + user_ = CreatePublicAccountUser("user@domain.com"); + + LoginPublicAccountUserView::Callbacks public_account_callbacks; + public_account_callbacks.on_tap = + base::BindRepeating(&LoginPublicAccountUserViewTest::OnUserViewTapped, + base::Unretained(this)); + public_account_callbacks.on_public_account_tapped = base::BindRepeating( + &LoginPublicAccountUserViewTest::OnPublicAccountTapped, + base::Unretained(this)); + public_account_view_ = + new LoginPublicAccountUserView(user_, public_account_callbacks); + + focusable_view_ = new views::View(); + focusable_view_->SetFocusBehavior(views::View::FocusBehavior::ALWAYS); + focusable_view_->SetPreferredSize(gfx::Size(kNonEmptySize, kNonEmptySize)); + + // We proxy |public_account_view_| inside of |container| so we can control + // layout. + auto* container = new views::View(); + container->SetLayoutManager( + std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical)); + container->AddChildView(public_account_view_); + container->AddChildView(focusable_view_); + SetWidget(CreateWidgetWithContent(container)); + } + + mojom::LoginUserInfoPtr user_; + + LoginPublicAccountUserView* public_account_view_ = nullptr; + views::View* focusable_view_ = nullptr; + + int user_view_tap_count_ = 0; + int public_account_tap_count_ = 0; + + private: + void OnUserViewTapped() { ++user_view_tap_count_; } + void OnPublicAccountTapped() { ++public_account_tap_count_; } + + DISALLOW_COPY_AND_ASSIGN(LoginPublicAccountUserViewTest); +}; + +} // namespace + +// Verifies that an auth enabled public account user is opaque. +// Verifies that hovered view is opaque. +TEST_F(LoginPublicAccountUserViewTest, EnableAuthAndHoverOpaque) { + LoginPublicAccountUserView::TestApi public_account_test(public_account_view_); + LoginUserView::TestApi user_test(public_account_view_->user_view()); + + // Make focusable_view_ to hold focus. The user view cannot have focus + // since focus will keep it opaque. + focusable_view_->RequestFocus(); + EXPECT_FALSE(public_account_view_->user_view()->HasFocus()); + EXPECT_FALSE(user_test.is_opaque()); + EXPECT_NE(public_account_test.arrow_button()->layer()->opacity(), 1); + + // Auth enabled view must be opaque. + public_account_view_->SetAuthEnabled(true /*enabled*/, false /*animate*/); + EXPECT_TRUE(user_test.is_opaque()); + EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1); + + // Auth enabled view stays opaque regardless of hover. + GetEventGenerator()->MoveMouseTo( + public_account_view_->GetBoundsInScreen().CenterPoint()); + EXPECT_TRUE(user_test.is_opaque()); + EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1); + GetEventGenerator()->MoveMouseTo( + focusable_view_->GetBoundsInScreen().CenterPoint()); + EXPECT_TRUE(user_test.is_opaque()); + EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1); + + // Disable auth makes view non-opaque. + public_account_view_->SetAuthEnabled(false /*enabled*/, false /*animate*/); + EXPECT_FALSE(user_test.is_opaque()); + EXPECT_NE(public_account_test.arrow_button()->layer()->opacity(), 1); + + // Move mouse over the view makes it opaque. + GetEventGenerator()->MoveMouseTo( + public_account_view_->user_view()->GetBoundsInScreen().CenterPoint()); + EXPECT_TRUE(user_test.is_opaque()); + EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1); + + // Move out the view makes it non-opaque. + GetEventGenerator()->MoveMouseTo( + focusable_view_->GetBoundsInScreen().CenterPoint()); + EXPECT_FALSE(user_test.is_opaque()); + EXPECT_NE(public_account_test.arrow_button()->layer()->opacity(), 1); +} + +// Verifies that LoginPublicAccountUserView::Callbacks run successfully. +TEST_F(LoginPublicAccountUserViewTest, VerifyCallackRun) { + LoginPublicAccountUserView::TestApi public_account_test(public_account_view_); + + // Tap on the user view and verify on_tap callback is run. + GetEventGenerator()->MoveMouseTo( + public_account_view_->user_view()->GetBoundsInScreen().CenterPoint()); + GetEventGenerator()->ClickLeftButton(); + EXPECT_EQ(user_view_tap_count_, 1); + + // Tap on the arrow button and verify on_public_account_tapped callback is + // run. + GetEventGenerator()->MoveMouseTo( + public_account_test.arrow_button()->GetBoundsInScreen().CenterPoint()); + GetEventGenerator()->ClickLeftButton(); + EXPECT_EQ(public_account_tap_count_, 1); +} + +// Verifies that displaying the arrow button does not change the view bounds. +// Also arrow button should always have the same horizontal centering as user +// view. +TEST_F(LoginPublicAccountUserViewTest, ArrowButtonDoesNotChangeViewBounds) { + LoginPublicAccountUserView::TestApi public_account_test(public_account_view_); + EXPECT_FALSE(public_account_view_->auth_enabled()); + const gfx::Rect auth_disabled_bounds = + public_account_view_->GetBoundsInScreen(); + EXPECT_NE(auth_disabled_bounds, gfx::Rect()); + + // Move mouse over the view, the arrow button becomes opaque. + // View bounds should not change. + GetEventGenerator()->MoveMouseTo( + public_account_view_->user_view()->GetBoundsInScreen().CenterPoint()); + EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1); + EXPECT_EQ(public_account_view_->GetBoundsInScreen(), auth_disabled_bounds); + EXPECT_EQ(public_account_view_->GetBoundsInScreen().x(), + public_account_test.arrow_button()->GetBoundsInScreen().x()); + + // Move out the view makes it non-opaque. View bounds should stay the same. + GetEventGenerator()->MoveMouseTo( + focusable_view_->GetBoundsInScreen().CenterPoint()); + EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 0); + EXPECT_EQ(public_account_view_->GetBoundsInScreen(), auth_disabled_bounds); + + // Set auth enable forces arrow button to be opaque. + // View bounds should not change. + public_account_view_->SetAuthEnabled(true /*enabled*/, false /*animate*/); + EXPECT_TRUE(public_account_view_->auth_enabled()); + EXPECT_EQ(public_account_test.arrow_button()->layer()->opacity(), 1); + EXPECT_EQ(public_account_view_->GetBoundsInScreen(), auth_disabled_bounds); + EXPECT_EQ(public_account_view_->GetBoundsInScreen().x(), + public_account_test.arrow_button()->GetBoundsInScreen().x()); +} + +} // namespace ash
diff --git a/ash/login/ui/login_user_view.cc b/ash/login/ui/login_user_view.cc index 5d410b8..16037ea 100644 --- a/ash/login/ui/login_user_view.cc +++ b/ash/login/ui/login_user_view.cc
@@ -323,6 +323,10 @@ return view_->menu_.get(); } +views::View* LoginUserView::TestApi::user_domain() const { + return view_->user_domain_; +} + bool LoginUserView::TestApi::is_opaque() const { return view_->is_opaque_; }
diff --git a/ash/login/ui/login_user_view.h b/ash/login/ui/login_user_view.h index 746697a..c91a6b1 100644 --- a/ash/login/ui/login_user_view.h +++ b/ash/login/ui/login_user_view.h
@@ -37,6 +37,7 @@ views::View* tap_button() const; views::View* dropdown() const; LoginBubble* menu() const; + views::View* user_domain() const; bool is_opaque() const;
diff --git a/ash/login/ui/login_user_view_unittest.cc b/ash/login/ui/login_user_view_unittest.cc index dc93a7f5..30d1e82 100644 --- a/ash/login/ui/login_user_view_unittest.cc +++ b/ash/login/ui/login_user_view_unittest.cc
@@ -23,8 +23,8 @@ // Builds a new LoginUserView instance and adds it to |container_|. LoginUserView* AddUserView(LoginDisplayStyle display_style, - bool show_dropdown) { - // TODO(crbug.com/809635): Add test case for show_domain. + bool show_dropdown, + bool public_account) { LoginUserView::OnRemoveWarningShown on_remove_warning_shown; LoginUserView::OnRemove on_remove; if (show_dropdown) { @@ -35,11 +35,14 @@ } auto* view = - new LoginUserView(display_style, show_dropdown, false /*show_domain*/, + new LoginUserView(display_style, show_dropdown, public_account, base::BindRepeating(&LoginUserViewUnittest::OnTapped, base::Unretained(this)), on_remove_warning_shown, on_remove); - mojom::LoginUserInfoPtr user = CreateUser("foo@foo.com"); + + std::string email = "foo@foo.com"; + mojom::LoginUserInfoPtr user = + public_account ? CreatePublicAccountUser(email) : CreateUser(email); view->UpdateForUser(user, false /*animate*/); container_->AddChildView(view); widget()->GetContentsView()->Layout(); @@ -79,10 +82,15 @@ // Verifies that the user view does not change width for short/long usernames. TEST_F(LoginUserViewUnittest, DifferentUsernamesHaveSameWidth) { - LoginUserView* large = AddUserView(LoginDisplayStyle::kLarge, false); - LoginUserView* small = AddUserView(LoginDisplayStyle::kSmall, false); + LoginUserView* large = + AddUserView(LoginDisplayStyle::kLarge, false /*show_dropdown*/, + false /*public_account*/); + LoginUserView* small = + AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/, + false /*public_account*/); LoginUserView* extra_small = - AddUserView(LoginDisplayStyle::kExtraSmall, false); + AddUserView(LoginDisplayStyle::kExtraSmall, false /*show_dropdown*/, + false /*public_account*/); int large_width = large->size().width(); int small_width = small->size().width(); @@ -107,10 +115,15 @@ // Verifies that the user views all have different sizes with different display // styles. TEST_F(LoginUserViewUnittest, DifferentStylesHaveDifferentSizes) { - LoginUserView* large = AddUserView(LoginDisplayStyle::kLarge, false); - LoginUserView* small = AddUserView(LoginDisplayStyle::kSmall, false); + LoginUserView* large = + AddUserView(LoginDisplayStyle::kLarge, false /*show_dropdown*/, + false /*public_account*/); + LoginUserView* small = + AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/, + false /*public_account*/); LoginUserView* extra_small = - AddUserView(LoginDisplayStyle::kExtraSmall, false); + AddUserView(LoginDisplayStyle::kExtraSmall, false /*show_dropdown*/, + false /*public_account*/); EXPECT_NE(large->size(), gfx::Size()); EXPECT_NE(large->size(), small->size()); @@ -121,8 +134,12 @@ // Verifies that displaying the dropdown does not change the view size. Further, // the dropdown should not change the centering for the user label. TEST_F(LoginUserViewUnittest, DropdownDoesNotChangeSize) { - LoginUserView* with = AddUserView(LoginDisplayStyle::kLarge, true); - LoginUserView* without = AddUserView(LoginDisplayStyle::kLarge, false); + LoginUserView* with = + AddUserView(LoginDisplayStyle::kLarge, true /*show_dropdown*/, + false /*public_account*/); + LoginUserView* without = + AddUserView(LoginDisplayStyle::kLarge, false /*show_dropdown*/, + false /*public_account*/); EXPECT_NE(with->size(), gfx::Size()); EXPECT_EQ(with->size(), without->size()); @@ -138,7 +155,9 @@ // Verifies that the entire user view is a tap target, and not just (for // example) the user icon. TEST_F(LoginUserViewUnittest, EntireViewIsTapTarget) { - LoginUserView* view = AddUserView(LoginDisplayStyle::kSmall, false); + LoginUserView* view = + AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/, + false /*public_account*/); EXPECT_NE(view->size(), gfx::Size()); // Returns true if there is a tap at |point| offset by |dx|, |dy|. @@ -165,8 +184,12 @@ // Verifies the focused user view is opaque. Verifies that a hovered view is // opaque. Verifies the interaction between focus and hovered opaqueness. TEST_F(LoginUserViewUnittest, FocusHoverOpaqueInteractions) { - LoginUserView* one = AddUserView(LoginDisplayStyle::kSmall, false); - LoginUserView* two = AddUserView(LoginDisplayStyle::kSmall, false); + LoginUserView* one = + AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/, + false /*public_account*/); + LoginUserView* two = + AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/, + false /*public_account*/); LoginUserView::TestApi one_test(one); LoginUserView::TestApi two_test(two); @@ -207,8 +230,12 @@ // focus, and that a forced opaque element can transition to both // opaque/transparent when losing forced opaque. TEST_F(LoginUserViewUnittest, ForcedOpaque) { - LoginUserView* one = AddUserView(LoginDisplayStyle::kSmall, false); - LoginUserView* two = AddUserView(LoginDisplayStyle::kSmall, false); + LoginUserView* one = + AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/, + false /*public_account*/); + LoginUserView* two = + AddUserView(LoginDisplayStyle::kSmall, false /*show_dropdown*/, + false /*public_account*/); LoginUserView::TestApi one_test(one); LoginUserView::TestApi two_test(two); @@ -248,7 +275,9 @@ // Verifies that a long user name does not push the label or dropdown button // outside of the LoginUserView bounds. TEST_F(LoginUserViewUnittest, ElideUserLabel) { - LoginUserView* view = AddUserView(LoginDisplayStyle::kLarge, true); + LoginUserView* view = + AddUserView(LoginDisplayStyle::kLarge, true /*show_dropdown*/, + false /*public_account*/); LoginUserView::TestApi view_test(view); mojom::LoginUserInfoPtr user = @@ -262,4 +291,23 @@ view_test.dropdown()->GetVisibleBounds())); } +// Verifies that displaying the domain does not change the view width. +// Also domain should have the same horizontal centering as user label. +TEST_F(LoginUserViewUnittest, DomainDoesNotChangeWidth) { + LoginUserView* public_account = + AddUserView(LoginDisplayStyle::kLarge, false /*show_dropdown*/, + true /*public_account*/); + LoginUserView* regular_user = + AddUserView(LoginDisplayStyle::kLarge, false /*show_dropdown*/, + false /*public_account*/); + EXPECT_NE(regular_user->size().width(), 0); + EXPECT_EQ(regular_user->size().width(), public_account->size().width()); + + views::View* user_label = LoginUserView::TestApi(public_account).user_label(); + views::View* user_domain = + LoginUserView::TestApi(public_account).user_label(); + EXPECT_EQ(user_label->GetBoundsInScreen().CenterPoint().x(), + user_domain->GetBoundsInScreen().CenterPoint().x()); +} + } // namespace ash
diff --git a/ash/system/ime/tray_ime_chromeos_unittest.cc b/ash/system/ime/tray_ime_chromeos_unittest.cc index 395ffce..1d59292 100644 --- a/ash/system/ime/tray_ime_chromeos_unittest.cc +++ b/ash/system/ime/tray_ime_chromeos_unittest.cc
@@ -109,8 +109,8 @@ input_device_client_test_api.SetTouchscreenDevices(screens); std::vector<ui::InputDevice> keyboards; - keyboards.push_back(ui::InputDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard")); + keyboards.push_back( + ui::InputDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")); input_device_client_test_api.SetKeyboardDevices(keyboards); }
diff --git a/ash/system/power/backlights_forced_off_setter_unittest.cc b/ash/system/power/backlights_forced_off_setter_unittest.cc index aeaf22c..a584d38 100644 --- a/ash/system/power/backlights_forced_off_setter_unittest.cc +++ b/ash/system/power/backlights_forced_off_setter_unittest.cc
@@ -223,7 +223,7 @@ // Initialize an external touch device. ui::TouchscreenDevice external_touchdevice( - 123, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + 123, ui::InputDeviceType::INPUT_DEVICE_USB, std::string("test external touch device"), gfx::Size(1000, 1000), 1); ui::TouchscreenDevice internal_touchdevice(
diff --git a/ash/system/power/peripheral_battery_notifier_unittest.cc b/ash/system/power/peripheral_battery_notifier_unittest.cc index fe747ba..420cf56 100644 --- a/ash/system/power/peripheral_battery_notifier_unittest.cc +++ b/ash/system/power/peripheral_battery_notifier_unittest.cc
@@ -189,7 +189,7 @@ const std::string kTestStylusName = "test_stylus"; // Add an external stylus to our test device manager. - ui::TouchscreenDevice stylus(0 /* id */, ui::INPUT_DEVICE_EXTERNAL, + ui::TouchscreenDevice stylus(0 /* id */, ui::INPUT_DEVICE_USB, kTestStylusName, gfx::Size(), 1 /* touch_points */, true /* has_stylus */); stylus.sys_path = base::FilePath(kTestStylusBatteryPath);
diff --git a/ash/system/power/power_prefs.cc b/ash/system/power/power_prefs.cc index 0a90fada..ba0a2b36 100644 --- a/ash/system/power/power_prefs.cc +++ b/ash/system/power/power_prefs.cc
@@ -256,6 +256,7 @@ prefs->GetBoolean(prefs::kPowerWaitForInitialUserActivity); values.force_nonzero_brightness_for_user_activity = prefs->GetBoolean(prefs::kPowerForceNonzeroBrightnessForUserActivity); + values.smart_dim_enabled = prefs->GetBoolean(prefs::kPowerSmartDimEnabled); power_policy_controller_->ApplyPrefs(values); }
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc index 1c491c70..a336737 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -140,6 +140,9 @@ Shell::Get()->window_tree_host_manager()->AddObserver(this); chromeos::AccelerometerReader::GetInstance()->AddObserver(this); ui::InputDeviceManager::GetInstance()->AddObserver(this); + bluetooth_devices_observer_ = std::make_unique<BluetoothDevicesObserver>( + base::BindRepeating(&TabletModeController::UpdateBluetoothDevice, + base::Unretained(this))); } chromeos::PowerManagerClient* power_manager_client = chromeos::DBusThreadManager::Get()->GetPowerManagerClient(); @@ -562,7 +565,9 @@ bool has_external_mouse = false; for (const ui::InputDevice& mouse : ui::InputDeviceManager::GetInstance()->GetMouseDevices()) { - if (mouse.type == ui::INPUT_DEVICE_EXTERNAL) { + if (mouse.type == ui::INPUT_DEVICE_USB || + (mouse.type == ui::INPUT_DEVICE_BLUETOOTH && + bluetooth_devices_observer_->IsConnectedBluetoothDevice(mouse))) { has_external_mouse = true; break; } @@ -615,4 +620,19 @@ lid_angle_ >= kEnterTabletModeAngle; } +void TabletModeController::UpdateBluetoothDevice( + device::BluetoothDevice* device) { + // We only care about mouse type bluetooth device change. Note KEYBOARD + // type is also included here as sometimes a bluetooth keyboard comes with a + // touch pad. + if (device->GetDeviceType() != device::BluetoothDeviceType::MOUSE && + device->GetDeviceType() != + device::BluetoothDeviceType::KEYBOARD_MOUSE_COMBO && + device->GetDeviceType() != device::BluetoothDeviceType::KEYBOARD) { + return; + } + + HandleMouseAddedOrRemoved(); +} + } // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.h b/ash/wm/tablet_mode/tablet_mode_controller.h index 4555e520..4b78118 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller.h +++ b/ash/wm/tablet_mode/tablet_mode_controller.h
@@ -8,6 +8,7 @@ #include <memory> #include "ash/ash_export.h" +#include "ash/bluetooth_devices_observer.h" #include "ash/display/window_tree_host_manager.h" #include "ash/public/interfaces/tablet_mode.mojom.h" #include "ash/session/session_observer.h" @@ -132,7 +133,7 @@ void SuspendImminent(power_manager::SuspendImminent::Reason reason) override; void SuspendDone(const base::TimeDelta& sleep_duration) override; - // ui::InputDeviceEventObserver:: + // ui::InputDeviceEventObserver: void OnMouseDeviceConfigurationChanged() override; void OnDeviceListsComplete() override; @@ -211,6 +212,10 @@ // angle range. bool LidAngleIsInTabletModeRange(); + // Callback function for |bluetooth_devices_observer_|. Called when |device| + // changes. + void UpdateBluetoothDevice(device::BluetoothDevice* device); + // The maximized window manager (if enabled). std::unique_ptr<TabletModeWindowManager> tablet_mode_window_manager_; @@ -257,6 +262,11 @@ // not enter tablet mode if this is true. bool has_external_mouse_ = false; + // Tracks if the device would enter tablet mode, but does not because of a + // attached external mouse. If the external mouse is detached and this is + // true, we will enter tablet mode. + bool should_enter_tablet_mode_ = false; + // Tracks smoothed accelerometer data over time. This is done when the hinge // is approaching vertical to remove abrupt acceleration that can lead to // incorrect calculations of hinge angles. @@ -277,6 +287,9 @@ ScopedSessionObserver scoped_session_observer_; + // Observer to observe the bluetooth devices. + std::unique_ptr<BluetoothDevicesObserver> bluetooth_devices_observer_; + base::ObserverList<TabletModeObserver>::Unchecked tablet_mode_observers_; base::WeakPtrFactory<TabletModeController> weak_factory_;
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc b/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc index 89bae99..ef0d7439 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc
@@ -27,7 +27,7 @@ void TabletModeControllerTestApi::AttachExternalMouse() { ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")}); + 3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")}); base::RunLoop().RunUntilIdle(); tablet_mode_controller_->OnMouseDeviceConfigurationChanged(); }
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc index a99be0c6..a21d35e 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -662,8 +662,8 @@ EXPECT_TRUE(AreEventsBlocked()); // Tests that attaching a external mouse will not change the mode. - ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")}); + ws::InputDeviceClientTestApi().SetMouseDevices( + {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")}); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(IsTabletModeStarted()); EXPECT_TRUE(AreEventsBlocked()); @@ -761,8 +761,8 @@ EXPECT_FALSE(IsTabletModeStarted()); // Attach a external mouse. - ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")}); + ws::InputDeviceClientTestApi().SetMouseDevices( + {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")}); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(IsTabletModeStarted()); @@ -787,8 +787,8 @@ // Attach external mouse and keyboard. Verify that tablet mode has ended, but // events are still blocked because the keyboard is still facing the bottom. - ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")}); + ws::InputDeviceClientTestApi().SetMouseDevices( + {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")}); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(IsTabletModeStarted()); EXPECT_TRUE(AreEventsBlocked()); @@ -816,7 +816,7 @@ // Attach external mouse doesn't change the mode. ws::InputDeviceClientTestApi().SetMouseDevices({ui::InputDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "mouse")}); + 3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")}); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(IsTabletModeStarted()); EXPECT_FALSE(AreEventsBlocked());
diff --git a/base/message_loop/message_loop_task_runner.cc b/base/message_loop/message_loop_task_runner.cc index a941a01..abb632f7 100644 --- a/base/message_loop/message_loop_task_runner.cc +++ b/base/message_loop/message_loop_task_runner.cc
@@ -108,8 +108,7 @@ } void MessageLoopTaskRunner::SetAddQueueTimeToTasks(bool enable) { - DCHECK_NE(add_queue_time_to_tasks_, enable); - add_queue_time_to_tasks_ = enable; + base::subtle::NoBarrier_Store(&add_queue_time_to_tasks_, enable ? 1 : 0); } MessageLoopTaskRunner::~MessageLoopTaskRunner() = default; @@ -127,7 +126,8 @@ PendingTask pending_task(from_here, std::move(task), CalculateDelayedRuntime(from_here, delay), nestable); - if (add_queue_time_to_tasks_) { + + if (base::subtle::NoBarrier_Load(&add_queue_time_to_tasks_)) { if (pending_task.delayed_run_time.is_null()) { pending_task.queue_time = base::TimeTicks::Now(); } else {
diff --git a/base/message_loop/message_loop_task_runner.h b/base/message_loop/message_loop_task_runner.h index 37a4de4..f9ba2d1 100644 --- a/base/message_loop/message_loop_task_runner.h +++ b/base/message_loop/message_loop_task_runner.h
@@ -5,6 +5,7 @@ #ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_ #define BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_ +#include "base/atomicops.h" #include "base/base_export.h" #include "base/callback.h" #include "base/macros.h" @@ -105,7 +106,7 @@ int next_sequence_num_ = 0; // Whether to add the queue time to tasks. - bool add_queue_time_to_tasks_ = false; + base::subtle::Atomic32 add_queue_time_to_tasks_ = 0; DISALLOW_COPY_AND_ASSIGN(MessageLoopTaskRunner); };
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.cc b/base/trace_event/heap_profiler_allocation_context_tracker.cc index 98f5d11..556719e 100644 --- a/base/trace_event/heap_profiler_allocation_context_tracker.cc +++ b/base/trace_event/heap_profiler_allocation_context_tracker.cc
@@ -259,7 +259,13 @@ ctx->backtrace.frame_count = backtrace - std::begin(ctx->backtrace.frames); - ctx->type_name = TaskContext(); + // TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension + // (component name) in the heap profiler and not piggy back on the type name. + if (!task_contexts_.empty()) { + ctx->type_name = task_contexts_.back(); + } else { + ctx->type_name = nullptr; + } return true; }
diff --git a/base/trace_event/heap_profiler_allocation_context_tracker.h b/base/trace_event/heap_profiler_allocation_context_tracker.h index a117ea0..da03b7f6 100644 --- a/base/trace_event/heap_profiler_allocation_context_tracker.h +++ b/base/trace_event/heap_profiler_allocation_context_tracker.h
@@ -108,11 +108,6 @@ void PushCurrentTaskContext(const char* context); void PopCurrentTaskContext(const char* context); - // Returns most recent task context added by ScopedTaskExecutionTracker. - const char* TaskContext() const { - return task_contexts_.empty() ? nullptr : task_contexts_.back(); - } - // Fills a snapshot of the current thread-local context. Doesn't fill and // returns false if allocations are being ignored. bool GetContextSnapshot(AllocationContext* snapshot);
diff --git a/build/chromeos/run_vm_test.py b/build/chromeos/run_vm_test.py index cc7c078..964c0f3d 100755 --- a/build/chromeos/run_vm_test.py +++ b/build/chromeos/run_vm_test.py
@@ -29,6 +29,8 @@ 0, os.path.join(CHROMIUM_SRC_PATH, 'tools', 'swarming_client', 'utils')) import subprocess42 # pylint: disable=import-error +DEFAULT_CROS_CACHE = os.path.abspath(os.path.join( + CHROMIUM_SRC_PATH, 'build', 'cros_cache')) CHROMITE_PATH = os.path.abspath(os.path.join( CHROMIUM_SRC_PATH, 'third_party', 'chromite')) CROS_RUN_VM_TEST_PATH = os.path.abspath(os.path.join( @@ -47,11 +49,9 @@ def __init__(self, args, unknown_args): self._additional_args = unknown_args self._path_to_outdir = args.path_to_outdir - self._test_exe = args.test_exe self._test_launcher_summary_output = args.test_launcher_summary_output self._vm_logs_dir = args.vm_logs_dir - self._test_env = os.environ.copy() self._retries = 0 self._timeout = None @@ -67,6 +67,23 @@ '--results-dest-dir', args.vm_logs_dir, ] + self._test_env = os.environ.copy() + # deploy_chrome needs a set of GN args used to build chrome to determine if + # certain libraries need to be pushed to the VM. It looks for the args via + # an env var. To trigger the default deploying behavior, give it a dummy set + # of args. + # TODO(crbug.com/823996): Make the GN-dependent deps controllable via cmd + # line args. + if not self._test_env.get('GN_ARGS'): + self._test_env['GN_ARGS'] = 'is_chromeos = true' + if not self._test_env.get('USE'): + self._test_env['USE'] = 'highdpi' + self._test_env['PATH'] = ( + self._test_env['PATH'] + ':' + os.path.join(CHROMITE_PATH, 'bin')) + @property + def suite_name(self): + raise NotImplementedError('Child classes need to define suite name.') + @property def vm_test_cmd(self): return self._vm_test_cmd @@ -119,7 +136,45 @@ return test_proc.returncode def post_run(self, return_code): - raise NotImplementedError() + # Create a simple json results file for a test run. The results will contain + # only one test (suite_name), and will either be a PASS or FAIL depending on + # return_code. + if self._test_launcher_summary_output: + result = (base_test_result.ResultType.FAIL if return_code else + base_test_result.ResultType.PASS) + suite_result = base_test_result.BaseTestResult(self.suite_name, result) + run_results = base_test_result.TestRunResults() + run_results.AddResult(suite_result) + with open(self._test_launcher_summary_output, 'w') as f: + json.dump(json_results.GenerateResultsDict([run_results]), f) + + +class TastTest(RemoteTest): + + def __init__(self, args, unknown_args): + super(TastTest, self).__init__(args, unknown_args) + + self._suite_name = args.suite_name + self._tests = args.tests + + @property + def suite_name(self): + return self._suite_name + + def build_test_command(self): + if self._additional_args: + raise TestFormatError( + 'Tast tests should not have additional args: %s' % ( + self._additional_args)) + + self._vm_test_cmd += [ + '--deploy', + '--build-dir', os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH), + '--cmd', + '--', + 'local_test_runner', + ] + self._vm_test_cmd.extend(self._tests) class GTestTest(RemoteTest): @@ -133,6 +188,7 @@ def __init__(self, args, unknown_args): super(GTestTest, self).__init__(args, unknown_args) + self._test_exe = args.test_exe self._runtime_deps_path = args.runtime_deps_path self._vpython_dir = args.vpython_dir @@ -141,6 +197,10 @@ self._on_vm_script = None + @property + def suite_name(self): + return self._test_exe + def build_test_command(self): # To keep things easy for us, ensure both types of output locations are # the same. @@ -284,6 +344,10 @@ self._retries = 2 self._timeout = 300 + @property + def suite_name(self): + return SANITY_TEST_TARGET + def build_test_command(self): if '--gtest_filter=%s' % SANITY_TEST_TARGET in self._additional_args: logging.info( @@ -304,33 +368,6 @@ '--build-dir', os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH), ] - # deploy_chrome needs a set of GN args used to build chrome to determine if - # certain libraries need to be pushed to the VM. It looks for the args via - # an env var. To trigger the default deploying behavior, give it a dummy set - # of args. - # TODO(crbug.com/823996): Make the GN-dependent deps controllable via cmd - # line args. - if not self._test_env.get('GN_ARGS'): - self._test_env['GN_ARGS'] = 'is_chromeos = true' - if not self._test_env.get('USE'): - self._test_env['USE'] = 'highdpi' - self._test_env['PATH'] = ( - self._test_env['PATH'] + ':' + os.path.join(CHROMITE_PATH, 'bin')) - - def post_run(self, return_code): - # Create a simple json results file for the sanity test if needed. The - # results will contain only one test (SANITY_TEST_TARGET), and will - # either be a PASS or FAIL depending on the return code of cros_run_vm_test. - if self._test_launcher_summary_output: - result = (base_test_result.ResultType.FAIL if return_code else - base_test_result.ResultType.PASS) - sanity_test_result = base_test_result.BaseTestResult( - SANITY_TEST_TARGET, result) - run_results = base_test_result.TestRunResults() - run_results.AddResult(sanity_test_result) - with open(self._test_launcher_summary_output, 'w') as f: - json.dump(json_results.GenerateResultsDict([run_results]), f) - def vm_test(args, unknown_args): # cros_run_vm_test has trouble with relative paths that go up directories, @@ -340,7 +377,9 @@ # pylint: disable=redefined-variable-type # TODO: Remove the above when depot_tool's pylint is updated to include the # fix to https://github.com/PyCQA/pylint/issues/710. - if args.test_exe == SANITY_TEST_TARGET: + if args.test_type == 'tast': + test = TastTest(args, unknown_args) + elif args.test_exe == SANITY_TEST_TARGET: test = BrowserSanityTest(args, unknown_args) else: test = GTestTest(args, unknown_args) @@ -402,6 +441,30 @@ cros_run_vm_test_cmd, stdout=sys.stdout, stderr=sys.stderr, env=test_env) +def add_common_args(parser): + parser.add_argument( + '--cros-cache', type=str, default=DEFAULT_CROS_CACHE, + help='Path to cros cache.') + parser.add_argument( + '--path-to-outdir', type=str, required=True, + help='Path to output directory, all of whose contents will be ' + 'deployed to the device.') + parser.add_argument( + '--runtime-deps-path', type=str, + help='Runtime data dependency file from GN.') + parser.add_argument( + '--vpython-dir', type=str, + help='Location on host of a directory containing a vpython binary to ' + 'deploy to the VM before the test starts. The location of this ' + 'dir will be added onto PATH in the VM. WARNING: The arch of the ' + 'VM might not match the arch of the host, so avoid using ' + '"${platform}" when downloading vpython via CIPD.') + parser.add_argument( + '--vm-logs-dir', type=str, + help='Will copy everything under /var/log/ from the VM after the test ' + 'into the specified dir.') + + def main(): parser = argparse.ArgumentParser() parser.add_argument('--verbose', '-v', action='store_true') @@ -416,7 +479,8 @@ '"--". Hostname and port for the VM will be 127.0.0.1:9222.') host_cmd_parser.set_defaults(func=host_cmd) host_cmd_parser.add_argument( - '--cros-cache', type=str, required=True, help='Path to cros cache.') + '--cros-cache', type=str, default=DEFAULT_CROS_CACHE, + help='Path to cros cache.') host_cmd_parser.add_argument( '--path-to-outdir', type=os.path.realpath, help='Path to output directory, all of whose contents will be deployed ' @@ -426,14 +490,13 @@ help='Will deploy a locally built Chrome binary to the VM before running ' 'the host-cmd.') host_cmd_parser.add_argument('cmd', nargs=argparse.REMAINDER) - # VM-side test args. - vm_test_parser = subparsers.add_parser( + # GTest args. + # TODO(bpastene): Rename 'vm-test' arg to 'gtest'. + gtest_parser = subparsers.add_parser( 'vm-test', help='Runs a vm-side gtest.') - vm_test_parser.set_defaults(func=vm_test) - vm_test_parser.add_argument( - '--cros-cache', type=str, required=True, help='Path to cros cache.') - vm_test_parser.add_argument( + gtest_parser.set_defaults(func=vm_test) + gtest_parser.add_argument( '--test-exe', type=str, required=True, help='Path to test executable to run inside VM. If the value is ' '%s, the sanity test that ships with the VM ' @@ -444,39 +507,39 @@ # GTest args. Some are passed down to the test binary in the VM. Others are # parsed here since they might need tweaking or special handling. - vm_test_parser.add_argument( + gtest_parser.add_argument( '--test-launcher-summary-output', type=str, help='When set, will pass the same option down to the test and retrieve ' 'its result file at the specified location.') # Shard args are parsed here since we might also specify them via env vars. - vm_test_parser.add_argument( + gtest_parser.add_argument( '--test-launcher-shard-index', type=int, default=os.environ.get('GTEST_SHARD_INDEX', 0), help='Index of the external shard to run.') - vm_test_parser.add_argument( + gtest_parser.add_argument( '--test-launcher-total-shards', type=int, default=os.environ.get('GTEST_TOTAL_SHARDS', 1), help='Total number of external shards.') - # Misc args. - vm_test_parser.add_argument( - '--path-to-outdir', type=str, required=True, - help='Path to output directory, all of whose contents will be deployed ' - 'to the device.') - vm_test_parser.add_argument( - '--runtime-deps-path', type=str, - help='Runtime data dependency file from GN.') - vm_test_parser.add_argument( - '--vpython-dir', type=str, - help='Location on host of a directory containing a vpython binary to ' - 'deploy to the VM before the test starts. The location of this dir ' - 'will be added onto PATH in the VM. WARNING: The arch of the VM ' - 'might not match the arch of the host, so avoid using "${platform}" ' - 'when downloading vpython via CIPD.') - vm_test_parser.add_argument( - '--vm-logs-dir', type=str, - help='Will copy everything under /var/log/ from the VM after the test ' - 'into the specified dir.') + # Tast test args. + tast_test_parser = subparsers.add_parser( + 'tast', + help='Runs a vm-side set of Tast tests.') + tast_test_parser.set_defaults(func=vm_test) + tast_test_parser.add_argument( + '--suite-name', type=str, required=True, + help='Name to apply to the set of Tast tests to run. This has no effect ' + 'on what is executed, but is used mainly for test results reporting ' + 'and tracking (eg: flakiness dashboard).') + tast_test_parser.add_argument( + '--test-launcher-summary-output', type=str, + help='Generates a simple GTest-style JSON result file for the test run.') + tast_test_parser.add_argument( + '--test', '-t', action='append', dest='tests', required=True, + help='A Tast test to run in the VM (eg: "ui.ChromeLogin").') + + add_common_args(gtest_parser) + add_common_args(tast_test_parser) args, unknown_args = parser.parse_known_args() logging.basicConfig(level=logging.DEBUG if args.verbose else logging.WARN)
diff --git a/build/fuchsia/device_target.py b/build/fuchsia/device_target.py index 0f8e270..862b10b 100644 --- a/build/fuchsia/device_target.py +++ b/build/fuchsia/device_target.py
@@ -5,11 +5,13 @@ """Implements commands for running and interacting with Fuchsia on devices.""" import boot_data +import filecmp import logging import os import subprocess import sys import target +import tempfile import time import uuid @@ -21,6 +23,8 @@ # Number of failed connection attempts before redirecting system logs to stdout. CONNECT_RETRY_COUNT_BEFORE_LOGGING = 10 +TARGET_HASH_FILE_PATH = '/data/.hash' + class DeviceTarget(target.Target): def __init__(self, output_dir, target_cpu, host=None, port=None, ssh_config=None, system_log_file=None): @@ -54,6 +58,20 @@ if self._loglistener: self._loglistener.kill() + def _SDKHashMatches(self): + """Checks if /data/.hash on the device matches SDK_ROOT/.hash. + + Returns True if the files are identical, or False otherwise. + """ + with tempfile.NamedTemporaryFile() as tmp: + try: + self.GetFile(TARGET_HASH_FILE_PATH, tmp.name) + except subprocess.CalledProcessError: + # If the file is unretrievable for whatever reason, assume mismatch. + return False + + return filecmp.cmp(tmp.name, os.path.join(SDK_ROOT, '.hash'), False) + def __Discover(self, node_name): """Returns the IP address and port of a Fuchsia instance discovered on the local area network.""" @@ -75,9 +93,14 @@ node_name = boot_data.GetNodeName(self._output_dir) self._host = self.__Discover(node_name) if self._host and self._WaitUntilReady(retries=0): - logging.info('Connected to an already booted device.') - self._new_instance = False - return + if not self._SDKHashMatches(): + logging.info('SDK hash does not match, rebooting.') + self.RunCommand(['dm', 'reboot']) + self._started = False + else: + logging.info('Connected to an already booted device.') + self._new_instance = False + return logging.info('Netbooting Fuchsia. ' + 'Please ensure that your device is in bootloader mode.') @@ -122,6 +145,9 @@ self._WaitUntilReady(); + # Update the target's hash to match the current tree's. + self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH) + def IsNewInstance(self): return self._new_instance
diff --git a/cc/cc.gni b/cc/cc.gni index 51bbd51a..8539c01 100644 --- a/cc/cc.gni +++ b/cc/cc.gni
@@ -11,7 +11,7 @@ "//build/config/compiler:wexit_time_destructors", ] -if (!is_debug && (is_win || is_android)) { +if (!is_debug) { cc_remove_configs += [ "//build/config/compiler:default_optimization" ] cc_add_configs += [ "//build/config/compiler:optimize_max" ] }
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index a7d7f4ee..283e364 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -429,6 +429,8 @@ test_hooks_->BeginMainFrame(args); } + void RecordEndOfFrameMetrics(base::TimeTicks) override {} + void UpdateLayerTreeHost() override { test_hooks_->UpdateLayerTreeHost(); } void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta,
diff --git a/cc/test/stub_layer_tree_host_client.h b/cc/test/stub_layer_tree_host_client.h index 57d56ffc..fa24c0fa 100644 --- a/cc/test/stub_layer_tree_host_client.h +++ b/cc/test/stub_layer_tree_host_client.h
@@ -17,6 +17,7 @@ void WillBeginMainFrame() override {} void DidBeginMainFrame() override {} void BeginMainFrame(const viz::BeginFrameArgs& args) override {} + void RecordEndOfFrameMetrics(base::TimeTicks) override {} void BeginMainFrameNotExpectedSoon() override {} void BeginMainFrameNotExpectedUntil(base::TimeTicks time) override {} void UpdateLayerTreeHost() override {}
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 716021c..a18aa62 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -945,6 +945,10 @@ RecordWheelAndTouchScrollingCount(*info); } +void LayerTreeHost::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) { + client_->RecordEndOfFrameMetrics(frame_begin_time); +} + const base::WeakPtr<InputHandler>& LayerTreeHost::GetInputHandler() const { return input_handler_weak_ptr_;
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h index 3531699..d2cd6ed 100644 --- a/cc/trees/layer_tree_host.h +++ b/cc/trees/layer_tree_host.h
@@ -536,6 +536,7 @@ // Called when the compositor completed page scale animation. void DidCompletePageScaleAnimation(); void ApplyScrollAndScale(ScrollAndScaleSet* info); + void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time); LayerTreeHostClient* client() { return client_; }
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h index 8950d17b..302521d 100644 --- a/cc/trees/layer_tree_host_client.h +++ b/cc/trees/layer_tree_host_client.h
@@ -89,6 +89,9 @@ virtual void DidPresentCompositorFrame( uint32_t frame_token, const gfx::PresentationFeedback& feedback) = 0; + // Record UMA and UKM metrics that require the time from the start of + // BeginMainFrame to the Commit, or early out. + virtual void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) = 0; protected: virtual ~LayerTreeHostClient() {}
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc index c84c480f..c89bd779 100644 --- a/cc/trees/proxy_main.cc +++ b/cc/trees/proxy_main.cc
@@ -228,6 +228,7 @@ if (skip_commit) { TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit_InsideBeginMainFrame", TRACE_EVENT_SCOPE_THREAD); + layer_tree_host_->RecordEndOfFrameMetrics(begin_main_frame_start_time); std::vector<std::unique_ptr<SwapPromise>> empty_swap_promises; ImplThreadTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&ProxyImpl::BeginMainFrameAbortedOnImpl, @@ -274,6 +275,7 @@ current_pipeline_stage_ = COMMIT_PIPELINE_STAGE; if (final_pipeline_stage_ < COMMIT_PIPELINE_STAGE) { TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD); + layer_tree_host_->RecordEndOfFrameMetrics(begin_main_frame_start_time); std::vector<std::unique_ptr<SwapPromise>> swap_promises = layer_tree_host_->GetSwapPromiseManager()->TakeSwapPromises(); ImplThreadTaskRunner()->PostTask( @@ -308,6 +310,7 @@ // coordinated by the Scheduler. { TRACE_EVENT0("cc", "ProxyMain::BeginMainFrame::commit"); + layer_tree_host_->RecordEndOfFrameMetrics(begin_main_frame_start_time); DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 3cad880..ff156841 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2236,8 +2236,8 @@ } if (!ChromeFeatureList.isInitialized() - || !ChromeFeatureList.isEnabled( - ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)) { + || (!ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID) + && !DeviceClassManager.enableAccessibilityLayout())) { super.setStatusBarColor(tab, ApiCompatibilityUtils.getColor(getResources(), R.color.modern_primary_color)); return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NavigationBarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/NavigationBarColorController.java index 60af248..99db394c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/NavigationBarColorController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/NavigationBarColorController.java
@@ -18,6 +18,7 @@ import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver; import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver; +import org.chromium.chrome.browser.device.DeviceClassManager; import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; @@ -120,7 +121,8 @@ boolean overviewVisible = mOverviewModeBehavior.overviewVisible() && !mOverviewModeHiding; boolean useLightNavigation; - if (ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)) { + if (ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID) + || DeviceClassManager.enableAccessibilityLayout()) { useLightNavigation = !mTabModelSelector.isIncognitoSelected(); } else { useLightNavigation = !mTabModelSelector.isIncognitoSelected() || overviewVisible;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java index 6d1b70f..4ab8ab9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -98,6 +98,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; import org.chromium.chrome.browser.tabmodel.TabReparentingParams; import org.chromium.chrome.browser.toolbar.ToolbarControlContainer; +import org.chromium.chrome.browser.toolbar.ToolbarManager; import org.chromium.chrome.browser.util.ColorUtils; import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.chrome.browser.util.UrlUtilities; @@ -793,6 +794,8 @@ mTabObserverRegistrar.registerPageLoadMetricsObserver( new FirstMeaningfulPaintObserver(mTabObserver, tab)); + initalizePreviewsObserver(); + // Immediately add the observer to PageLoadMetrics to catch early events that may // be generated in the middle of tab initialization. mTabObserverRegistrar.addObserversForTab(tab); @@ -805,6 +808,67 @@ prepareTabBackground(tab); } + private void initalizePreviewsObserver() { + mTabObserverRegistrar.registerTabObserver(new EmptyTabObserver() { + /** Keeps track of the original color before the preview was shown. */ + private int mOriginalColor; + + /** True if a change to the toolbar color was made because of a preview. */ + private boolean mTriggeredPreviewChange; + + @Override + public void onPageLoadFinished(Tab tab) { + // Update the color when the page load finishes. + updateColor(tab); + } + + @Override + public void didReloadLoFiImages(Tab tab) { + // Update the color when the LoFi preview is reloaded. + updateColor(tab); + } + + @Override + public void onUrlUpdated(Tab tab) { + // Update the color on every new URL. + updateColor(tab); + } + + /** + * Updates the color of the Activity's status bar and the CCT Toolbar. When a preview is + * shown, it should be reset to the default color. If the user later navigates away from + * that preview to a non-preview page, reset the color back to the original. This does + * not interfere with site-specific theme colors which are disabled when a preview is + * being shown. + */ + private void updateColor(Tab tab) { + final ToolbarManager manager = getToolbarManager(); + // Record the original toolbar color in case we need to revert back to it later + // after a preview has been shown then the user navigates to another non-preview + // page. + if (mOriginalColor == 0) mOriginalColor = manager.getPrimaryColor(); + + final boolean shouldUpdateOriginal = manager.getShouldUpdateToolbarPrimaryColor(); + manager.setShouldUpdateToolbarPrimaryColor(true); + + if (tab.isPreview()) { + final int defaultColor = ColorUtils.getDefaultThemeColor(getResources(), false); + manager.updatePrimaryColor(defaultColor, false); + setStatusBarColor(defaultColor, false); + mTriggeredPreviewChange = true; + } else if (mOriginalColor != manager.getPrimaryColor() && mTriggeredPreviewChange) { + manager.updatePrimaryColor(mOriginalColor, false); + setStatusBarColor(mOriginalColor, false); + + mTriggeredPreviewChange = false; + mOriginalColor = 0; + } + + manager.setShouldUpdateToolbarPrimaryColor(shouldUpdateOriginal); + } + }); + } + @Override public void initializeCompositor() { super.initializeCompositor();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java index e98ed46..f7f06217 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.explore_sites; +import android.graphics.Bitmap; + import org.chromium.base.Callback; import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.browser.profiles.Profile; @@ -29,6 +31,10 @@ nativeGetEspCatalog(profile, result, callback); } + public static void getSiteImage(Profile profile, int siteID, Callback<Bitmap> callback) { + nativeGetIcon(profile, siteID, callback); + } + /** * Causes a network request for updating the catalog. */ @@ -48,4 +54,7 @@ static native int nativeGetVariation(); private static native void nativeGetEspCatalog(Profile profile, List<ExploreSitesCategory> result, Callback<List<ExploreSitesCategory>> callback); + + private static native void nativeGetIcon( + Profile profile, int siteID, Callback<Bitmap> callback); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/TasksUma.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/TasksUma.java index 099666a..dac3592 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/TasksUma.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/TasksUma.java
@@ -45,7 +45,7 @@ } } - recordStatistic(tabInGroupsCount, tabGroupCount, model.getCount()); + recordParentChildrenTabStatistic(tabInGroupsCount, tabGroupCount, model.getCount()); } private static int getTabsInOneGroupCount( @@ -62,17 +62,31 @@ private static void getTabsRelationship( TabModel model, Map<Integer, List<Integer>> tabsRelationList) { + int duplicatedTabCount = 0; + Map<String, Integer> uniqueUrlCounterMap = new HashMap<>(); + for (int i = 0; i < model.getCount(); i++) { Tab currentTab = model.getTabAt(i); + + String url = currentTab.getUrl(); + int urlDuplicatedCount = 0; + if (uniqueUrlCounterMap.containsKey(url)) { + duplicatedTabCount++; + urlDuplicatedCount = uniqueUrlCounterMap.get(url); + } + uniqueUrlCounterMap.put(url, urlDuplicatedCount + 1); + int parentIdOfCurrentTab = currentTab.getParentId(); if (!tabsRelationList.containsKey(parentIdOfCurrentTab)) { tabsRelationList.put(parentIdOfCurrentTab, new ArrayList<>()); } tabsRelationList.get(parentIdOfCurrentTab).add(currentTab.getId()); } + + recordDuplicatedTabStatistic(duplicatedTabCount, model.getCount()); } - private static void recordStatistic( + private static void recordParentChildrenTabStatistic( int tabsInGroupCount, int tabGroupCount, int totalTabCount) { if (totalTabCount == 0) return; @@ -101,4 +115,15 @@ Log.d(TAG, "TabsInGroupRatioPercent: %d", (int) tabsInGroupRatioPercent); Log.d(TAG, "TabGroupDensityPercent: %d", (int) tabGroupDensityPercent); } + + private static void recordDuplicatedTabStatistic(int duplicatedTabCount, int totalTabCount) { + if (totalTabCount == 0 || duplicatedTabCount >= totalTabCount) return; + + RecordHistogram.recordCountHistogram( + "Tabs.Tasks.DuplicatedTab.DuplicatedTabCount", duplicatedTabCount); + + int duplicatedTabRatioPercent = 100 * duplicatedTabCount / totalTabCount; + RecordHistogram.recordPercentageHistogram( + "Tabs.Tasks.DuplicatedTab.DuplicatedTabRatio", duplicatedTabRatioPercent); + } }
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 0019d5b5..4f901ab 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
@@ -1408,6 +1408,14 @@ } /** + * @return Whether we should be updating the toolbar primary color based on updates from the + * Tab. + */ + public boolean getShouldUpdateToolbarPrimaryColor() { + return mShouldUpdateToolbarPrimaryColor; + } + + /** * @return The primary toolbar color. */ public int getPrimaryColor() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java index a2a27c0..01930f8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java
@@ -109,27 +109,24 @@ mStandardButtonIcon = new TintedImageView(getContext()); mStandardButtonIcon.setImageResource(R.drawable.btn_normal_tabs); mStandardButtonIcon.setScaleY(-1.0f); + mStandardButtonIcon.setContentDescription( + getResources().getString(R.string.accessibility_tab_switcher_standard_stack)); mIncognitoButtonIcon = new TintedImageView(getContext()); mIncognitoButtonIcon.setImageResource(R.drawable.btn_incognito_tabs); mIncognitoButtonIcon.setScaleY(-1.0f); + mIncognitoButtonIcon.setContentDescription(getResources().getString( + ChromeFeatureList.isEnabled(ChromeFeatureList.INCOGNITO_STRINGS) + ? R.string.accessibility_tab_switcher_private_stack + : R.string.accessibility_tab_switcher_incognito_stack)); setDividerDrawable(null); ((ListView) findViewById(R.id.list_view)).setDivider(null); mLayout = findViewById(R.id.tab_wrapper); mStackButtonWrapper = findViewById(R.id.tab_layout); - mStandardButton = - mStackButtonWrapper.newTab() - .setCustomView(mStandardButtonIcon) - .setContentDescription(R.string.accessibility_tab_switcher_standard_stack); + mStandardButton = mStackButtonWrapper.newTab().setCustomView(mStandardButtonIcon); mStackButtonWrapper.addTab(mStandardButton); - mIncognitoButton = - mStackButtonWrapper.newTab() - .setCustomView(mIncognitoButtonIcon) - .setContentDescription( - ChromeFeatureList.isEnabled(ChromeFeatureList.INCOGNITO_STRINGS) - ? R.string.accessibility_tab_switcher_private_stack - : R.string.accessibility_tab_switcher_incognito_stack); + mIncognitoButton = mStackButtonWrapper.newTab().setCustomView(mIncognitoButtonIcon); mStackButtonWrapper.addTab(mIncognitoButton); mStackButtonWrapper.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 49e9cf3..2a7994f 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -4078,7 +4078,7 @@ <message name="IDS_EXTENSION_WEB_STORE_TITLE" desc="Text for the Chrome Web Store"> Chrome Web Store </message> - <message name="IDS_EXTENSION_WEB_STORE_TITLE_SHORT" desc="Text for the Chrome Web Store"> + <message name="IDS_EXTENSION_WEB_STORE_TITLE_SHORT" desc="Shortened version of text for the Chrome Web Store"> Web Store </message> <message name="IDS_EXTENSIONS_SHOW_DETAILS" desc="Tooltip for the button next to an extension that shows more details">
diff --git a/chrome/app/nibs/BUILD.gn b/chrome/app/nibs/BUILD.gn index 44e41aa..84880c6 100644 --- a/chrome/app/nibs/BUILD.gn +++ b/chrome/app/nibs/BUILD.gn
@@ -10,7 +10,6 @@ translated_xibs = [ "SaveAccessoryView.xib", "TaskManager.xib", - "Toolbar.xib", ] mac_xib_bundle_data("chrome_xibs") {
diff --git a/chrome/app/nibs/Toolbar.xib b/chrome/app/nibs/Toolbar.xib deleted file mode 100644 index bc6c940..0000000 --- a/chrome/app/nibs/Toolbar.xib +++ /dev/null
@@ -1,104 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13F1077" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> - <dependencies> - <deployment version="1090" identifier="macosx"/> - <development version="5100" identifier="xcode"/> - <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/> - </dependencies> - <objects> - <customObject id="-2" userLabel="File's Owner" customClass="ToolbarController"> - <connections> - <outlet property="backButton_" destination="2" id="17"/> - <outlet property="browserActionsContainerView_" destination="144" id="154"/> - <outlet property="forwardButton_" destination="7" id="18"/> - <outlet property="homeButton_" destination="8" id="35"/> - <outlet property="locationBar_" destination="4" id="31"/> - <outlet property="reloadButton_" destination="3" id="19"/> - <outlet property="view" destination="1" id="22"/> - <outlet property="appMenuButton_" destination="38" id="41"/> - </connections> - </customObject> - <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> - <customObject id="-3" userLabel="Application"/> - <customView id="1" customClass="ToolbarViewCocoa"> - <rect key="frame" x="0.0" y="0.0" width="604" height="35"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> - <subviews> - <button toolTip="^IDS_APPMENU_TOOLTIP" id="38" customClass="MenuButton"> - <rect key="frame" x="572" y="4" width="29" height="29"/> - <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" borderStyle="border" inset="2" id="39" customClass="AppToolbarButtonCell"> - <behavior key="behavior" lightByContents="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - </button> - <button toolTip="^IDS_TOOLTIP_BACK" tag="33000" id="2" customClass="MenuButton"> - <rect key="frame" x="3" y="4" width="29" height="29"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" state="on" borderStyle="border" inset="2" id="15" customClass="ClickHoldButtonCell"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <action selector="commandDispatchUsingKeyModifiers:" target="-1" id="138"/> - </connections> - </button> - <button toolTip="^IDS_TOOLTIP_FORWARD" tag="33001" id="7" customClass="MenuButton"> - <rect key="frame" x="31" y="4" width="29" height="29"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" state="on" borderStyle="border" inset="2" id="10" customClass="ClickHoldButtonCell"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <action selector="commandDispatchUsingKeyModifiers:" target="-1" id="139"/> - </connections> - </button> - <button toolTip="^IDS_TOOLTIP_RELOAD" tag="33002" id="3" customClass="ReloadButtonCocoa"> - <rect key="frame" x="59" y="4" width="29" height="29"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" borderStyle="border" inset="2" id="14" customClass="ClickHoldButtonCell"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <action selector="commandDispatchUsingKeyModifiers:" target="-1" id="26"/> - </connections> - </button> - <button toolTip="^IDS_TOOLTIP_HOME" tag="33003" id="8" customClass="ToolbarButtonCocoa"> - <rect key="frame" x="87" y="4" width="29" height="29"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" borderStyle="border" inset="2" id="9" customClass="ClickHoldButtonCell"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <action selector="commandDispatchUsingKeyModifiers:" target="-1" id="155"/> - </connections> - </button> - <textField focusRingType="exterior" verticalHuggingPriority="750" tag="33004" id="4"> - <rect key="frame" x="119" y="4" width="454" height="29"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="exterior" alignment="left" drawsBackground="YES" id="13"> - <font key="font" metaFont="system"/> - <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> - </textFieldCell> - <connections> - <action selector="commandDispatch:" target="-1" id="24"/> - </connections> - </textField> - <customView hidden="YES" id="144" userLabel="Browser Actions Container"> - <rect key="frame" x="572" y="4" width="0.0" height="29"/> - <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/> - </customView> - </subviews> - </customView> - <customObject id="122" customClass="ChromeUILocalizer"> - <connections> - <outlet property="owner_" destination="-2" id="123"/> - </connections> - </customObject> - <userDefaultsController representsSharedInstance="YES" id="130"/> - </objects> -</document>
diff --git a/chrome/browser/android/explore_sites/explore_sites_bridge.cc b/chrome/browser/android/explore_sites/explore_sites_bridge.cc index 7da43f5..1861e62 100644 --- a/chrome/browser/android/explore_sites/explore_sites_bridge.cc +++ b/chrome/browser/android/explore_sites/explore_sites_bridge.cc
@@ -18,6 +18,7 @@ #include "jni/ExploreSitesBridge_jni.h" #include "jni/ExploreSitesCategory_jni.h" #include "jni/ExploreSitesSite_jni.h" +#include "ui/gfx/android/java_bitmap.h" namespace explore_sites { using base::android::ConvertUTF8ToJavaString; @@ -51,6 +52,19 @@ base::android::RunObjectCallbackAndroid(j_callback_obj, j_result_obj); } +void ImageReady(ScopedJavaGlobalRef<jobject>(j_callback_obj), + std::unique_ptr<SkBitmap> bitmap) { + if (!bitmap) { + DVLOG(1) << "Site icon is empty."; + base::android::RunObjectCallbackAndroid(j_callback_obj, nullptr); + return; + } + + ScopedJavaLocalRef<jobject> j_bitmap = gfx::ConvertToJavaBitmap(bitmap.get()); + + base::android::RunObjectCallbackAndroid(j_callback_obj, j_bitmap); +} + } // namespace // static @@ -83,4 +97,27 @@ chrome::android::explore_sites::GetExploreSitesVariation()); } +// static +void JNI_ExploreSitesBridge_GetIcon( + JNIEnv* env, + const JavaParamRef<jclass>& j_caller, + const JavaParamRef<jobject>& j_profile, + const jint j_site_id, + const JavaParamRef<jobject>& j_callback_obj) { + Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); + DCHECK(profile); + + ExploreSitesService* service = + ExploreSitesServiceFactory::GetForBrowserContext(profile); + if (!service) { + DLOG(ERROR) << "Unable to create the ExploreSitesService!"; + base::android::RunObjectCallbackAndroid(j_callback_obj, nullptr); + return; + } + int site_id = static_cast<int>(j_site_id); + + service->GetSiteImage( + site_id, base::BindOnce(&ImageReady, + ScopedJavaGlobalRef<jobject>(j_callback_obj))); +} } // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl.cc b/chrome/browser/android/explore_sites/explore_sites_service_impl.cc index 06daed0..fc17f08 100644 --- a/chrome/browser/android/explore_sites/explore_sites_service_impl.cc +++ b/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/android/explore_sites/explore_sites_service_impl.h" +#include "base/task/post_task.h" #include "chrome/browser/android/explore_sites/catalog.pb.h" #include "chrome/browser/android/explore_sites/explore_sites_feature.h" #include "chrome/browser/android/explore_sites/explore_sites_store.h" @@ -11,6 +12,12 @@ #include "chrome/browser/android/explore_sites/get_images_task.h" #include "chrome/browser/android/explore_sites/import_catalog_task.h" #include "components/offline_pages/task/task.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/common/service_manager_connection.h" +#include "services/data_decoder/public/cpp/decode_image.h" +#include "services/service_manager/public/cpp/connector.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/geometry/size.h" using chrome::android::explore_sites::ExploreSitesVariation; using chrome::android::explore_sites::GetExploreSitesVariation; @@ -20,12 +27,6 @@ const int kFaviconsPerCategoryImage = 4; } -void DecodeImageBytes(BitmapCallback callback, EncodedImageList images) { - // TODO(freedjm): implement image decode. - NOTIMPLEMENTED(); - std::move(callback).Run(nullptr); -} - ExploreSitesServiceImpl::ExploreSitesServiceImpl( std::unique_ptr<ExploreSitesStore> store) : task_queue_(this), explore_sites_store_(std::move(store)) {} @@ -49,7 +50,8 @@ BitmapCallback callback) { task_queue_.AddTask(std::make_unique<GetImagesTask>( explore_sites_store_.get(), category_id, kFaviconsPerCategoryImage, - base::BindOnce(&DecodeImageBytes, std::move(callback)))); + base::BindOnce(&ExploreSitesServiceImpl::DecodeImageBytes, + std::move(callback)))); // TODO(dewittj, freedjm): implement. std::move(callback).Run(nullptr); } @@ -58,7 +60,8 @@ BitmapCallback callback) { task_queue_.AddTask(std::make_unique<GetImagesTask>( explore_sites_store_.get(), site_id, - base::BindOnce(&DecodeImageBytes, std::move(callback)))); + base::BindOnce(&ExploreSitesServiceImpl::DecodeImageBytes, + std::move(callback)))); } void ExploreSitesServiceImpl::Shutdown() {} @@ -75,4 +78,32 @@ explore_sites_store_.get(), version_token, std::move(catalog_proto))); } +// static +void ExploreSitesServiceImpl::OnDecodeDone(BitmapCallback callback, + const SkBitmap& decoded_image) { + std::unique_ptr<SkBitmap> bitmap = std::make_unique<SkBitmap>(decoded_image); + std::move(callback).Run(std::move(bitmap)); +} + +// static +void ExploreSitesServiceImpl::DecodeImageBytes(BitmapCallback callback, + EncodedImageList images) { + // TODO(freedjm) Fix to handle multiple images when support is added for + // creating composite images for the NTP tiles. + DCHECK(images.size() > 0); + std::unique_ptr<EncodedImageBytes> image_data = std::move(images[0]); + + service_manager::mojom::ConnectorRequest connector_request; + std::unique_ptr<service_manager::Connector> connector = + service_manager::Connector::Create(&connector_request); + content::ServiceManagerConnection::GetForProcess() + ->GetConnector() + ->BindConnectorRequest(std::move(connector_request)); + + data_decoder::DecodeImage(connector.get(), *image_data, + data_decoder::mojom::ImageCodec::DEFAULT, false, + data_decoder::kDefaultMaxSizeInBytes, gfx::Size(), + base::BindOnce(&OnDecodeDone, std::move(callback))); +} + } // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl.h b/chrome/browser/android/explore_sites/explore_sites_service_impl.h index 003f5256..827de0c 100644 --- a/chrome/browser/android/explore_sites/explore_sites_service_impl.h +++ b/chrome/browser/android/explore_sites/explore_sites_service_impl.h
@@ -41,6 +41,11 @@ void AddUpdatedCatalog(std::string version_token, std::unique_ptr<Catalog> catalog_proto); + static void OnDecodeDone(BitmapCallback callback, + const SkBitmap& decoded_image); + static void DecodeImageBytes(BitmapCallback callback, + EncodedImageList images); + // True when Chrome starts up, this is reset after the catalog is requested // the first time in Chrome. This prevents the ESP from changing out from // under a viewer.
diff --git a/chrome/browser/autofill/risk_util.cc b/chrome/browser/autofill/risk_util.cc index 75db7b3..c9a271b9 100644 --- a/chrome/browser/autofill/risk_util.cc +++ b/chrome/browser/autofill/risk_util.cc
@@ -38,12 +38,12 @@ namespace { -void PassRiskData(const base::Callback<void(const std::string&)>& callback, +void PassRiskData(base::OnceCallback<void(const std::string&)> callback, std::unique_ptr<risk::Fingerprint> fingerprint) { std::string proto_data, risk_data; fingerprint->SerializeToString(&proto_data); base::Base64Encode(proto_data, &risk_data); - callback.Run(risk_data); + std::move(callback).Run(risk_data); } #if !defined(OS_ANDROID) @@ -66,10 +66,9 @@ } // namespace -void LoadRiskData( - uint64_t obfuscated_gaia_id, - content::WebContents* web_contents, - const base::RepeatingCallback<void(const std::string&)>& callback) { +void LoadRiskData(uint64_t obfuscated_gaia_id, + content::WebContents* web_contents, + base::OnceCallback<void(const std::string&)> callback) { // No easy way to get window bounds on Android, and that signal isn't very // useful anyway (given that we're also including the bounds of the web // contents). @@ -96,7 +95,7 @@ obfuscated_gaia_id, window_bounds, web_contents, version_info::GetVersionNumber(), charset, accept_languages, install_time, g_browser_process->GetApplicationLocale(), GetUserAgent(), - base::Bind(PassRiskData, callback), connector); + base::BindOnce(PassRiskData, std::move(callback)), connector); } } // namespace autofill
diff --git a/chrome/browser/autofill/risk_util.h b/chrome/browser/autofill/risk_util.h index 32d38c0..e462a38 100644 --- a/chrome/browser/autofill/risk_util.h +++ b/chrome/browser/autofill/risk_util.h
@@ -22,10 +22,9 @@ // process if provided. |web_contents| is used during fingerprinting as well, // when retrieving user prefs, and in determining window bounds when not on // Android. -void LoadRiskData( - uint64_t obfuscated_gaia_id, - content::WebContents* web_contents, - const base::RepeatingCallback<void(const std::string&)>& callback); +void LoadRiskData(uint64_t obfuscated_gaia_id, + content::WebContents* web_contents, + base::OnceCallback<void(const std::string&)> callback); } // namespace autofill
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 288ee38..011d8bb 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1586,6 +1586,12 @@ "power/auto_screen_brightness/fake_als_reader.h", "power/auto_screen_brightness/fake_brightness_monitor.cc", "power/auto_screen_brightness/fake_brightness_monitor.h", + "power/auto_screen_brightness/modeller.h", + "power/auto_screen_brightness/modeller_impl.cc", + "power/auto_screen_brightness/modeller_impl.h", + "power/auto_screen_brightness/trainer.h", + "power/auto_screen_brightness/utils.cc", + "power/auto_screen_brightness/utils.h", "power/cpu_data_collector.cc", "power/cpu_data_collector.h", "power/extension_event_observer.cc", @@ -2260,6 +2266,8 @@ "policy/weekly_time/weekly_time_unittest.cc", "power/auto_screen_brightness/als_reader_impl_unittest.cc", "power/auto_screen_brightness/brightness_monitor_impl_unittest.cc", + "power/auto_screen_brightness/modeller_impl_unittest.cc", + "power/auto_screen_brightness/utils_unittest.cc", "power/cpu_data_collector_unittest.cc", "power/extension_event_observer_unittest.cc", "power/ml/adaptive_screen_brightness_manager_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc index 9d247972..d5b85cb 100644 --- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc +++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
@@ -632,6 +632,11 @@ class_name); } + if (!GetProperty(node, AXBooleanProperty::IMPORTANCE)) { + out_data->role = ax::mojom::Role::kIgnored; + return; + } + if (GetProperty(node, AXBooleanProperty::EDITABLE)) { out_data->role = ax::mojom::Role::kTextField; return;
diff --git a/chrome/browser/chromeos/events/event_rewriter_unittest.cc b/chrome/browser/chromeos/events/event_rewriter_unittest.cc index a37e246..7f190b7 100644 --- a/chrome/browser/chromeos/events/event_rewriter_unittest.cc +++ b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
@@ -310,8 +310,7 @@ ui::INPUT_DEVICE_INTERNAL); rewriter_->KeyboardDeviceAddedForTesting( kKeyboardDeviceId + 1, "External Keyboard", - ui::EventRewriterChromeOS::kKbdTopRowLayoutDefault, - ui::INPUT_DEVICE_EXTERNAL); + ui::EventRewriterChromeOS::kKbdTopRowLayoutDefault, ui::INPUT_DEVICE_USB); // The Meta key on both external and internal keyboards should produce Search.
diff --git a/chrome/browser/chromeos/input_method/accessibility.cc b/chrome/browser/chromeos/input_method/accessibility.cc index 2df2614..992dbe43 100644 --- a/chrome/browser/chromeos/input_method/accessibility.cc +++ b/chrome/browser/chromeos/input_method/accessibility.cc
@@ -37,7 +37,7 @@ const std::string medium_name = base::UTF16ToUTF8( imm_->GetInputMethodUtil()->GetInputMethodMediumName(descriptor)); - AutomationManagerAura::GetInstance()->HandleAlert(profile, medium_name); + AutomationManagerAura::GetInstance()->HandleAlert(medium_name); } } // namespace input_method
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc index a0b95bb81..6f5c64b 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.cc +++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -1528,8 +1528,7 @@ void ExistingUserController::SendAccessibilityAlert( const std::string& alert_text) { - AutomationManagerAura::GetInstance()->HandleAlert( - ProfileHelper::GetSigninProfile(), alert_text); + AutomationManagerAura::GetInstance()->HandleAlert(alert_text); } void ExistingUserController::SetPublicSessionKeyboardLayoutAndLogin(
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc index f7c64bd4..38962535 100644 --- a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc +++ b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
@@ -34,6 +34,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/test/ui_controls.h" +#include "ui/base/ui_base_features.h" #include "ui/compositor/layer_animator.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/views/widget/widget.h" @@ -150,6 +151,11 @@ }; IN_PROC_BROWSER_TEST_F(WebUiScreenLockerTest, TestBasic) { + // WebUiScreenLockerTest fails with Mash because of unexpected window + // structure. Fortunately we will deprecate the WebUI-based screen locker + // soon, so it is okay to skip it. See https://crbug.com/888779 + if (features::IsUsingWindowService()) + return; ScreenLocker::Show(); std::unique_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester()); tester->EmulateWindowManagerReady(); @@ -199,6 +205,11 @@ // Test how locking the screen affects an active fullscreen window. IN_PROC_BROWSER_TEST_F(WebUiScreenLockerTest, TestFullscreenExit) { + // WebUiScreenLockerTest fails with Mash because of unexpected window + // structure. Fortunately we will deprecate the WebUI-based screen locker + // soon, so it is okay to skip it. See https://crbug.com/888779 + if (features::IsUsingWindowService()) + return; // 1) If the active browser window is in fullscreen and the fullscreen window // does not have all the pixels (e.g. the shelf is auto hidden instead of // hidden), locking the screen should not exit fullscreen. The shelf is
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h b/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h index d5f8b1f..cd3e54b 100644 --- a/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h +++ b/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h
@@ -32,9 +32,10 @@ static constexpr int kMaxInitialAttempts = 20; // Interval for polling ambient light values. - // TODO(jiameng): revise frequency. + // TODO(jiameng): currently poll ALS samples every 250ms. May revise. + static constexpr int kNumberAlsPollPerSeconds = 4; static constexpr base::TimeDelta kAlsPollInterval = - base::TimeDelta::FromSeconds(1); + base::TimeDelta::FromSecondsD(1.0 / kNumberAlsPollPerSeconds); AlsReaderImpl(); ~AlsReaderImpl() override;
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller.h b/chrome/browser/chromeos/power/auto_screen_brightness/modeller.h new file mode 100644 index 0000000..b61fada1 --- /dev/null +++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller.h
@@ -0,0 +1,59 @@ +// 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_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_H_ +#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_H_ + +#include "base/observer_list_types.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h" + +namespace chromeos { +namespace power { +namespace auto_screen_brightness { + +// Interface to on-device adaptive model. +class Modeller { + public: + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + enum class Status { + kInitializing = 0, + kDisabled = 1, + kGlobal = 2, + kPersonal = 3, + kMaxValue = kPersonal + }; + + // Modeller must outlive its observers. + class Observer : public base::CheckedObserver { + public: + Observer() = default; + ~Observer() override = default; + + // Called when a new curve (|brightness_curve|) is trained. + virtual void OnModelTrained(const BrightnessCurve& brightness_curve) = 0; + + // Called when the model is initialized. Observers will be notified about + // both model status and initial curve (|brightness_curve|). If model status + // is |kDisabled|, the |brightness_curve| will be empty. + virtual void OnModelInitialized( + Status model_status, + const BrightnessCurve& brightness_curve) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Observer); + }; + + virtual ~Modeller() = default; + + // Adds or removes an observer. + virtual void AddObserver(Observer* observer) = 0; + virtual void RemoveObserver(Observer* observer) = 0; +}; + +} // namespace auto_screen_brightness +} // namespace power +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_H_
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc new file mode 100644 index 0000000..071bac68 --- /dev/null +++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
@@ -0,0 +1,341 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h" + +#include <cmath> + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/important_file_writer.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/task/post_task.h" +#include "base/task_runner_util.h" +#include "base/time/default_tick_clock.h" +#include "base/time/time.h" +#include "content/public/browser/browser_thread.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" + +namespace chromeos { +namespace power { +namespace auto_screen_brightness { + +namespace { +// Loads data from a specified location on disk. This should run in another +// thread to be non-blocking to the main thread (if |is_testing| is false). +std::string LoadDataFromDisk(const base::FilePath& path, bool is_testing) { + DCHECK(is_testing || + !content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (!PathExists(path)) { + return ""; + } + + std::string content; + if (!base::ReadFileToString(path, &content)) { + return ""; + } + return content; +} + +// Saves data to disk. This should run in another thread to be non-blocking to +// the main thread (if |is_testing| is false). +// TODO(jiameng): alternative to WriteFile is WriteFileAtomically, but the +// latter is very slow. Investigate whether we need to change to +// WriteFileAtomically. +void SaveCurveToDisk(const base::FilePath& path, + const BrightnessCurve& curve, + bool is_testing) { + DCHECK(is_testing || + !content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + const std::string data = CurveToString(curve); + const int bytes_written = base::WriteFile(path, data.data(), data.size()); + if (bytes_written != static_cast<int>(data.size())) { + LOG(ERROR) << "Wrote " << bytes_written << " byte(s) instead of " + << data.size() << " to " << path.value(); + } +} + +// Trains a new curve using the current |curve| and training |data|. Returns the +// new curve. This should run in another thread to be non-blocking to the main +// thread (if |is_testing| is false). +BrightnessCurve TrainModel(Trainer* trainer, + const BrightnessCurve& curve, + const std::vector<TrainingDataPoint>& data, + bool is_testing) { + DCHECK(is_testing || + !content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + return trainer->Train(curve, data); +} + +} // namespace + +constexpr base::TimeDelta ModellerImpl::kTrainingDelay; +constexpr int ModellerImpl::kMaxTrainingDataPoints; +constexpr int ModellerImpl::kAmbientLightHorizonSeconds; +constexpr base::TimeDelta ModellerImpl::kAmbientLightHorizon; +constexpr int ModellerImpl::kNumberAmbientValuesToTrack; +constexpr char ModellerImpl::kModelDir[]; +constexpr char ModellerImpl::kCurveFileName[]; + +ModellerImpl::ModellerImpl(Profile* profile, + AlsReader* als_reader, + BrightnessMonitor* brightness_monitor, + ui::UserActivityDetector* user_activity_detector, + std::unique_ptr<Trainer> trainer) + : ModellerImpl(profile, + als_reader, + brightness_monitor, + user_activity_detector, + std::move(trainer), + base::CreateSequencedTaskRunnerWithTraits( + {base::TaskPriority::BEST_EFFORT, base::MayBlock(), + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}), + base::DefaultTickClock::GetInstance()) {} + +ModellerImpl::~ModellerImpl() = default; + +void ModellerImpl::AddObserver(Modeller::Observer* observer) { + DCHECK(observer); + observers_.AddObserver(observer); + if (model_status_ != Modeller::Status::kInitializing) { + observer->OnModelInitialized(model_status_, curve_); + } +} + +void ModellerImpl::RemoveObserver(Modeller::Observer* observer) { + DCHECK(observer); + observers_.RemoveObserver(observer); +} + +void ModellerImpl::OnAmbientLightUpdated(int lux) { + if (model_status_ == Status::kDisabled) + return; + + const AmbientLightSample sample = {lux, tick_clock_->NowTicks()}; + ambient_light_values_.SaveToBuffer(sample); +} + +void ModellerImpl::OnAlsReaderInitialized(AlsReader::AlsInitStatus status) { + if (als_init_status_.has_value()) + return; + + als_init_status_ = status; + + HandleStatusUpdate(); +} + +void ModellerImpl::OnBrightnessMonitorInitialized(bool success) { + if (brightness_monitor_success_.has_value()) + return; + + brightness_monitor_success_ = success; + HandleStatusUpdate(); +} + +void ModellerImpl::OnUserBrightnessChanged(double old_brightness_percent, + double new_brightness_percent) { + if (model_status_ == Status::kDisabled) + return; + + // We don't add any training data if there is no ambient light sample. + if (ambient_light_values_.CurrentIndex() == 0) + return; + + const double average_ambient_lux = AverageAmbient(ambient_light_values_, -1); + data_cache_.push_back({old_brightness_percent, new_brightness_percent, + average_ambient_lux, tick_clock_->NowTicks()}); + + if (data_cache_.size() == kMaxTrainingDataPoints) { + model_timer_.Stop(); + StartTraining(); + } +} + +void ModellerImpl::OnUserBrightnessChangeRequested() {} + +void ModellerImpl::OnUserActivity(const ui::Event* event) { + if (!event) + return; + ScheduleTrainerStart(); +} + +std::unique_ptr<ModellerImpl> ModellerImpl::CreateForTesting( + Profile* profile, + AlsReader* als_reader, + BrightnessMonitor* brightness_monitor, + ui::UserActivityDetector* user_activity_detector, + std::unique_ptr<Trainer> trainer, + scoped_refptr<base::SequencedTaskRunner> task_runner, + const base::TickClock* tick_clock) { + return base::WrapUnique(new ModellerImpl( + profile, als_reader, brightness_monitor, user_activity_detector, + std::move(trainer), task_runner, tick_clock, true /* is_testing */)); +} + +double ModellerImpl::AverageAmbientForTesting() const { + return AverageAmbient(ambient_light_values_, -1); +} + +int ModellerImpl::NumberTrainingDataPointsForTesting() const { + return data_cache_.size(); +} + +base::FilePath ModellerImpl::GetCurvePathForTesting(Profile* profile) const { + return GetCurvePathFromProfile(profile); +} + +ModellerImpl::ModellerImpl( + Profile* profile, + AlsReader* als_reader, + BrightnessMonitor* brightness_monitor, + ui::UserActivityDetector* user_activity_detector, + std::unique_ptr<Trainer> trainer, + const scoped_refptr<base::SequencedTaskRunner> task_runner, + const base::TickClock* tick_clock, + bool is_testing) + : is_testing_(is_testing), + als_reader_observer_(this), + brightness_monitor_observer_(this), + user_activity_observer_(this), + model_task_runner_(task_runner), + trainer_(trainer.release(), + base::OnTaskRunnerDeleter(model_task_runner_)), + tick_clock_(tick_clock), + model_timer_(tick_clock_), + weak_ptr_factory_(this) { + DCHECK(als_reader); + DCHECK(brightness_monitor); + DCHECK(trainer_); + DCHECK(user_activity_detector); + + if (!profile) { + model_status_ = Status::kDisabled; + return; + } + + curve_path_ = GetCurvePathFromProfile(profile); + if (curve_path_.empty()) { + model_status_ = Status::kDisabled; + return; + } + + model_timer_.SetTaskRunner(model_task_runner_); + + als_reader_observer_.Add(als_reader); + brightness_monitor_observer_.Add(brightness_monitor); + user_activity_observer_.Add(user_activity_detector); +} + +base::FilePath ModellerImpl::GetCurvePathFromProfile(Profile* profile) const { + DCHECK(profile); + const base::FilePath empty_path; + + const base::FilePath profile_path = profile->GetPath(); + if (profile_path.empty()) { + return empty_path; + } + + const base::FilePath model_dir = profile_path.Append(kModelDir); + if (!base::DirectoryExists(model_dir) && !base::CreateDirectory(model_dir)) { + return empty_path; + } + + return model_dir.Append(kCurveFileName); +} + +void ModellerImpl::HandleStatusUpdate() { + if (model_status_ != Modeller::Status::kInitializing) + return; + + if (!als_init_status_.has_value()) { + return; + } + const bool als_success = + als_init_status_.value() == AlsReader::AlsInitStatus::kSuccess; + if (!als_success) { + model_status_ = Modeller::Status::kDisabled; + OnInitializationComplete(); + return; + } + + if (!brightness_monitor_success_.has_value()) { + return; + } + if (!brightness_monitor_success_.value()) { + model_status_ = Modeller::Status::kDisabled; + OnInitializationComplete(); + return; + } + + base::PostTaskAndReplyWithResult( + model_task_runner_.get(), FROM_HERE, + base::BindOnce(&LoadDataFromDisk, curve_path_, is_testing_), + base::BindOnce(&ModellerImpl::OnCurveLoadedFromDisk, + weak_ptr_factory_.GetWeakPtr())); +} + +void ModellerImpl::OnInitializationComplete() { + DCHECK_NE(model_status_, Status::kInitializing); + for (auto& observer : observers_) + observer.OnModelInitialized(model_status_, curve_); +} + +// TODO(crbug.com/881215): add actual default curve and then add unit test too. +void ModellerImpl::InitWithDefaultCurve() { + curve_.clear(); + return; +} + +void ModellerImpl::OnCurveLoadedFromDisk(const std::string& content) { + if (content.empty() || !CurveFromString(content, &curve_)) { + InitWithDefaultCurve(); + model_status_ = Status::kGlobal; + } else { + model_status_ = Status::kPersonal; + } + + OnInitializationComplete(); + + ScheduleTrainerStart(); +} + +void ModellerImpl::ScheduleTrainerStart() { + // Reset the timer if it's already running. + model_timer_.Start(FROM_HERE, kTrainingDelay, this, + &ModellerImpl::StartTraining); +} + +void ModellerImpl::StartTraining() { + if (data_cache_.empty()) { + ScheduleTrainerStart(); + return; + } + + base::PostTaskAndReplyWithResult( + model_task_runner_.get(), FROM_HERE, + base::BindOnce(&TrainModel, trainer_.get(), curve_, + std::move(data_cache_), is_testing_), + base::BindOnce(&ModellerImpl::OnTrainingFinished, + weak_ptr_factory_.GetWeakPtr())); + data_cache_.clear(); +} + +void ModellerImpl::OnTrainingFinished(const BrightnessCurve& curve) { + curve_ = curve; + for (auto& observer : observers_) + observer.OnModelTrained(curve); + + model_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&SaveCurveToDisk, curve_path_, curve_, is_testing_)); + ScheduleTrainerStart(); +} + +} // namespace auto_screen_brightness +} // namespace power +} // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h new file mode 100644 index 0000000..50d3a16 --- /dev/null +++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h
@@ -0,0 +1,204 @@ +// 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_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_ +#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_ + +#include <memory> + +#include "base/containers/ring_buffer.h" +#include "base/macros.h" +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/optional.h" +#include "base/scoped_observer.h" +#include "base/sequenced_task_runner.h" +#include "base/time/time.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/modeller.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h" +#include "chrome/browser/profiles/profile.h" +#include "ui/base/user_activity/user_activity_detector.h" +#include "ui/base/user_activity/user_activity_observer.h" + +namespace chromeos { +namespace power { +namespace auto_screen_brightness { + +// Real implementation of Modeller. +// It monitors user-requested brightness changes, ambient light values and +// trains personal brightness curves when user remains idle for a period of +// time. +class ModellerImpl : public Modeller, + public AlsReader::Observer, + public BrightnessMonitor::Observer, + public ui::UserActivityObserver { + public: + // Once user remains idle for |kTrainingDelay|, we start training the model. + static constexpr base::TimeDelta kTrainingDelay = + base::TimeDelta::FromSeconds(60); + + // If number of recorded training data has reached |kMaxTrainingDataPoints| we + // start training immediately, without waiting for user to become idle for + // |kTrainingDelay|. + static constexpr int kMaxTrainingDataPoints = 100; + + // TODO(jiameng): we currently use past 10 seconds of ambient values to + // calculate average. May revise. + static constexpr int kAmbientLightHorizonSeconds = 10; + static constexpr base::TimeDelta kAmbientLightHorizon = + base::TimeDelta::FromSeconds(kAmbientLightHorizonSeconds); + + // Size of |data_cache_|. + static constexpr int kNumberAmbientValuesToTrack = + kAmbientLightHorizonSeconds * AlsReaderImpl::kNumberAlsPollPerSeconds; + + static constexpr char kModelDir[] = "autobrightness"; + static constexpr char kCurveFileName[] = "curve"; + + // ModellerImpl has weak dependencies on all parameters except |trainer|. + ModellerImpl(Profile* profile, + AlsReader* als_reader, + BrightnessMonitor* brightness_monitor, + ui::UserActivityDetector* user_activity_detector, + std::unique_ptr<Trainer> trainer); + ~ModellerImpl() override; + + // Modeller overrides: + void AddObserver(Modeller::Observer* observer) override; + void RemoveObserver(Modeller::Observer* observer) override; + + // AlsReader::Observer overrides: + void OnAmbientLightUpdated(int lux) override; + void OnAlsReaderInitialized(AlsReader::AlsInitStatus status) override; + + // BrightnessMonitor::Observer overrides: + void OnBrightnessMonitorInitialized(bool success) override; + void OnUserBrightnessChanged(double old_brightness_percent, + double new_brightness_percent) override; + void OnUserBrightnessChangeRequested() override; + + // ui::UserActivityObserver overrides: + void OnUserActivity(const ui::Event* event) override; + + // ModellerImpl has weak dependencies on all parameters except |trainer|. + static std::unique_ptr<ModellerImpl> CreateForTesting( + Profile* profile, + AlsReader* als_reader, + BrightnessMonitor* brightness_monitor, + ui::UserActivityDetector* user_activity_detector, + std::unique_ptr<Trainer> trainer, + scoped_refptr<base::SequencedTaskRunner> task_runner, + const base::TickClock* tick_clock); + + // Current average ambient light. + double AverageAmbientForTesting() const; + + // Current number of training data points stored, which will be used for next + // training. + int NumberTrainingDataPointsForTesting() const; + + // Calls GetCurvePathFromProfile directly. + base::FilePath GetCurvePathForTesting(Profile* profile) const; + + private: + // ModellerImpl has weak dependencies on all parameters except |trainer|. + ModellerImpl(Profile* profile, + AlsReader* als_reader, + BrightnessMonitor* brightness_monitor, + ui::UserActivityDetector* user_activity_detector, + std::unique_ptr<Trainer> trainer, + scoped_refptr<base::SequencedTaskRunner> task_runner, + const base::TickClock* tick_clock, + bool is_testing = false); + + // Returns the path that will be used to store curves. It also creates + // intermediate directories if they do not exist. Returns an empty path on + // failures. + base::FilePath GetCurvePathFromProfile(Profile* profile) const; + + // Updates |model_status_| by checking |als_init_status_| and + // |brightness_monitor_status_| and optionally loads a curve. + // 1. |model_status_| is |kDisabled| if either |als_init_status_| is not + // |kSuccess|, or |brightness_monitor_success_| is false. The modeller will + // notify its observers as soon as |model_status_| is |kDisabled|. + // 2. If |als_init_status_| is |kSuccess| and |brightness_monitor_success_| is + // true, then this method loads a curve from the disk and sets |model_status_| + // to |kPersonal|. If no curve is found from the disk a default curve will be + // created and |model_status_| is set to |kGlobal|. All observers will be + // notified about the status and the curve. + void HandleStatusUpdate(); + + // Notifies its observers on the status of the model. It will be called either + // when HandleStatusUpdate is called and |model_status_| is no longer + // |kInitializing|, or when an observer is added to the modeller, and + // |model_status_| is not |kInitializing|. + void OnInitializationComplete(); + + // Called when there is no saved curve from the disk. + void InitWithDefaultCurve(); + + // Called after reading from disk is complete. |content| may be empty, in that + // case we'll construct a default curve. + void OnCurveLoadedFromDisk(const std::string& content); + + // Starts |model_timer_| to start training after certain inactivity period. + void ScheduleTrainerStart(); + + // Starts model training and runs it in non UI thread. Also clears + // |data_cache_|. + void StartTraining(); + + // Called after training is complete with a new curve. + void OnTrainingFinished(const BrightnessCurve& curve); + + // If |is_testing_| is false, we check curve saving/loading and training jobs + // are running on non-UI thread. + const bool is_testing_ = false; + + ScopedObserver<AlsReader, AlsReader::Observer> als_reader_observer_; + + ScopedObserver<BrightnessMonitor, BrightnessMonitor::Observer> + brightness_monitor_observer_; + + ScopedObserver<ui::UserActivityDetector, ui::UserActivityObserver> + user_activity_observer_; + + scoped_refptr<base::SequencedTaskRunner> model_task_runner_; + std::unique_ptr<Trainer, base::OnTaskRunnerDeleter> trainer_; + + // This will be replaced by a mock tick clock during tests. + const base::TickClock* const tick_clock_; + + base::OneShotTimer model_timer_; + + base::Optional<AlsReader::AlsInitStatus> als_init_status_; + base::Optional<bool> brightness_monitor_success_; + Status model_status_ = Status::kInitializing; + + base::FilePath curve_path_; + + // Latest trained curve. + BrightnessCurve curve_; + + // Recent |kNumberAmbientValuesToTrack| ambient values. + base::RingBuffer<AmbientLightSample, kNumberAmbientValuesToTrack> + ambient_light_values_; + + std::vector<TrainingDataPoint> data_cache_; + + base::ObserverList<Modeller::Observer> observers_; + + base::WeakPtrFactory<ModellerImpl> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ModellerImpl); +}; + +} // namespace auto_screen_brightness +} // namespace power +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_MODELLER_IMPL_H_
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc new file mode 100644 index 0000000..b84454c --- /dev/null +++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
@@ -0,0 +1,391 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h" + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/important_file_writer.h" +#include "base/files/scoped_temp_dir.h" +#include "base/strings/string_number_conversions.h" +#include "base/test/scoped_task_environment.h" +#include "base/test/test_mock_time_task_runner.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/fake_als_reader.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/fake_brightness_monitor.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.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 "ui/base/user_activity/user_activity_detector.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" + +namespace chromeos { +namespace power { +namespace auto_screen_brightness { + +namespace { + +void CompareBrightnessCurve(const BrightnessCurve& expected, + const BrightnessCurve& actual) { + EXPECT_EQ(expected.size(), actual.size()); + for (size_t i = 0; i < expected.size(); ++i) { + EXPECT_DOUBLE_EQ(expected[i].first, actual[i].first); + EXPECT_DOUBLE_EQ(expected[i].second, actual[i].second); + } +} + +std::pair<double, double> DataToCurvePoint(const TrainingDataPoint& data) { + return std::make_pair(data.ambient_lux, + (data.brightness_old + data.brightness_new) / 2); +} + +// Testing trainer. +class FakeTrainer : public Trainer { + public: + FakeTrainer() = default; + ~FakeTrainer() override = default; + + // Trainer overrides: + BrightnessCurve Train(const BrightnessCurve& /* curve */, + const std::vector<TrainingDataPoint>& data) override { + BrightnessCurve result_curve; + for (const auto& training_data_point : data) { + result_curve.push_back(DataToCurvePoint(training_data_point)); + } + return result_curve; + } + + private: + DISALLOW_COPY_AND_ASSIGN(FakeTrainer); +}; + +class TestObserver : public Modeller::Observer { + public: + TestObserver() {} + ~TestObserver() override = default; + + // Modeller::Observer overrides: + void OnModelTrained(const BrightnessCurve& brightness_curve) override { + brightness_curve_ = base::Optional<BrightnessCurve>(brightness_curve); + } + + void OnModelInitialized(const Modeller::Status model_status, + const BrightnessCurve& brightness_curve) override { + model_status_ = base::Optional<Modeller::Status>(model_status); + brightness_curve_ = base::Optional<BrightnessCurve>(brightness_curve); + } + + Modeller::Status model_status() const { + DCHECK(model_status_.has_value()); + return model_status_.value(); + } + + BrightnessCurve brightness_curve() const { + DCHECK(brightness_curve_.has_value()); + return brightness_curve_.value(); + } + + bool HasModelStatus() { return model_status_.has_value(); } + bool HasBrightnessCurve() { return brightness_curve_.has_value(); } + + private: + base::Optional<Modeller::Status> model_status_; + base::Optional<BrightnessCurve> brightness_curve_; + + DISALLOW_COPY_AND_ASSIGN(TestObserver); +}; + +} // namespace + +class ModellerImplTest : public testing::Test { + public: + ModellerImplTest() + : scoped_task_environment_( + base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME), + thread_bundle_(content::TestBrowserThreadBundle::PLAIN_MAINLOOP) { + CHECK(temp_dir_.CreateUniqueTempDir()); + TestingProfile::Builder profile_builder; + profile_builder.SetProfileName("testuser@gmail.com"); + profile_builder.SetPath(temp_dir_.GetPath().AppendASCII("TestProfile")); + profile_ = profile_builder.Build(); + } + + ~ModellerImplTest() override { + base::TaskScheduler::GetInstance()->FlushForTesting(); + } + + void SetUpModeller() { + modeller_ = ModellerImpl::CreateForTesting( + profile_.get(), &fake_als_reader_, &fake_brightness_monitor_, + &user_activity_detector_, std::make_unique<FakeTrainer>(), + base::SequencedTaskRunnerHandle::Get(), + scoped_task_environment_.GetMockTickClock()); + + test_observer_ = std::make_unique<TestObserver>(); + modeller_->AddObserver(test_observer_.get()); + } + + protected: + void WriteCurveToFile(const BrightnessCurve& curve) { + const base::FilePath curve_path = + modeller_->GetCurvePathForTesting(profile_.get()); + CHECK(!curve_path.empty()); + + const std::string& data = CurveToString(curve); + const int bytes_written = + base::WriteFile(curve_path, data.data(), data.size()); + ASSERT_EQ(bytes_written, static_cast<int>(data.size())) + << "Wrote " << bytes_written << " byte(s) instead of " << data.size() + << " to " << curve_path; + } + + base::test::ScopedTaskEnvironment scoped_task_environment_; + content::TestBrowserThreadBundle thread_bundle_; + + ui::UserActivityDetector user_activity_detector_; + + base::ScopedTempDir temp_dir_; + std::unique_ptr<TestingProfile> profile_; + + FakeAlsReader fake_als_reader_; + FakeBrightnessMonitor fake_brightness_monitor_; + + std::unique_ptr<ModellerImpl> modeller_; + std::unique_ptr<TestObserver> test_observer_; + + private: + DISALLOW_COPY_AND_ASSIGN(ModellerImplTest); +}; + +// AlsReader is |kDisabled| when Modeller is created. +TEST_F(ModellerImplTest, AlsReaderDisabledOnInit) { + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kDisabled); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status()); +} + +// BrightnessMonitor is |kDisabled| when Modeller is created. +TEST_F(ModellerImplTest, BrightnessMonitorDisabledOnInit) { + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kDisabled); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status()); +} + +// AlsReader is |kDisabled| on later notification. +TEST_F(ModellerImplTest, AlsReaderDisabledOnNotification) { + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kInProgress); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + EXPECT_FALSE(test_observer_->HasModelStatus()); + EXPECT_FALSE(test_observer_->HasBrightnessCurve()); + + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kDisabled); + fake_als_reader_.ReportReaderInitialized(); + EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status()); +} + +// AlsReader is |kSuccess| on later notification. +TEST_F(ModellerImplTest, AlsReaderEnabledOnNotification) { + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kInProgress); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + EXPECT_FALSE(test_observer_->HasModelStatus()); + EXPECT_FALSE(test_observer_->HasBrightnessCurve()); + + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess); + fake_als_reader_.ReportReaderInitialized(); + scoped_task_environment_.RunUntilIdle(); + EXPECT_EQ(Modeller::Status::kGlobal, test_observer_->model_status()); + EXPECT_TRUE(test_observer_->brightness_curve().empty()); +} + +// BrightnessMonitor is |kDisabled| on later notification. +TEST_F(ModellerImplTest, BrightnessMonitorDisabledOnNotification) { + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kInitializing); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + EXPECT_FALSE(test_observer_->HasModelStatus()); + EXPECT_FALSE(test_observer_->HasBrightnessCurve()); + + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kDisabled); + fake_brightness_monitor_.ReportBrightnessMonitorInitialized(); + EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status()); +} + +// BrightnessMonitor is |kSuccess| on later notification. +TEST_F(ModellerImplTest, BrightnessMonitorEnabledOnNotification) { + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kInitializing); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + EXPECT_FALSE(test_observer_->HasModelStatus()); + EXPECT_FALSE(test_observer_->HasBrightnessCurve()); + + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess); + fake_brightness_monitor_.ReportBrightnessMonitorInitialized(); + scoped_task_environment_.RunUntilIdle(); + EXPECT_EQ(Modeller::Status::kGlobal, test_observer_->model_status()); + EXPECT_TRUE(test_observer_->brightness_curve().empty()); +} + +// There is no saved curve, hence a global curve is created. +TEST_F(ModellerImplTest, NoSavedCurve) { + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + EXPECT_EQ(Modeller::Status::kGlobal, test_observer_->model_status()); + EXPECT_TRUE(test_observer_->brightness_curve().empty()); +} + +// A curve is loaded from disk, this is a personal curve. +TEST_F(ModellerImplTest, CurveLoadedFromProfilePath) { + const BrightnessCurve curve = {{10, 15}, {20, 25}, {30, 35}, {40, 45}, + {50, 55}, {60, 65}, {70, 75}, {80, 85}}; + WriteCurveToFile(curve); + + scoped_task_environment_.RunUntilIdle(); + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + + EXPECT_EQ(Modeller::Status::kPersonal, test_observer_->model_status()); + EXPECT_EQ(curve, test_observer_->brightness_curve()); +} + +// Ambient light values are received. We check average ambient light has been +// calculated from the past |kNumberAmbientValuesToTrack| samples only. +TEST_F(ModellerImplTest, OnAmbientLightUpdated) { + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + ASSERT_EQ(Modeller::Status::kGlobal, test_observer_->model_status()); + + const int first_lux = 1000; + double running_sum = first_lux; + fake_als_reader_.ReportAmbientLightUpdate(first_lux); + for (int i = 1; i < ModellerImpl::kNumberAmbientValuesToTrack; ++i) { + const int lux = i; + fake_als_reader_.ReportAmbientLightUpdate(lux); + running_sum += lux; + EXPECT_DOUBLE_EQ(running_sum / (i + 1), + modeller_->AverageAmbientForTesting()); + } + + // Add another one should push the oldest |first_lux| out of the horizon. + fake_als_reader_.ReportAmbientLightUpdate(100); + running_sum = running_sum + 100 - first_lux; + EXPECT_DOUBLE_EQ(running_sum / ModellerImpl::kNumberAmbientValuesToTrack, + modeller_->AverageAmbientForTesting()); +} + +// User brightness changes are received, training example cache reaches +// |kMaxTrainingDataPoints| to trigger early training. This all happens within a +// small window shorter than |kTrainingDelay|. +TEST_F(ModellerImplTest, OnUserBrightnessChanged) { + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + ASSERT_EQ(Modeller::Status::kGlobal, test_observer_->model_status()); + + std::vector<TrainingDataPoint> expected_data; + for (int i = 0; i < ModellerImpl::kMaxTrainingDataPoints - 1; ++i) { + EXPECT_EQ(i, modeller_->NumberTrainingDataPointsForTesting()); + scoped_task_environment_.FastForwardBy( + base::TimeDelta::FromMilliseconds(1)); + const base::TimeTicks now = + scoped_task_environment_.GetMockTickClock()->NowTicks(); + const int lux = i * 20; + fake_als_reader_.ReportAmbientLightUpdate(lux); + const double brightness_old = 10.0 + i; + const double brightness_new = 20.0 + i; + modeller_->OnUserBrightnessChanged(brightness_old, brightness_new); + expected_data.push_back({brightness_old, brightness_new, + modeller_->AverageAmbientForTesting(), now}); + } + + // Training should not have started. + EXPECT_EQ(ModellerImpl::kMaxTrainingDataPoints - 1, + modeller_->NumberTrainingDataPointsForTesting()); + + // Add one more data point to trigger the training early. + scoped_task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1)); + const base::TimeTicks now = + scoped_task_environment_.GetMockTickClock()->NowTicks(); + const double brightness_old = 85; + const double brightness_new = 95; + modeller_->OnUserBrightnessChanged(brightness_old, brightness_new); + expected_data.push_back({brightness_old, brightness_new, + modeller_->AverageAmbientForTesting(), now}); + scoped_task_environment_.RunUntilIdle(); + + EXPECT_EQ(0, modeller_->NumberTrainingDataPointsForTesting()); + const BrightnessCurve result_curve = test_observer_->brightness_curve(); + BrightnessCurve expected_curve; + for (auto& training_data_point : expected_data) { + expected_curve.push_back(DataToCurvePoint(training_data_point)); + } + CompareBrightnessCurve(expected_curve, result_curve); +} + +// User activities resets timer used to start training. +TEST_F(ModellerImplTest, MultipleUserActivities) { + fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess); + fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess); + SetUpModeller(); + scoped_task_environment_.RunUntilIdle(); + ASSERT_EQ(Modeller::Status::kGlobal, test_observer_->model_status()); + + fake_als_reader_.ReportAmbientLightUpdate(30); + modeller_->OnUserBrightnessChanged(10, 20); + const TrainingDataPoint expected_data = { + 10, 20, 30, scoped_task_environment_.GetMockTickClock()->NowTicks()}; + EXPECT_EQ(1, modeller_->NumberTrainingDataPointsForTesting()); + + scoped_task_environment_.FastForwardBy(ModellerImpl::kTrainingDelay - + base::TimeDelta::FromSeconds(10)); + // A user activity is received, timer should be reset. + const ui::MouseEvent mouse_event(ui::ET_MOUSE_EXITED, gfx::Point(0, 0), + gfx::Point(0, 0), base::TimeTicks(), 0, 0); + modeller_->OnUserActivity(&mouse_event); + + scoped_task_environment_.FastForwardBy(ModellerImpl::kTrainingDelay - + base::TimeDelta::FromSeconds(2)); + EXPECT_EQ(1, modeller_->NumberTrainingDataPointsForTesting()); + + // Another user event is received. + modeller_->OnUserActivity(&mouse_event); + + // After |kTrainingDelay| - 2 seconds, no training has started. + scoped_task_environment_.FastForwardBy(ModellerImpl::kTrainingDelay - + base::TimeDelta::FromSeconds(2)); + scoped_task_environment_.RunUntilIdle(); + EXPECT_EQ(1, modeller_->NumberTrainingDataPointsForTesting()); + + // After another 2 seconds, training is scheduled. + scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2)); + scoped_task_environment_.RunUntilIdle(); + + EXPECT_EQ(0, modeller_->NumberTrainingDataPointsForTesting()); + const BrightnessCurve result_curve = test_observer_->brightness_curve(); + BrightnessCurve expected_curve = {DataToCurvePoint(expected_data)}; + CompareBrightnessCurve(expected_curve, result_curve); +} + +} // namespace auto_screen_brightness +} // namespace power +} // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/trainer.h b/chrome/browser/chromeos/power/auto_screen_brightness/trainer.h new file mode 100644 index 0000000..0ed5c89 --- /dev/null +++ b/chrome/browser/chromeos/power/auto_screen_brightness/trainer.h
@@ -0,0 +1,36 @@ +// 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_POWER_AUTO_SCREEN_BRIGHTNESS_TRAINER_H_ +#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_TRAINER_H_ + +namespace chromeos { +namespace power { +namespace auto_screen_brightness { + +// It is a mapping from ambient light (in lux) to brightness percent. It should +// be sorted in the ascending order in lux. +using BrightnessCurve = std::vector<std::pair<double, double>>; + +struct TrainingDataPoint { + double brightness_old; + double brightness_new; + double ambient_lux; + base::TimeTicks sample_time; +}; + +// Interface to train an on-device adaptive brightness curve. +class Trainer { + public: + virtual ~Trainer() = default; + + virtual BrightnessCurve Train(const BrightnessCurve& curve, + const std::vector<TrainingDataPoint>& data) = 0; +}; + +} // namespace auto_screen_brightness +} // namespace power +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_TRAINER_H_
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/utils.cc b/chrome/browser/chromeos/power/auto_screen_brightness/utils.cc new file mode 100644 index 0000000..fc9b208 --- /dev/null +++ b/chrome/browser/chromeos/power/auto_screen_brightness/utils.cc
@@ -0,0 +1,64 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h" + +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" + +namespace chromeos { +namespace power { +namespace auto_screen_brightness { + +bool CurveFromString(const std::string& data, BrightnessCurve* const curve) { + DCHECK(curve); + curve->clear(); + if (data.empty()) + return true; + + base::StringPairs key_value_pairs; + if (!base::SplitStringIntoKeyValuePairs(data, ',', '\n', &key_value_pairs)) { + LOG(ERROR) << "Ill-formatted curve"; + return false; + } + + for (base::StringPairs::iterator it = key_value_pairs.begin(); + it != key_value_pairs.end(); ++it) { + double lux; + if (!base::StringToDouble(it->first, &lux)) { + LOG(ERROR) << "Ill-formatted lux"; + curve->clear(); + return false; + } + + double brightness; + if (!base::StringToDouble(it->second, &brightness)) { + LOG(ERROR) << "Ill-formatted brightness"; + curve->clear(); + return false; + } + + curve->push_back(std::make_pair(lux, brightness)); + } + return true; +} + +std::string CurveToString(const BrightnessCurve& curve) { + if (curve.empty()) + return ""; + + std::vector<std::string> rows; + for (const auto& kv : curve) { + rows.push_back(base::JoinString( + {base::NumberToString(kv.first), base::NumberToString(kv.second)}, + ",")); + } + + return base::JoinString(rows, "\n"); +} + +} // namespace auto_screen_brightness +} // namespace power +} // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/utils.h b/chrome/browser/chromeos/power/auto_screen_brightness/utils.h new file mode 100644 index 0000000..a5b6cbe --- /dev/null +++ b/chrome/browser/chromeos/power/auto_screen_brightness/utils.h
@@ -0,0 +1,67 @@ +// 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_POWER_AUTO_SCREEN_BRIGHTNESS_UTILS_H_ +#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_UTILS_H_ + +#include <string> +#include <vector> + +#include "base/containers/ring_buffer.h" +#include "base/time/time.h" +#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h" + +namespace chromeos { +namespace power { +namespace auto_screen_brightness { + +// Replaces |curve| with the parsed curve data from |data|, returning true if +// successful. Correct formatting in |data| should be 1 row per +// (<ambient_light>, <brightness>) mapping. Ambient light should be a double and +// brightness should be a double. +bool CurveFromString(const std::string& data, BrightnessCurve* const curve); + +// Converts |curve| to a string. An empty string will be returned if |curve| is +// empty. +std::string CurveToString(const BrightnessCurve& curve); + +struct AmbientLightSample { + int lux; + base::TimeTicks sample_time; +}; + +// Calculates average ambient light over the most recent |num_recent| samples. +// |num_recent| has to be no larger than the capacity of the buffer, but it can +// be greater than the number of samples stored. If |num_recent| is greater than +// the number of samples stored, it returns average of stored samples. If +// |num_recent| is negative, it returns average over all stored samples. If +// input |ambient_light_values| is empty, it returns 0. +// TODO(jiameng): this is the very basic version of averaging, we need to change +// it to allow for time decay. +template <size_t size> +double AverageAmbient( + const base::RingBuffer<AmbientLightSample, size>& ambient_light_values, + int num_recent) { + DCHECK_LE(num_recent, static_cast<int>(ambient_light_values.BufferSize())); + if (ambient_light_values.CurrentIndex() == 0) + return 0; + + double sum = 0; + int count = 0; + const int used_num_recent = + num_recent < 0 ? ambient_light_values.BufferSize() : num_recent; + for (auto it = ambient_light_values.End(); it && count < used_num_recent; + --it) { + const auto& ambient_sample = **it; + sum += ambient_sample.lux; + ++count; + } + return sum / count; +} + +} // namespace auto_screen_brightness +} // namespace power +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_UTILS_H_
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/utils_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/utils_unittest.cc new file mode 100644 index 0000000..4bf53ed --- /dev/null +++ b/chrome/browser/chromeos/power/auto_screen_brightness/utils_unittest.cc
@@ -0,0 +1,73 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h" + +#include <cmath> + +#include "base/logging.h" +#include "base/test/simple_test_tick_clock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chromeos { +namespace power { +namespace auto_screen_brightness { + +TEST(AverageAmbient, FullBufferTest) { + base::SimpleTestTickClock tick_clock; + base::RingBuffer<AmbientLightSample, 5> data; + for (int i = 0; i < 5; ++i) { + const AmbientLightSample sample = {i, tick_clock.NowTicks()}; + data.SaveToBuffer(sample); + } + + double sum = 0; + for (int i = 0; i < 5; ++i) { + const int num_recent = i + 1; + // Reverse order. + const int head_value = 4 - i; + sum += head_value; + const double expected = sum / num_recent; + EXPECT_DOUBLE_EQ(AverageAmbient(data, num_recent), expected); + } + + EXPECT_DOUBLE_EQ(AverageAmbient(data, -1), sum / 5); +} + +TEST(AverageAmbient, NonFullBufferTest) { + base::SimpleTestTickClock tick_clock; + base::RingBuffer<AmbientLightSample, 5> data; + for (int i = 0; i < 3; ++i) { + const AmbientLightSample sample = {i, tick_clock.NowTicks()}; + data.SaveToBuffer(sample); + } + + double sum = 0; + for (int i = 0; i < 3; ++i) { + const int num_recent = i + 1; + // Reverse order. + const int head_value = 2 - i; + sum += head_value; + const double expected = sum / num_recent; + EXPECT_DOUBLE_EQ(AverageAmbient(data, num_recent), expected); + } + + const double expected = sum / 3; + for (int i = 3; i < 5; ++i) { + const int num_recent = i + 1; + EXPECT_DOUBLE_EQ(AverageAmbient(data, num_recent), expected); + } + + EXPECT_DOUBLE_EQ(AverageAmbient(data, -1), expected); +} + +TEST(AverageAmbient, EmptyBufferTest) { + base::RingBuffer<AmbientLightSample, 5> data; + EXPECT_DOUBLE_EQ(AverageAmbient(data, 2), 0); + EXPECT_DOUBLE_EQ(AverageAmbient(data, -1), 0); +} + +} // namespace auto_screen_brightness +} // namespace power +} // namespace chromeos
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn b/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn index 5707ed8..b994829 100644 --- a/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn +++ b/chrome/browser/chromeos/power/ml/smart_dim/BUILD.gn
@@ -21,6 +21,7 @@ "//chrome/browser/chromeos:user_activity_event_proto", "//chrome/browser/chromeos/power/ml:user_activity_ukm_logger_helpers", "//chrome/common:constants", + "//chromeos:chromeos", "//components/assist_ranker", "//components/assist_ranker/proto", "//components/sessions",
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc b/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc index 0864cae..5704816 100644 --- a/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc +++ b/chrome/browser/chromeos/power/ml/smart_dim/model_impl.cc
@@ -17,8 +17,8 @@ #include "base/strings/string_number_conversions.h" #include "chrome/browser/chromeos/power/ml/smart_dim/tf_native_inference.h" #include "chrome/browser/chromeos/power/ml/user_activity_ukm_logger_helpers.h" -#include "chrome/common/chrome_features.h" #include "chrome/grit/browser_resources.h" +#include "chromeos/chromeos_features.h" #include "components/assist_ranker/example_preprocessing.h" #include "components/assist_ranker/proto/example_preprocessor.pb.h" #include "components/assist_ranker/proto/ranker_example.pb.h"
diff --git a/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc b/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc index 591b6172..224f0f60 100644 --- a/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc +++ b/chrome/browser/chromeos/power/ml/smart_dim/model_unittest.cc
@@ -11,7 +11,7 @@ #include "base/test/scoped_feature_list.h" #include "base/time/time.h" #include "chrome/browser/chromeos/power/ml/user_activity_event.pb.h" -#include "chrome/common/chrome_features.h" +#include "chromeos/chromeos_features.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/page_transition_types.h"
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager.cc b/chrome/browser/chromeos/power/ml/user_activity_manager.cc index cbff5fe8d..046745f 100644 --- a/chrome/browser/chromeos/power/ml/user_activity_manager.cc +++ b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
@@ -18,7 +18,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/common/chrome_features.h" +#include "chromeos/chromeos_features.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/power_manager/power_supply_properties.pb.h" #include "chromeos/system/devicetype.h"
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc b/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc index 8a01c45..8f7aad1 100644 --- a/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc +++ b/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
@@ -24,10 +24,10 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/tabs/tab_activity_simulator.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/common/chrome_features.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/test_browser_window_aura.h" #include "chrome/test/base/testing_profile.h" +#include "chromeos/chromeos_features.h" #include "chromeos/dbus/fake_power_manager_client.h" #include "chromeos/dbus/power_manager/idle.pb.h" #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc index f86480e..a3a28cc 100644 --- a/chrome/browser/extensions/api/automation/automation_apitest.cc +++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -218,7 +218,7 @@ } IN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopFocusViews) { - AutomationManagerAura::GetInstance()->Enable(browser()->profile()); + AutomationManagerAura::GetInstance()->Enable(); // Trigger the shelf subtree to be computed. ash::Shell::Get()->accelerator_controller()->PerformActionIfEnabled( ash::FOCUS_SHELF); @@ -248,7 +248,7 @@ #if defined(OS_CHROMEOS) IN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopActions) { - AutomationManagerAura::GetInstance()->Enable(browser()->profile()); + AutomationManagerAura::GetInstance()->Enable(); // Trigger the shelf subtree to be computed. ash::Shell::Get()->accelerator_controller()->PerformActionIfEnabled( ash::FOCUS_SHELF);
diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc index 8897086f..19d5c616 100644 --- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc +++ b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
@@ -544,7 +544,7 @@ AutomationEventRouter::GetInstance()->RegisterListenerWithDesktopPermission( extension_id(), source_process_id()); - AutomationManagerAura::GetInstance()->Enable(browser_context()); + AutomationManagerAura::GetInstance()->Enable(); return RespondNow(NoArguments()); #else return RespondNow(Error("getDesktop is unsupported by this platform"));
diff --git a/chrome/browser/history/top_sites_factory.cc b/chrome/browser/history/top_sites_factory.cc index 9daef8e..6fa7ee56 100644 --- a/chrome/browser/history/top_sites_factory.cc +++ b/chrome/browser/history/top_sites_factory.cc
@@ -60,9 +60,9 @@ // Android does not use prepopulated pages. const RawPrepopulatedPage kRawPrepopulatedPages[] = { { - IDS_WEBSTORE_URL, IDS_EXTENSION_WEB_STORE_TITLE, IDR_WEBSTORE_ICON_16, - IDR_WEBSTORE_ICON_32, IDR_NEWTAB_WEBSTORE_THUMBNAIL, - SkColorSetRGB(63, 132, 197), + IDS_WEBSTORE_URL, IDS_EXTENSION_WEB_STORE_TITLE_SHORT, + IDR_WEBSTORE_ICON_16, IDR_WEBSTORE_ICON_32, + IDR_NEWTAB_WEBSTORE_THUMBNAIL, SkColorSetRGB(63, 132, 197), }, }; #endif
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc index 3a1c1b3..65ddccc 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" #include "chrome/browser/profiles/profile.h" #include "components/metrics/net/network_metrics_provider.h" +#include "net/http/http_response_headers.h" #include "services/metrics/public/cpp/metrics_utils.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_recorder.h" @@ -61,6 +62,10 @@ UkmPageLoadMetricsObserver::ObservePolicy UkmPageLoadMetricsObserver::OnCommit( content::NavigationHandle* navigation_handle, ukm::SourceId source_id) { + const net::HttpResponseHeaders* response_headers = + navigation_handle->GetResponseHeaders(); + if (response_headers) + http_response_code_ = response_headers->response_code(); // The PageTransition for the navigation may be updated on commit. page_transition_ = navigation_handle->GetPageTransition(); return CONTINUE_OBSERVING; @@ -220,6 +225,10 @@ static_cast<int64_t>(proto_effective_connection_type)); } + if (http_response_code_) { + builder.SetNet_HttpResponseCode( + static_cast<int64_t>(http_response_code_.value())); + } if (http_rtt_estimate_) { builder.SetNet_HttpRttEstimate_OnNavigationStart( static_cast<int64_t>(http_rtt_estimate_.value().InMilliseconds()));
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h index e0c069a..b9698e33 100644 --- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
@@ -80,6 +80,7 @@ // Network quality estimates. net::EffectiveConnectionType effective_connection_type_ = net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN; + base::Optional<int32_t> http_response_code_; base::Optional<base::TimeDelta> http_rtt_estimate_; base::Optional<base::TimeDelta> transport_rtt_estimate_; base::Optional<int32_t> downstream_kbps_estimate_;
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 fd4c918..abdccd4 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
@@ -138,6 +138,8 @@ test_ukm_recorder().ExpectEntryMetric( kv.second.get(), PageLoad::kDocumentTiming_NavigationToLoadEventFiredName, 500); + test_ukm_recorder().ExpectEntryMetric( + kv.second.get(), PageLoad::kNet_HttpResponseCodeName, 200); EXPECT_FALSE(test_ukm_recorder().EntryHasMetric( kv.second.get(), PageLoad::
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc index 57e40d4..0c8febd9 100644 --- a/chrome/browser/previews/previews_lite_page_browsertest.cc +++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -127,7 +127,7 @@ {"previews_host", previews_server().spec()}, {"blacklisted_path_suffixes", ".mp4,.jpg"}, {"trigger_on_localhost", "true"}, - {"navigation_timeout_milliseconds", use_timeout ? "2000" : "0"}}; + {"navigation_timeout_milliseconds", use_timeout ? "250" : "0"}}; base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( "TrialName1", "GroupName1", feature_parameters); @@ -275,7 +275,7 @@ const net::test_server::HttpRequest& request) { std::unique_ptr<net::test_server::DelayedHttpResponse> response = std::make_unique<net::test_server::DelayedHttpResponse>( - base::TimeDelta::FromSeconds(3)); + base::TimeDelta::FromMilliseconds(500)); response->set_code(net::HttpStatusCode::HTTP_OK); return std::move(response); }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js index 206d6ac..d49e6cc 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
@@ -355,7 +355,7 @@ AutomationPredicate.structuralContainer = AutomationPredicate.roles([ Role.ALERT_DIALOG, Role.CLIENT, Role.DIALOG, Role.ROOT_WEB_AREA, Role.WEB_VIEW, Role.WINDOW, Role.EMBEDDED_OBJECT, Role.IFRAME, - Role.IFRAME_PRESENTATIONAL, Role.UNKNOWN + Role.IFRAME_PRESENTATIONAL, Role.IGNORED, Role.UNKNOWN ]); /**
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.js b/chrome/browser/resources/local_ntp/custom_links_edit.js index 308b165..276ffef 100644 --- a/chrome/browser/resources/local_ntp/custom_links_edit.js +++ b/chrome/browser/resources/local_ntp/custom_links_edit.js
@@ -121,19 +121,6 @@ /** - * Disables the "Done" button until the URL field is modified. - */ -function disableSubmitUntilTextInput() { - $(IDS.DONE).disabled = true; - let reenable = (event) => { - $(IDS.DONE).disabled = false; - $(IDS.URL_FIELD).removeEventListener('input', reenable); - }; - $(IDS.URL_FIELD).addEventListener('input', reenable); -} - - -/** * Shows the invalid URL error message until the URL field is modified. */ function showInvalidUrlUntilTextInput() { @@ -243,7 +230,7 @@ document.title = addLinkTitle; $(IDS.DIALOG_TITLE).textContent = addLinkTitle; $(IDS.DELETE).disabled = true; - disableSubmitUntilTextInput(); + $(IDS.DONE).disabled = true; // Set accessibility names. $(IDS.DONE).setAttribute('aria-label', addLinkTitle); $(IDS.DONE).title = addLinkTitle; @@ -352,6 +339,9 @@ .addEventListener('focusin', () => changeColor(IDS.URL_FIELD_NAME)); $(IDS.URL_FIELD) .addEventListener('blur', () => changeColor(IDS.URL_FIELD_NAME)); + // Disables the "Done" button when the URL field is empty. + $(IDS.URL_FIELD).addEventListener('input', + () => $(IDS.DONE).disabled = ($(IDS.URL_FIELD).value.trim() === '')); $(IDS.EDIT_DIALOG).showModal();
diff --git a/chrome/browser/resources/print_preview/new/pages_settings.html b/chrome/browser/resources/print_preview/new/pages_settings.html index b6ec296..76c90cca 100644 --- a/chrome/browser/resources/print_preview/new/pages_settings.html +++ b/chrome/browser/resources/print_preview/new/pages_settings.html
@@ -1,69 +1,71 @@ <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html"> <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html"> +<link rel="import" href="chrome://resources/html/md_select_css.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html"> <link rel="import" href="../data/document_info.html"> <link rel="import" href="../print_preview_utils.html"> <link rel="import" href="input_behavior.html"> <link rel="import" href="print_preview_shared_css.html"> +<link rel="import" href="select_behavior.html"> <link rel="import" href="settings_behavior.html"> <link rel="import" href="settings_section.html"> <link rel="import" href="strings.html"> <dom-module id="print-preview-pages-settings"> <template> - <style include="print-preview-shared"> + <style include="print-preview-shared md-select"> :host([error-state_='0']) #pageSettingsCustomInput { --cr-input-error-display: none; } - :host(:not([error-state_='0'])) #custom-radio-button { - /* Margin = -1 * error height = -1 * (16px + 2 lines * line-height) */ - --cr-radio-button-disc: { - margin-top: calc(-16px - 2 * .75rem); - }; + #pageSettingsCustomInput { + --cr-input-row-container: { + min-height: 38px; + } } /* Margin = standard margin (16px) - error field margin (8px) */ - :host(:not([error-state_='0'])) print-preview-settings-section { + :host(:not([error-state_='0'])) #customInputWrapper { margin-bottom: 8px; } #pageSettingsCustomInput { cursor: default; - height: 100%; + --cr-form-field-label-height: 100%; } </style> - <print-preview-settings-section - class="input-settings-section multirow-controls"> - <span slot="title">$i18n{pagesLabel}</span> - <div slot="controls" id="controls"> - <div class="radio"> - <cr-radio-button name="pages" id="all-radio-button" - checked$="[[!customSelected_]]" - disabled$="[[getDisabled_(disabled)]]" - on-click="onAllRadioClick_"> - <span>$i18n{optionAllPages}</span> - </cr-radio-button> - <cr-radio-button name="pages" id="custom-radio-button" - checked$="[[customSelected_]]" - disabled$="[[getDisabled_(disabled)]]" - aria-label="$i18n{optionCustomPages}" - on-click="onCustomRadioClick_" - on-focus="onCustomRadioFocus_" - on-blur="onCustomInputBlur_"> - <cr-input id="pageSettingsCustomInput" type="text" - data-timeout-delay="500" - disabled$="[[getDisabled_(disabled)]]" spellcheck="false" - on-focus="onCustomInputFocus_" on-blur="onCustomInputBlur_" - placeholder="$i18n{examplePageRangeText}" - error-message="[[getHintMessage_(errorState_, - documentInfo.pageCount)]]"> - </cr-input> - </cr-radio-button> - </div> + <print-preview-settings-section> + <span slot="title" id="pages-label">$i18n{pagesLabel}</span> + <div slot="controls"> + <select class="md-select" aria-labelledby="pages-label" + disabled$="[[getDisabled_(disabled)]]" + value="{{selectedValue::change}}" + on-blur="onSelectBlur_"> + <option value="[[pagesValueEnum_.ALL]]" selected> + $i18n{optionAllPages} + </option> + <option value="[[pagesValueEnum_.CUSTOM]]"> + $i18n{optionCustomPages} + </option> + </select> </div> </print-preview-settings-section> + <iron-collapse opened="[[customSelected_]]"> + <print-preview-settings-section id="customInputWrapper"> + <div slot="title"></div> + <div slot="controls"> + <cr-input id="pageSettingsCustomInput" type="text" + data-timeout-delay="500" + disabled$="[[getDisabled_(disabled)]]" spellcheck="false" + on-blur="onCustomInputBlur_" + placeholder="$i18n{examplePageRangeText}" + error-message="[[getHintMessage_(errorState_, + documentInfo.pageCount)]]"> + </cr-input> + </div> + </print-preview-settings-section> + </iron-collapse> </template> <script src="pages_settings.js"></script> </dom-module>
diff --git a/chrome/browser/resources/print_preview/new/pages_settings.js b/chrome/browser/resources/print_preview/new/pages_settings.js index 2db57211..9f12e46c 100644 --- a/chrome/browser/resources/print_preview/new/pages_settings.js +++ b/chrome/browser/resources/print_preview/new/pages_settings.js
@@ -12,10 +12,19 @@ OUT_OF_BOUNDS: 2, }; +/** @enum {number} */ +const PagesValue = { + ALL: 0, + CUSTOM: 1, +}; + Polymer({ is: 'print-preview-pages-settings', - behaviors: [SettingsBehavior, print_preview_new.InputBehavior], + behaviors: [ + SettingsBehavior, print_preview_new.InputBehavior, + print_preview_new.SelectBehavior + ], properties: { /** @type {!print_preview.DocumentInfo} */ @@ -33,14 +42,14 @@ computed: 'computeAllPagesArray_(documentInfo.pageCount)', }, + disabled: Boolean, + /** @private {boolean} */ customSelected_: { type: Boolean, value: false, }, - disabled: Boolean, - /** @private {number} */ errorState_: { type: Number, @@ -60,6 +69,15 @@ type: Array, computed: 'computeRangesToPrint_(pagesToPrint_, allPagesArray_)', }, + + /** + * Mirroring the enum so that it can be used from HTML bindings. + * @private + */ + pagesValueEnum_: { + type: Object, + value: PagesValue, + }, }, observers: [ @@ -71,6 +89,11 @@ 'input-change': 'onInputChange_', }, + // Initialize in attached() since this doesn't observe settings.pages. + attached: function() { + this.selectedValue = PagesValue.ALL.toString(); + }, + /** @return {!CrInputElement} The cr-input field element for InputBehavior. */ getInput: function() { return this.$.pageSettingsCustomInput; @@ -84,6 +107,14 @@ this.inputString_ = /** @type {string} */ (e.detail); }, + onProcessSelectChange: function(value) { + this.customSelected_ = value === PagesValue.CUSTOM.toString(); + if (this.customSelected_) { + /** @type {!CrInputElement} */ (this.$.pageSettingsCustomInput) + .inputElement.focus(); + } + }, + /** * @return {boolean} Whether the controls should be disabled. * Does not need to depend on |errorState_|, since |errorState_| is always @@ -274,28 +305,13 @@ }, /** @private */ - onAllRadioClick_: function() { - this.customSelected_ = false; - }, + onSelectBlur_: function(event) { + if (!this.customSelected_ || + event.relatedTarget === this.$.pageSettingsCustomInput) { + return; + } - /** - * @param {Event} event Contains information about where focus came from. - * @private - */ - onCustomRadioFocus_: function(event) { - if (event.relatedTarget !== this.$.pageSettingsCustomInput) - this.onCustomRadioClick_(); - }, - - /** @private */ - onCustomRadioClick_: function() { - /** @type {!CrInputElement} */ (this.$.pageSettingsCustomInput) - .inputElement.focus(); - }, - - /** @private */ - onCustomInputFocus_: function() { - this.customSelected_ = true; + this.onCustomInputBlur_(event); }, /** @@ -305,9 +321,11 @@ onCustomInputBlur_: function(event) { this.resetAndUpdate(); - if (this.inputString_.trim() == '' && - event.relatedTarget != this.$$('#custom-radio-button')) { + if (this.inputString_ === '' && + event.relatedTarget != this.$.customInputWrapper && + event.relatedTarget != this.$$('.md-select')) { this.customSelected_ = false; + this.selectedValue = PagesValue.ALL.toString(); } },
diff --git a/chrome/browser/resources/print_preview/new/print_preview_shared_css.html b/chrome/browser/resources/print_preview/new/print_preview_shared_css.html index c74e79ef..5e3de37 100644 --- a/chrome/browser/resources/print_preview/new/print_preview_shared_css.html +++ b/chrome/browser/resources/print_preview/new/print_preview_shared_css.html
@@ -15,7 +15,6 @@ margin-top: 3px; margin-bottom: 3px; }; - --cr-radio-button-size: 16px; --md-select-width: calc(100% - 17px); --print-preview-settings-border: 1px solid rgb(232, 234, 237); --print-preview-dialog-margin: 34px; @@ -24,8 +23,7 @@ } /* Default state ********************************************************/ - input[type='checkbox'], - input[type='radio'] { + input[type='checkbox'] { margin-bottom: 0; margin-inline-end: 1px; margin-inline-start: 0; @@ -48,13 +46,11 @@ user-select: none; } - .checkbox cr-checkbox, - .radio cr-radio-button { + .checkbox cr-checkbox { margin-bottom: 3px; margin-top: 3px; min-height: 32px; --cr-checkbox-ripple-size: 38px; - --cr-radio-button-ink-size: 38px; --cr-checkbox-label-container: { overflow: hidden; padding-inline-start: 15px;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 0d17497..4593c0c 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -81,14 +81,8 @@ "cocoa/chrome_browser_window.mm", "cocoa/chrome_event_processing_window.h", "cocoa/chrome_event_processing_window.mm", - "cocoa/clickhold_button_cell.h", - "cocoa/clickhold_button_cell.mm", "cocoa/cocoa_util.h", "cocoa/cocoa_util.mm", - "cocoa/constrained_window/constrained_window_alert.h", - "cocoa/constrained_window/constrained_window_alert.mm", - "cocoa/constrained_window/constrained_window_button.h", - "cocoa/constrained_window/constrained_window_button.mm", "cocoa/constrained_window/constrained_window_control_utils.h", "cocoa/constrained_window/constrained_window_control_utils.mm", "cocoa/constrained_window/constrained_window_custom_sheet.h", @@ -104,7 +98,6 @@ "cocoa/constrained_window/constrained_window_sheet_info.mm", "cocoa/constrained_window/constrained_window_web_dialog_sheet.h", "cocoa/constrained_window/constrained_window_web_dialog_sheet.mm", - "cocoa/create_native_web_modal_manager_cocoa.mm", "cocoa/drag_util.h", "cocoa/drag_util.mm", "cocoa/extensions/extension_keybinding_registry_cocoa.h", @@ -138,15 +131,11 @@ "cocoa/has_weak_browser_pointer.h", "cocoa/hover_close_button.h", "cocoa/hover_close_button.mm", - "cocoa/image_button_cell.h", - "cocoa/image_button_cell.mm", "cocoa/javascript_app_modal_dialog_cocoa.h", "cocoa/javascript_app_modal_dialog_cocoa.mm", "cocoa/location_bar/location_bar_view_mac.h", "cocoa/location_bar/location_bar_view_mac.mm", "cocoa/main_menu_item.h", - "cocoa/menu_button.h", - "cocoa/menu_button.mm", "cocoa/nsview_additions.h", "cocoa/nsview_additions.mm", "cocoa/rect_path_utils.h", @@ -199,20 +188,6 @@ "cocoa/tabs/tab_window_controller.mm", "cocoa/themed_window.h", "cocoa/themed_window.mm", - "cocoa/toolbar/app_toolbar_button.h", - "cocoa/toolbar/app_toolbar_button.mm", - "cocoa/toolbar/app_toolbar_button_cell.h", - "cocoa/toolbar/app_toolbar_button_cell.mm", - "cocoa/toolbar/back_forward_menu_controller.h", - "cocoa/toolbar/back_forward_menu_controller.mm", - "cocoa/toolbar/reload_button_cocoa.h", - "cocoa/toolbar/reload_button_cocoa.mm", - "cocoa/toolbar/toolbar_button_cocoa.h", - "cocoa/toolbar/toolbar_button_cocoa.mm", - "cocoa/toolbar/toolbar_controller.h", - "cocoa/toolbar/toolbar_controller.mm", - "cocoa/toolbar/toolbar_view_cocoa.h", - "cocoa/toolbar/toolbar_view_cocoa.mm", "cocoa/touchbar/credit_card_autofill_touch_bar_controller.h", "cocoa/touchbar/credit_card_autofill_touch_bar_controller.mm", "cocoa/touchbar/text_suggestions_touch_bar_controller.h", @@ -224,8 +199,6 @@ "cocoa/view_id_util.h", "cocoa/view_id_util.mm", "cocoa/view_resizer.h", - "cocoa/web_contents_modal_dialog_manager_views_mac.h", - "cocoa/web_contents_modal_dialog_manager_views_mac.mm", # TODO(estade): this class should be deleted in favor of a combobox model. # See crbug.com/590850 @@ -2236,7 +2209,6 @@ "//chrome/browser/apps/app_shim", "//extensions/components/native_app_window", "//third_party/google_toolbox_for_mac", - "//third_party/molokocacao", "//third_party/mozilla", "//ui/accelerated_widget_mac:accelerated_widget_mac", ] @@ -3038,8 +3010,6 @@ "views/frame/native_widget_mac_frameless_nswindow.mm", "views/policy/enterprise_startup_dialog_mac_util.h", "views/policy/enterprise_startup_dialog_mac_util.mm", - "views/relaunch_notification/get_app_menu_anchor_point.h", - "views/relaunch_notification/get_app_menu_anchor_point.mm", ] } else { sources += [
diff --git a/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc b/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc index 938b9c5..b7b8f33 100644 --- a/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc +++ b/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc
@@ -21,7 +21,7 @@ DCHECK(context); AutomationManagerAura* manager = AutomationManagerAura::GetInstance(); if (enabled) - manager->Enable(context); + manager->Enable(); else manager->Disable(); } @@ -85,7 +85,7 @@ if (msg) { AutomationManagerAura::GetInstance()->HandleAlert( - profile, l10n_util::GetStringUTF8(msg)); + l10n_util::GetStringUTF8(msg)); // After handling the alert, if the alert is screen-off, we should // disable automation manager to handle any following a11y events. if (alert == ash::mojom::AccessibilityAlert::SCREEN_OFF)
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc index 2d3eb06..df90b96 100644 --- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc +++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -8,13 +8,9 @@ #include "base/memory/singleton.h" #include "build/build_config.h" -#include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/automation_internal/automation_event_router.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/profiles/profiles_state.h" #include "chrome/common/extensions/chrome_extension_messages.h" #include "content/public/browser/ax_event_notification_details.h" -#include "content/public/browser/browser_context.h" #include "content/public/browser/render_frame_host.h" #include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_enum_util.h" @@ -32,62 +28,22 @@ #include "ash/shell.h" #include "ash/wm/window_util.h" #include "chrome/browser/chromeos/accessibility/ax_host_service.h" -#include "components/session_manager/core/session_manager.h" #include "ui/base/ui_base_features.h" #include "ui/views/widget/widget_delegate.h" #endif -using content::BrowserContext; using extensions::AutomationEventRouter; -namespace { - -// Returns default browser context for sending events in case it was not -// provided. This works around a crash in profile creation during OOBE when -// accessibility is enabled. https://crbug.com/738003 -BrowserContext* GetDefaultEventContext() { - ProfileManager* profile_manager = g_browser_process->profile_manager(); - if (!profile_manager) - return nullptr; - -#if defined(OS_CHROMEOS) - session_manager::SessionManager* session_manager = - session_manager::SessionManager::Get(); - // It is not guaranteed that user profile creation is completed for - // some session states. In this case use default profile. - const session_manager::SessionState session_state = - session_manager ? session_manager->session_state() - : session_manager::SessionState::UNKNOWN; - switch (session_state) { - case session_manager::SessionState::LOGGED_IN_NOT_ACTIVE: - case session_manager::SessionState::ACTIVE: - case session_manager::SessionState::LOCKED: - break; - case session_manager::SessionState::UNKNOWN: - case session_manager::SessionState::OOBE: - case session_manager::SessionState::LOGIN_PRIMARY: - case session_manager::SessionState::LOGIN_SECONDARY: - const base::FilePath defult_profile_dir = - profiles::GetDefaultProfileDir(profile_manager->user_data_dir()); - return profile_manager->GetProfileByPath(defult_profile_dir); - } -#endif - - return ProfileManager::GetLastUsedProfile(); -} - -} // namespace - // static AutomationManagerAura* AutomationManagerAura::GetInstance() { return base::Singleton<AutomationManagerAura>::get(); } -void AutomationManagerAura::Enable(BrowserContext* context) { +void AutomationManagerAura::Enable() { enabled_ = true; Reset(false); - SendEvent(context, current_tree_->GetRoot(), ax::mojom::Event::kLoadComplete); + SendEvent(current_tree_->GetRoot(), ax::mojom::Event::kLoadComplete); views::AXAuraObjCache::GetInstance()->SetDelegate(this); #if defined(OS_CHROMEOS) @@ -98,7 +54,7 @@ views::AXAuraObjWrapper* focus = views::AXAuraObjCache::GetInstance()->GetOrCreate(active_window); if (focus) - SendEvent(context, focus, ax::mojom::Event::kChildrenChanged); + SendEvent(focus, ax::mojom::Event::kChildrenChanged); } } // Gain access to out-of-process native windows. @@ -115,14 +71,13 @@ #endif } -void AutomationManagerAura::HandleEvent(BrowserContext* context, - views::View* view, +void AutomationManagerAura::HandleEvent(views::View* view, ax::mojom::Event event_type) { if (!enabled_) return; if (!view) { - SendEvent(nullptr, current_tree_->GetRoot(), event_type); + SendEvent(current_tree_->GetRoot(), event_type); return; } @@ -146,18 +101,17 @@ ax::mojom::Event event_type) { views::AXAuraObjWrapper* obj = views::AXAuraObjCache::GetInstance()->Get(id); if (obj) - SendEvent(nullptr, obj, event_type); + SendEvent(obj, event_type); } -void AutomationManagerAura::HandleAlert(content::BrowserContext* context, - const std::string& text) { +void AutomationManagerAura::HandleAlert(const std::string& text) { if (!enabled_) return; views::AXAuraObjWrapper* obj = static_cast<AXRootObjWrapper*>(current_tree_->GetRoot()) ->GetAlertForText(text); - SendEvent(context, obj, ax::mojom::Event::kAlert); + SendEvent(obj, ax::mojom::Event::kAlert); } void AutomationManagerAura::PerformAction(const ui::AXActionData& data) { @@ -181,12 +135,12 @@ if (!parent) parent = current_tree_->GetRoot(); - SendEvent(nullptr, parent, ax::mojom::Event::kChildrenChanged); + SendEvent(parent, ax::mojom::Event::kChildrenChanged); } void AutomationManagerAura::OnEvent(views::AXAuraObjWrapper* aura_obj, ax::mojom::Event event_type) { - SendEvent(nullptr, aura_obj, event_type); + SendEvent(aura_obj, event_type); } AutomationManagerAura::AutomationManagerAura() @@ -206,8 +160,7 @@ new AuraAXTreeSerializer(current_tree_.get())); } -void AutomationManagerAura::SendEvent(BrowserContext* context, - views::AXAuraObjWrapper* aura_obj, +void AutomationManagerAura::SendEvent(views::AXAuraObjWrapper* aura_obj, ax::mojom::Event event_type) { if (!enabled_) return; @@ -215,14 +168,6 @@ if (!current_tree_serializer_) return; - if (!context) - context = GetDefaultEventContext(); - - if (!context) { - LOG(WARNING) << "Accessibility notification but no browser context"; - return; - } - if (processing_events_) { pending_events_.push_back(std::make_pair(aura_obj, event_type)); return; @@ -271,9 +216,7 @@ auto pending_events_copy = pending_events_; pending_events_.clear(); for (size_t i = 0; i < pending_events_copy.size(); ++i) { - SendEvent(context, - pending_events_copy[i].first, - pending_events_copy[i].second); + SendEvent(pending_events_copy[i].first, pending_events_copy[i].second); } } @@ -354,6 +297,6 @@ views::AXAuraObjWrapper* window_wrapper = views::AXAuraObjCache::GetInstance()->GetOrCreate(window); if (window_wrapper) - SendEvent(nullptr, window_wrapper, action.hit_test_event_to_fire); + SendEvent(window_wrapper, action.hit_test_event_to_fire); #endif }
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h index c947f91..c7a4695 100644 --- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h +++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
@@ -24,10 +24,6 @@ struct DefaultSingletonTraits; } // namespace base -namespace content { -class BrowserContext; -} // namespace content - namespace views { class AXAuraObjWrapper; class View; @@ -48,17 +44,15 @@ static AutomationManagerAura* GetInstance(); // Enable automation support for views. - void Enable(content::BrowserContext* context); + void Enable(); // Disable automation support for views. void Disable(); // Handle an event fired upon a |View|. - void HandleEvent(content::BrowserContext* context, - views::View* view, - ax::mojom::Event event_type); + void HandleEvent(views::View* view, ax::mojom::Event event_type); - void HandleAlert(content::BrowserContext* context, const std::string& text); + void HandleAlert(const std::string& text); // AXHostDelegate implementation. void PerformAction(const ui::AXActionData& data) override; @@ -89,8 +83,7 @@ // serializer to save memory. void Reset(bool reset_serializer); - void SendEvent(content::BrowserContext* context, - views::AXAuraObjWrapper* aura_obj, + void SendEvent(views::AXAuraObjWrapper* aura_obj, ax::mojom::Event event_type); void PerformHitTest(const ui::AXActionData& data);
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc index f0d9588..b15a37a 100644 --- a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc +++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
@@ -107,7 +107,7 @@ content::BrowserAccessibilityState::GetInstance()->EnableAccessibility(); AutomationManagerAura* manager = AutomationManagerAura::GetInstance(); - manager->Enable(browser()->profile()); + manager->Enable(); auto* tree = manager->current_tree_.get(); ui_test_utils::NavigateToURL( @@ -143,7 +143,7 @@ IN_PROC_BROWSER_TEST_F(AutomationManagerAuraBrowserTest, TransientFocusChangesAreSuppressed) { AutomationManagerAura* manager = AutomationManagerAura::GetInstance(); - manager->Enable(browser()->profile()); + manager->Enable(); views::Widget* widget = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index 67e22c3..b5ce30cb 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -243,7 +243,7 @@ void ChromeAutofillClient::ConfirmSaveCreditCardLocally( const CreditCard& card, - const base::Closure& callback) { + base::OnceClosure callback) { #if defined(OS_ANDROID) InfoBarService::FromWebContents(web_contents()) ->AddInfoBar(CreateSaveCardInfoBarMobile( @@ -251,14 +251,14 @@ false, card, std::unique_ptr<base::DictionaryValue>(nullptr), /*upload_save_card_callback=*/ base::OnceCallback<void(const base::string16&)>(), - /*local_save_card_callback=*/callback, GetPrefs()))); + /*local_save_card_callback=*/std::move(callback), GetPrefs()))); #else // Do lazy initialization of SaveCardBubbleControllerImpl. autofill::SaveCardBubbleControllerImpl::CreateForWebContents( web_contents()); autofill::SaveCardBubbleControllerImpl* controller = autofill::SaveCardBubbleControllerImpl::FromWebContents(web_contents()); - controller->ShowBubbleForLocalSave(card, callback); + controller->ShowBubbleForLocalSave(card, std::move(callback)); #endif } @@ -307,8 +307,8 @@ } void ChromeAutofillClient::LoadRiskData( - const base::Callback<void(const std::string&)>& callback) { - ::autofill::LoadRiskData(0, web_contents(), callback); + base::OnceCallback<void(const std::string&)> callback) { + ::autofill::LoadRiskData(0, web_contents(), std::move(callback)); } bool ChromeAutofillClient::HasCreditCardScanFeature() {
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h index fc31651..907a3ab 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.h +++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -72,7 +72,7 @@ void ConfirmSaveAutofillProfile(const AutofillProfile& profile, base::OnceClosure callback) override; void ConfirmSaveCreditCardLocally(const CreditCard& card, - const base::Closure& callback) override; + base::OnceClosure callback) override; void ConfirmSaveCreditCardToCloud( const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, @@ -81,7 +81,7 @@ void ConfirmCreditCardFillAssist(const CreditCard& card, const base::Closure& callback) override; void LoadRiskData( - const base::Callback<void(const std::string&)>& callback) override; + base::OnceCallback<void(const std::string&)> callback) override; bool HasCreditCardScanFeature() override; void ScanCreditCard(const CreditCardScanCallback& callback) override; void ShowAutofillPopup(
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc index ec40074b..eefda91 100644 --- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc +++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
@@ -43,7 +43,9 @@ if (!LegalMessageLine::Parse(*legal_message, &legal_message_lines_, /*escape_apostrophes=*/true)) { - // TODO(crbug/867194): Add metric. + AutofillMetrics::LogLocalCardMigrationDialogOfferMetric( + AutofillMetrics:: + LOCAL_CARD_MIGRATION_DIALOG_NOT_SHOWN_INVALID_LEGAL_MESSAGE); return; } @@ -52,6 +54,10 @@ migratable_credit_cards_ = migratable_credit_cards; view_state_ = LocalCardMigrationDialogState::kOffered; local_card_migration_dialog_->ShowDialog(); + dialog_is_visible_duration_timer_ = base::ElapsedTimer(); + + AutofillMetrics::LogLocalCardMigrationDialogOfferMetric( + AutofillMetrics::LOCAL_CARD_MIGRATION_DIALOG_SHOWN); } LocalCardMigrationDialogState @@ -71,12 +77,21 @@ void LocalCardMigrationDialogControllerImpl::OnSaveButtonClicked( const std::vector<std::string>& selected_cards_guids) { - // TODO(crbug.com/867194): Add metrics. + AutofillMetrics::LogLocalCardMigrationDialogUserInteractionMetric( + dialog_is_visible_duration_timer_.Elapsed(), selected_cards_guids.size(), + migratable_credit_cards_.size(), + AutofillMetrics::LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED); + std::move(start_migrating_cards_callback_).Run(selected_cards_guids); } void LocalCardMigrationDialogControllerImpl::OnCancelButtonClicked() { - // TODO(crbug.com/867194): Add metrics. + AutofillMetrics::LogLocalCardMigrationDialogUserInteractionMetric( + dialog_is_visible_duration_timer_.Elapsed(), 0, + migratable_credit_cards_.size(), + AutofillMetrics:: + LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED); + start_migrating_cards_callback_.Reset(); } @@ -89,6 +104,13 @@ ui::PAGE_TRANSITION_LINK, /*is_renderer_initiated=*/false)); } +void LocalCardMigrationDialogControllerImpl::OnLegalMessageLinkClicked() { + AutofillMetrics::LogLocalCardMigrationDialogUserInteractionMetric( + dialog_is_visible_duration_timer_.Elapsed(), 0, + migratable_credit_cards_.size(), + AutofillMetrics::LOCAL_CARD_MIGRATION_DIALOG_LEGAL_MESSAGE_CLICKED); +} + void LocalCardMigrationDialogControllerImpl::OnDialogClosed() { if (local_card_migration_dialog_) local_card_migration_dialog_ = nullptr;
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h index a534222..f12ecdc3 100644 --- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h +++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "base/timer/elapsed_timer.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/ui/local_card_migration_dialog_controller.h" #include "content/public/browser/web_contents_user_data.h" @@ -41,6 +42,7 @@ const std::vector<std::string>& selected_cards_guids) override; void OnCancelButtonClicked() override; void OnViewCardsButtonClicked() override; + void OnLegalMessageLinkClicked() override; void OnDialogClosed() override; protected: @@ -68,6 +70,10 @@ // LocalCardMigrationDialogView. std::vector<MigratableCreditCard> migratable_credit_cards_; + // Timer used to measure the amount of time that the local card migration + // dialog is visible to users. + base::ElapsedTimer dialog_is_visible_duration_timer_; + DISALLOW_COPY_AND_ASSIGN(LocalCardMigrationDialogControllerImpl); };
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc index 2e4acce..364ba27d 100644 --- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc +++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
@@ -61,7 +61,7 @@ void SaveCardBubbleControllerImpl::ShowBubbleForLocalSave( const CreditCard& card, - const base::Closure& save_card_callback) { + base::OnceClosure save_card_callback) { // Don't show the bubble if it's already visible. if (save_card_bubble_view_) return; @@ -79,7 +79,7 @@ GetSecurityLevel()); card_ = card; - local_save_card_callback_ = save_card_callback; + local_save_card_callback_ = std::move(save_card_callback); current_bubble_type_ = BubbleType::LOCAL_SAVE; ShowBubble(); } @@ -314,8 +314,7 @@ can_animate_ = base::FeatureList::IsEnabled( features::kAutofillSaveCardSignInAfterLocalSave); - local_save_card_callback_.Run(); - local_save_card_callback_.Reset(); + std::move(local_save_card_callback_).Run(); break; case BubbleType::MANAGE_CARDS: AutofillMetrics::LogManageCardsPromptMetric(
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h index c7f9a56..3792743 100644 --- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h +++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
@@ -36,9 +36,8 @@ // Sets up the controller for local save and shows the bubble. // |save_card_callback| will be invoked if and when the Save button is // pressed. - // TODO(crbug.com/852562): Migrate this to BindOnce/OnceClosure. void ShowBubbleForLocalSave(const CreditCard& card, - const base::Closure& save_card_callback); + base::OnceClosure save_card_callback); // Sets up the controller for upload and shows the bubble. // |save_card_callback| will be invoked if and when the Save button is @@ -158,7 +157,7 @@ // Callback to run if user presses Save button in the local save bubble. If // both callbacks return true for .is_null() then no bubble is available to // show and the icon is not visible. - base::Closure local_save_card_callback_; + base::OnceClosure local_save_card_callback_; // Governs whether the upload or local save version of the UI should be shown. bool is_upload_save_ = false;
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc index bceed539..061f2fe 100644 --- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc +++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
@@ -114,7 +114,7 @@ controller()->ShowBubbleForLocalSave( card ? CreditCard(*card) : autofill::test::GetCreditCard(), // Visa by default - base::Bind(&LocalSaveCardCallback)); + base::BindOnce(&LocalSaveCardCallback)); } void ShowUploadBubble(bool should_request_name_from_user = false) {
diff --git a/chrome/browser/ui/cocoa/DEPS b/chrome/browser/ui/cocoa/DEPS index 7a63c31..027546a 100644 --- a/chrome/browser/ui/cocoa/DEPS +++ b/chrome/browser/ui/cocoa/DEPS
@@ -1,5 +1,4 @@ include_rules = [ "+chrome/browser/ui/views", - "+third_party/molokocacao", # For NSBezierPath additions. "+third_party/ocmock", # For unit tests. ]
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm index 2fb2747..f5947db3 100644 --- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm +++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -40,7 +40,6 @@ #import "chrome/browser/ui/cocoa/nsmenuitem_additions.h" #include "chrome/browser/ui/cocoa/restart_browser.h" #include "chrome/browser/ui/cocoa/task_manager_mac.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" #include "chrome/browser/ui/layout_constants.h" #include "chrome/browser/ui/profile_chooser_constants.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h index 3ffb675..5fc08776 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.h +++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -47,7 +47,6 @@ @class OverlayableContentsController; @class TabStripControllerCocoa; @class TabStripView; -@class ToolbarController; namespace content { class WebContents; @@ -70,7 +69,7 @@ std::unique_ptr<Browser> browser_; NSWindow* savedRegularWindow_; std::unique_ptr<BrowserWindowCocoa> windowShim_; - base::scoped_nsobject<ToolbarController> toolbarController_; + std::unique_ptr<LocationBarViewMac> locationBar_; base::scoped_nsobject<TabStripControllerCocoa> tabStripController_; base::scoped_nsobject<OverlayableContentsController> overlayableContentsController_; @@ -188,9 +187,6 @@ // Access the C++ bridge between the NSWindow and the rest of Chromium. - (BrowserWindow*)browserWindow; -// Return a weak pointer to the toolbar controller. -- (ToolbarController*)toolbarController; - // Return a weak pointer to the tab strip controller. - (TabStripControllerCocoa*)tabStripController;
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index 679f690e..c32d730 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -55,14 +55,12 @@ #include "chrome/browser/ui/cocoa/fullscreen_placeholder_view.h" #import "chrome/browser/ui/cocoa/fullscreen_window.h" #include "chrome/browser/ui/cocoa/l10n_util.h" +#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h" #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h" #import "chrome/browser/ui/cocoa/tabs/tab_view.h" -#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h" #import "chrome/browser/ui/cocoa/touchbar/browser_window_touch_bar_controller.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/browser/ui/location_bar/location_bar.h" @@ -297,16 +295,8 @@ // managing the creation of new tabs. [self createTabStripController]; - // Create a controller for the toolbar, giving it the toolbar model object - // and the toolbar view from the nib. The controller will handle - // registering for the appropriate command state changes from the back-end. - // Adds the toolbar to the content area. - toolbarController_.reset([[ToolbarController alloc] - initWithCommands:browser->command_controller() - profile:browser->profile() - browser:browser]); - [[toolbarController_ toolbarView] setResizeDelegate:self]; - [toolbarController_ setHasToolbar:[self hasToolbar] hasLocationBar:NO]; + locationBar_.reset(new LocationBarViewMac( + browser_->command_controller(), browser_->profile(), browser_.get())); [self updateFullscreenCollectionBehavior]; @@ -378,7 +368,6 @@ // that retains NSViewControllers and is autoreleased, so there is no way to // guarantee that the [super dealloc] call below will also call dealloc on the // controllers. - [toolbarController_ browserWillBeDestroyed]; [tabStripController_ browserWillBeDestroyed]; [super dealloc]; @@ -420,16 +409,12 @@ return windowShim_.get(); } -- (ToolbarController*)toolbarController { - return toolbarController_.get(); -} - - (TabStripControllerCocoa*)tabStripController { return tabStripController_.get(); } - (LocationBarViewMac*)locationBarBridge { - return [toolbarController_ locationBarBridge]; + return locationBar_.get(); } - (NSView*)floatingBarBackingView { @@ -810,33 +795,6 @@ BOOL autoresizesSubviews = [chromeContentView autoresizesSubviews]; [chromeContentView setAutoresizesSubviews:NO]; - // On Yosemite the toolbar can flicker when hiding or showing the bookmarks - // bar. Here, |chromeContentView| is set to not autoresize its subviews during - // the window resize. Because |chromeContentView| is not flipped, if the - // window is getting shorter, the toolbar will move up within the window. - // Soon after, a call to layoutSubviews corrects its position. Passing NO to - // setFrame:display: should keep the toolbarView's intermediate position - // hidden, as should the prior call to disable screen updates. For some - // reason, neither prevents the toolbarView's intermediate position from - // becoming visible. Its subsequent appearance in its correct location causes - // the flicker. It may be that the Appkit assumes that updating the window - // immediately is not a big deal given that everything in it is layer-backed. - // Indeed, turning off layer backing for all ancestors of the toolbarView - // causes the flicker to go away. - // - // By shifting the toolbarView enough so that it's in its correct location - // immediately after the call to setFrame:display:, the toolbar will be in - // the right spot when the Appkit prematurely flushes the window contents to - // the screen. http://crbug.com/444080 . - if ([self hasToolbar]) { - NSView* toolbarView = [toolbarController_ view]; - NSRect currentWindowFrame = [window frame]; - NSRect toolbarViewFrame = [toolbarView frame]; - toolbarViewFrame.origin.y += windowFrame.size.height - - currentWindowFrame.size.height; - [toolbarView setFrame:toolbarViewFrame]; - } - [window setFrame:windowFrame display:NO]; [chromeContentView setAutoresizesSubviews:autoresizesSubviews]; return YES; @@ -851,7 +809,6 @@ // If we are asked to size the bookmark // bar directly, its superview must be this controller's content view. DCHECK(view); - DCHECK(view == [toolbarController_ view]); // Change the height of the view and call |-layoutSubViews|. We set the height // here without regard to where the view is on the screen or whether it needs @@ -878,19 +835,15 @@ } - (void)updateToolbarWithContents:(WebContents*)tab { - [toolbarController_ updateToolbarWithContents:tab]; } - (void)resetTabState:(WebContents*)tab { - [toolbarController_ resetTabState:tab]; } - (void)setStarredState:(BOOL)isStarred { - [toolbarController_ setStarredState:isStarred]; } - (void)setCurrentPageIsTranslated:(BOOL)on { - [toolbarController_ setTranslateIconLit:on]; } - (void)onActiveTabChanged:(content::WebContents*)oldContents @@ -902,7 +855,6 @@ } - (void)zoomChangedForActiveTab:(BOOL)canShowBubble { - [toolbarController_ zoomChangedForActiveTab:canShowBubble]; } // Accept tabs from a BrowserWindowController with the same Profile. @@ -1015,7 +967,6 @@ } - (void)setIsLoading:(BOOL)isLoading force:(BOOL)force { - [toolbarController_ setIsLoading:isLoading force:force]; } - (void)firstResponderUpdated:(NSResponder*)responder { @@ -1279,12 +1230,6 @@ [[self fullscreenToolbarController] revealToolbarForWebContents:contents inForeground:inForeground]; - - if (inForeground) { - AppToolbarButton* appMenuButton = - static_cast<AppToolbarButton*>([toolbarController_ appMenuButton]); - [appMenuButton animateIfPossibleWithDelay:YES]; - } } - (void)userChangedTheme { @@ -1405,9 +1350,7 @@ // Delegate method: see |NSWindowDelegate| protocol. - (id)windowWillReturnFieldEditor:(NSWindow*)sender toObject:(id)obj { - // Ask the toolbar controller if it wants to return a custom field editor - // for the specific object. - return [toolbarController_ customFieldEditorForObject:obj]; + return nil; } // (Private/TestingAPI) @@ -1440,17 +1383,7 @@ // (Private/TestingAPI) - (NSRect)omniboxPopupAnchorRect { - // Start with toolbar rect. - NSView* toolbarView = [toolbarController_ view]; - NSRect anchorRect = [toolbarView frame]; - - // Adjust to account for height and possible bookmark bar. Compress by 1 - // to account for the separator. - anchorRect.origin.y = - NSMaxY(anchorRect) - [toolbarController_ desiredHeightForCompression:1]; - - // Shift to window base coordinates. - return [[toolbarView superview] convertRect:anchorRect toView:nil]; + return NSZeroRect; } - (BOOL)isLayoutSubviewsBlocked {
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm index bdf54b92..8ac73da 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -34,7 +34,6 @@ #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h" #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_switches.h" @@ -178,14 +177,10 @@ willPositionSheet:(NSWindow*)sheet usingRect:(NSRect)defaultSheetLocation { CGFloat defaultSheetY = defaultSheetLocation.origin.y; - if ([self hasToolbar]) { - defaultSheetY = NSMinY([[toolbarController_ view] frame]); - } else { - // The toolbar is not shown in popup and application modes. The sheet - // should be located at the top of the window, under the title of the - // window. - defaultSheetY = NSMaxY([[window contentView] frame]); - } + // The toolbar is not shown in popup and application modes. The sheet + // should be located at the top of the window, under the title of the + // window. + defaultSheetY = NSMaxY([[window contentView] frame]); // AppKit may shift the window up to fit the sheet on screen, but it will // never adjust the height of the sheet, or the origin of the sheet relative @@ -223,8 +218,6 @@ [self updateLayoutParameters:layout]; [self applyLayout:layout]; - [toolbarController_ setDividerOpacity:[self toolbarDividerOpacity]]; - // Will update the location of the permission bubble when showing/hiding the // top level toolbar in fullscreen. [self updatePermissionBubbleAnchor]; @@ -280,17 +273,6 @@ } - (void)adjustToolbarAndBookmarkBarForCompression:(CGFloat)compression { - CGFloat newHeight = - [toolbarController_ desiredHeightForCompression:compression]; - NSRect toolbarFrame = [[toolbarController_ view] frame]; - CGFloat deltaH = newHeight - toolbarFrame.size.height; - - if (deltaH == 0) - return; - - toolbarFrame.size.height = newHeight; - [[toolbarController_ view] setFrame:toolbarFrame]; - [self layoutSubviews]; } // Fullscreen methods @@ -824,7 +806,6 @@ [layout setFullscreenButtonFrame:[self fullscreenButtonFrame]]; [layout setHasToolbar:[self hasToolbar]]; - [layout setToolbarHeight:NSHeight([[toolbarController_ view] bounds])]; } - (void)applyLayout:(BrowserWindowLayout*)layout { @@ -833,9 +814,6 @@ if (!NSIsEmptyRect(output.tabStripLayout.frame)) [self applyTabStripLayout:output.tabStripLayout]; - if (!NSIsEmptyRect(output.toolbarFrame)) - [[toolbarController_ view] setFrame:output.toolbarFrame]; - [self layoutTabContentArea:output.contentAreaFrame]; if (!NSIsEmptyRect(output.fullscreenBackingBarFrame)) { @@ -854,8 +832,6 @@ - (void)updateSubviewZOrderNormal { base::scoped_nsobject<NSMutableArray> subviews([[NSMutableArray alloc] init]); - if ([toolbarController_ view]) - [subviews addObject:[toolbarController_ view]]; if ([self tabContentArea]) [subviews addObject:[self tabContentArea]]; @@ -871,9 +847,6 @@ if (floatingBarBackingView_) [subviews addObject:floatingBarBackingView_]; - if ([toolbarController_ view]) - [subviews addObject:[toolbarController_ view]]; - [self setContentViewSubviews:subviews]; }
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm index 1079058..0381b49 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -18,7 +18,6 @@ #include "chrome/browser/ui/cocoa/tabs/tab_strip_view.h" #include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h" #include "chrome/browser/ui/cocoa/test/run_loop_testing.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_profile.h" #include "components/prefs/pref_service.h" @@ -39,16 +38,11 @@ @interface BrowserWindowController (ExposedForTesting) // Implementations are below. -- (NSView*)toolbarView; - (void)dontFocusLocationBar:(BOOL)selectAll; @end @implementation BrowserWindowController (ExposedForTesting) -- (NSView*)toolbarView { - return [toolbarController_ view]; -} - - (void)dontFocusLocationBar:(BOOL)selectAll { } @end @@ -170,11 +164,6 @@ namespace { -// Returns the frame of the view in window coordinates. -NSRect FrameInWindowForView(NSView* view) { - return [[view superview] convertRect:[view frame] toView:nil]; -} - // Whether the view's frame is within the bounds of the superview. BOOL ViewContainmentValid(NSView* view) { if (NSIsEmptyRect([view frame])) @@ -210,13 +199,6 @@ // completely fill the area under the tabstrip. void CheckViewPositions(BrowserWindowController* controller) { EXPECT_TRUE(ViewHierarchyContainmentValid([[controller window] contentView])); - - NSRect tabstrip = FrameInWindowForView([controller tabStripView]); - NSRect toolbar = FrameInWindowForView([controller toolbarView]); - - // Toolbar should start immediately under the tabstrip, but the tabstrip is - // not necessarily fixed with respect to the content view. - EXPECT_EQ(NSMinY(tabstrip), NSMaxY(toolbar)); } } // end namespace @@ -351,7 +333,6 @@ TEST_F(BrowserWindowControllerTest, TestResizeViews) { TabStripView* tabstrip = [controller_ tabStripView]; NSView* contentView = [[tabstrip window] contentView]; - NSView* toolbar = [controller_ toolbarView]; // We need to muck with the views a bit to put us in a consistent state before // we start resizing. In particular, we need to move the tab strip to be @@ -364,14 +345,6 @@ // Force a layout and check each view's frame. [controller_ layoutSubviews]; CheckViewPositions(controller_); - - // Expand the toolbar to 64px and recheck - [controller_ resizeView:toolbar newHeight:64]; - CheckViewPositions(controller_); - - // Shrink the infobar to 0px and toolbar to 39px and recheck - [controller_ resizeView:toolbar newHeight:39]; - CheckViewPositions(controller_); } // By the "zoom frame", we mean what Apple calls the "standard frame".
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell.h b/chrome/browser/ui/cocoa/clickhold_button_cell.h deleted file mode 100644 index a845b267..0000000 --- a/chrome/browser/ui/cocoa/clickhold_button_cell.h +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright (c) 2011 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_COCOA_CLICKHOLD_BUTTON_CELL_H_ -#define CHROME_BROWSER_UI_COCOA_CLICKHOLD_BUTTON_CELL_H_ - -#import <Cocoa/Cocoa.h> - -#import "chrome/browser/ui/cocoa/image_button_cell.h" - -// A button cell that implements "click hold" behavior after a specified delay -// or after dragging. If click-hold is never enabled (e.g., if -// |-setEnableClickHold:| is never called), this behaves like a normal button. -@interface ClickHoldButtonCell : ImageButtonCell { - @private - BOOL enableClickHold_; - BOOL enableRightClick_; - NSTimeInterval clickHoldTimeout_; - id clickHoldTarget_; // Weak. - SEL clickHoldAction_; - id accessibilityShowMenuTarget_; // Weak. - SEL accessibilityShowMenuAction_; - BOOL trackOnlyInRect_; - BOOL activateOnDrag_; -} - -// Enable click-hold? Default: NO. -@property(assign, nonatomic) BOOL enableClickHold; - -// Enable right click? Default: NO. Needs to be set for accessibility. -@property(assign, nonatomic) BOOL enableRightClick; - -// Timeout is in seconds (at least 0.0, at most 5; 0.0 means that the button -// will always have its click-hold action activated immediately on press). -// Default: 0.25 (a guess at a Cocoa-ish value). -@property(assign, nonatomic) NSTimeInterval clickHoldTimeout; - -// Track only in the frame rectangle? Default: NO. -@property(assign, nonatomic) BOOL trackOnlyInRect; - -// Activate (click-hold) immediately on a sufficiently-large drag (if not, -// always wait for timeout)? Default: YES. -@property(assign, nonatomic) BOOL activateOnDrag; - -// Defines what to do when click-held (as per usual action/target). -@property(assign, nonatomic) id clickHoldTarget; -@property(assign, nonatomic) SEL clickHoldAction; - -// Defines what to do when the Show Menu accessibility action is performed. -// (clickHoldAction should be independent from accessibilityShowMenuAction -// since different operations, e.g. releasing vs. not releasing a mouse button, -// may need to be performed for each occasion.) -@property(assign, nonatomic) id accessibilityShowMenuTarget; -@property(assign, nonatomic) SEL accessibilityShowMenuAction; - -@end // @interface ClickHoldButtonCell - -#endif // CHROME_BROWSER_UI_COCOA_CLICKHOLD_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell.mm b/chrome/browser/ui/cocoa/clickhold_button_cell.mm deleted file mode 100644 index c26a7f4..0000000 --- a/chrome/browser/ui/cocoa/clickhold_button_cell.mm +++ /dev/null
@@ -1,234 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/clickhold_button_cell.h" - -#include "base/logging.h" - -// Minimum and maximum click-hold timeout. -static const NSTimeInterval kMinTimeout = 0.0; -static const NSTimeInterval kMaxTimeout = 5.0; - -// Drag distance threshold to activate click-hold; should be >= 0. -static const CGFloat kDragDistThreshold = 2.5; - -// See |-resetToDefaults| (and header file) for other default values. - -@interface ClickHoldButtonCell (Private) -- (void)resetToDefaults; -- (BOOL)shouldExposeAccessibilityShowMenu; -- (id)accessibilityAttributeValue:(NSString*)attribute; -@end // @interface ClickHoldButtonCell (Private) - -@implementation ClickHoldButtonCell - -@synthesize enableClickHold = enableClickHold_; -@synthesize enableRightClick = enableRightClick_; -@synthesize clickHoldTimeout = clickHoldTimeout_; -@synthesize trackOnlyInRect = trackOnlyInRect_; -@synthesize activateOnDrag = activateOnDrag_; -@synthesize clickHoldTarget = clickHoldTarget_; -@synthesize clickHoldAction = clickHoldAction_; -@synthesize accessibilityShowMenuTarget = accessibilityShowMenuTarget_; -@synthesize accessibilityShowMenuAction = accessibilityShowMenuAction_; - -// Overrides: - -+ (BOOL)prefersTrackingUntilMouseUp { - return NO; -} - -- (id)init { - if ((self = [super init])) - [self resetToDefaults]; - return self; -} - -- (id)initWithCoder:(NSCoder*)decoder { - if ((self = [super initWithCoder:decoder])) - [self resetToDefaults]; - return self; -} - -- (id)initImageCell:(NSImage*)image { - if ((self = [super initImageCell:image])) - [self resetToDefaults]; - return self; -} - -- (id)initTextCell:(NSString*)string { - if ((self = [super initTextCell:string])) - [self resetToDefaults]; - return self; -} - -- (void)accessibilityPerformAction:(NSString*)action { - if ([action isEqualToString:NSAccessibilityShowMenuAction] && - [self shouldExposeAccessibilityShowMenu]) { - NSControl* controlView = static_cast<NSControl*>([self controlView]); - if (controlView) - [controlView sendAction:accessibilityShowMenuAction_ - to:accessibilityShowMenuTarget_]; - return; - } - - [super accessibilityPerformAction:action]; -} - -- (BOOL)startTrackingAt:(NSPoint)startPoint - inView:(NSView*)controlView { - return enableClickHold_ ? YES : - [super startTrackingAt:startPoint - inView:controlView]; -} - -- (BOOL)continueTracking:(NSPoint)lastPoint - at:(NSPoint)currentPoint - inView:(NSView*)controlView { - return enableClickHold_ ? YES : - [super continueTracking:lastPoint - at:currentPoint - inView:controlView]; -} - -- (BOOL)trackMouse:(NSEvent*)originalEvent - inRect:(NSRect)cellFrame - ofView:(NSView*)controlView - untilMouseUp:(BOOL)untilMouseUp { - if (!enableClickHold_) { - return [super trackMouse:originalEvent - inRect:cellFrame - ofView:controlView - untilMouseUp:untilMouseUp]; - } - - // If doing click-hold, track the mouse ourselves. - NSPoint currPoint = [controlView convertPoint:[originalEvent locationInWindow] - fromView:nil]; - NSPoint lastPoint = currPoint; - NSPoint firstPoint = currPoint; - NSTimeInterval timeout = - MAX(MIN(clickHoldTimeout_, kMaxTimeout), kMinTimeout); - NSDate* clickHoldBailTime = [NSDate dateWithTimeIntervalSinceNow:timeout]; - - if (![self startTrackingAt:currPoint inView:controlView]) - return NO; - - enum { - kContinueTrack, kStopClickHold, kStopMouseUp, kStopLeftRect, kStopNoContinue - } state = kContinueTrack; - do { - NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask | - NSLeftMouseUpMask) - untilDate:clickHoldBailTime - inMode:NSEventTrackingRunLoopMode - dequeue:YES]; - currPoint = [controlView convertPoint:[event locationInWindow] - fromView:nil]; - - // Time-out. - if (!event) { - state = kStopClickHold; - - // Drag? (If distance meets threshold.) - } else if (activateOnDrag_ && ([event type] == NSLeftMouseDragged)) { - CGFloat dx = currPoint.x - firstPoint.x; - CGFloat dy = currPoint.y - firstPoint.y; - if ((dx*dx + dy*dy) >= (kDragDistThreshold*kDragDistThreshold)) - state = kStopClickHold; - - // Mouse up. - } else if ([event type] == NSLeftMouseUp) { - state = kStopMouseUp; - - // Stop tracking if mouse left frame rectangle (if requested to do so). - } else if (trackOnlyInRect_ && ![controlView mouse:currPoint - inRect:cellFrame]) { - state = kStopLeftRect; - - // Stop tracking if instructed to. - } else if (![self continueTracking:lastPoint - at:currPoint - inView:controlView]) { - state = kStopNoContinue; - } - - lastPoint = currPoint; - } while (state == kContinueTrack); - - [self stopTracking:lastPoint - at:lastPoint - inView:controlView - mouseIsUp:NO]; - - switch (state) { - case kStopClickHold: - if (clickHoldAction_) { - [static_cast<NSControl*>(controlView) sendAction:clickHoldAction_ - to:clickHoldTarget_]; - } - return YES; - - case kStopMouseUp: - if ([self action]) { - [static_cast<NSControl*>(controlView) sendAction:[self action] - to:[self target]]; - } - return YES; - - case kStopLeftRect: - case kStopNoContinue: - return NO; - - default: - NOTREACHED() << "Unknown terminating state!"; - } - - return NO; -} - -// Accessors and mutators: - -- (NSArray*)accessibilityActionNames { - NSArray* actionNames = [super accessibilityActionNames]; - if ([self shouldExposeAccessibilityShowMenu] && - ![actionNames containsObject:NSAccessibilityShowMenuAction]) { - return [actionNames arrayByAddingObject:NSAccessibilityShowMenuAction]; - } - - return actionNames; -} - -@end // @implementation ClickHoldButtonCell - -@implementation ClickHoldButtonCell (Private) - -// Resets various members to defaults indicated in the header file. (Those -// without indicated defaults are *not* touched.) Please keep the values below -// in sync with the header file, and please be aware of side-effects on code -// which relies on the "published" defaults. -- (void)resetToDefaults { - [self setEnableClickHold:NO]; - [self setClickHoldTimeout:0.25]; - [self setTrackOnlyInRect:NO]; - [self setActivateOnDrag:YES]; -} - -- (BOOL)shouldExposeAccessibilityShowMenu { - return (enableRightClick_ || - (enableClickHold_ && clickHoldTimeout_ > kMinTimeout)) && - accessibilityShowMenuAction_ && accessibilityShowMenuTarget_; -} - -- (id)accessibilityAttributeValue:(NSString*)attribute { - if ([attribute isEqual:NSAccessibilityRoleAttribute] && - [self clickHoldTimeout] == 0.0) { - // When the delay is set to zero, this button operates like a popup button - // from a user perspective. - return NSAccessibilityPopUpButtonRole; - } - return [super accessibilityAttributeValue:attribute]; -} - -@end // @implementation ClickHoldButtonCell (Private)
diff --git a/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm b/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm deleted file mode 100644 index 276c4ce..0000000 --- a/chrome/browser/ui/cocoa/clickhold_button_cell_unittest.mm +++ /dev/null
@@ -1,134 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/clickhold_button_cell.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/gtest_mac.h" -#include "testing/platform_test.h" - -@interface ClickHoldButtonCellTestTarget : NSObject { - @private - BOOL didOpen_; -} -- (void)open; -- (BOOL)didOpen; -@end - -@implementation ClickHoldButtonCellTestTarget -- (instancetype)init { - if ((self = [super init])) - didOpen_ = NO; - - return self; -} - -- (void)open { - didOpen_ = YES; -} - -- (BOOL)didOpen { - return didOpen_; -} -@end - -namespace { - -class ClickHoldButtonCellTest : public CocoaTest { - public: - ClickHoldButtonCellTest() { - NSRect frame = NSMakeRect(0, 0, 50, 30); - base::scoped_nsobject<NSButton> view( - [[NSButton alloc] initWithFrame:frame]); - view_ = view.get(); - base::scoped_nsobject<ClickHoldButtonCell> cell( - [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]); - [view_ setCell:cell.get()]; - [[test_window() contentView] addSubview:view_]; - } - - NSButton* view_; -}; - -TEST_VIEW(ClickHoldButtonCellTest, view_) - -// Test default values; make sure they are what they should be. -TEST_F(ClickHoldButtonCellTest, Defaults) { - ClickHoldButtonCell* cell = static_cast<ClickHoldButtonCell*>([view_ cell]); - ASSERT_TRUE([cell isKindOfClass:[ClickHoldButtonCell class]]); - - EXPECT_FALSE([cell enableClickHold]); - - NSTimeInterval clickHoldTimeout = [cell clickHoldTimeout]; - EXPECT_GE(clickHoldTimeout, 0.15); // Check for a "Cocoa-ish" value. - EXPECT_LE(clickHoldTimeout, 0.35); - - EXPECT_FALSE([cell trackOnlyInRect]); - EXPECT_TRUE([cell activateOnDrag]); -} - -// TODO(viettrungluu): (1) Enable click-hold and figure out how to test the -// tracking loop (i.e., |-trackMouse:...|), which is the nontrivial part. -// (2) Test various initialization code paths (in particular, loading from nib). - -TEST_F(ClickHoldButtonCellTest, AccessibilityShowMenu) { - ClickHoldButtonCell* cell = static_cast<ClickHoldButtonCell*>([view_ cell]); - ASSERT_TRUE([cell isKindOfClass:[ClickHoldButtonCell class]]); - - ClickHoldButtonCellTestTarget* cellTarget = - [[[ClickHoldButtonCellTestTarget alloc] init] autorelease]; - ASSERT_NSNE(nil, cellTarget); - ASSERT_TRUE([cellTarget respondsToSelector:@selector(open)]); - ASSERT_FALSE([cellTarget didOpen]); - - [cell setEnableClickHold:NO]; - - NSArray* actionNames = [cell accessibilityActionNames]; - EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]); - - [cell setEnableClickHold:YES]; - - // There is no action set. - actionNames = [cell accessibilityActionNames]; - EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]); - - // clickHoldAction should be independent from accessibilityShowMenuAction - // since different operations, e.g. releasing vs. not releasing a mouse - // button, may need to be performed for each occasion. - [cell setClickHoldAction:@selector(open)]; - [cell setClickHoldTarget:cellTarget]; - - actionNames = [cell accessibilityActionNames]; - EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]); - EXPECT_FALSE([cellTarget didOpen]); - - // Even when accessibilityShowMenuAction is set, no action should be available - // if neither enableClickHold nor enableRightClickHold are true. - [cell setEnableClickHold:NO]; - [cell setAccessibilityShowMenuAction:@selector(open)]; - [cell setAccessibilityShowMenuTarget:cellTarget]; - - actionNames = [cell accessibilityActionNames]; - EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]); - - // Now the action should be available. - [cell setEnableClickHold:YES]; - - actionNames = [cell accessibilityActionNames]; - EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]); - - [cell setEnableClickHold:NO]; - [cell setEnableRightClick:YES]; - - actionNames = [cell accessibilityActionNames]; - EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]); - - [cell accessibilityPerformAction:NSAccessibilityShowMenuAction]; - EXPECT_TRUE([cellTarget didOpen]); -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h deleted file mode 100644 index 4365413..0000000 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h +++ /dev/null
@@ -1,60 +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 CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_ALERT_H_ -#define CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_ALERT_H_ - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" - -// This class implements an alert that has a constrained window look and feel -// (close button on top right, WebUI style buttons, etc...). The alert can be -// shown by using the window accessor and calling -[window orderFont:]. Normally -// this would be done by ConstrainedWindowSheetController. -@interface ConstrainedWindowAlert : NSObject { - @private - base::scoped_nsobject<NSTextField> informativeTextField_; - base::scoped_nsobject<NSTextField> messageTextField_; - base::scoped_nsobject<NSButton> linkView_; - base::scoped_nsobject<NSView> accessoryView_; - base::scoped_nsobject<NSMutableArray> buttons_; - base::scoped_nsobject<NSButton> closeButton_; - base::scoped_nsobject<NSWindow> window_; -} - -@property(nonatomic, copy) NSString* informativeText; -@property(nonatomic, copy) NSString* messageText; -@property(nonatomic, retain) NSView* accessoryView; -@property(nonatomic, readonly) NSArray* buttons; -@property(nonatomic, readonly) NSButton* closeButton; -@property(nonatomic, readonly) NSWindow* window; - -// Default initializer. -- (id)init; - -// Adds a button with the given |title|. Newly added buttons are positioned in -// order from right to left. -- (void)addButtonWithTitle:(NSString*)title - keyEquivalent:(NSString*)keyEquivalent - target:(id)target - action:(SEL)action; - -// Sets the |text|, the |target| and the |action| of a left-aligned link -// positioned above the buttons. If |text| is empty, no link is displayed. -- (void)setLinkText:(NSString*)text - target:(id)target - action:(SEL)action; - -// Lays out the controls in the alert. This should be called before the window -// is displayed. -- (void)layout; - -@end - -@interface ConstrainedWindowAlert (ExposedForTesting) -@property(nonatomic, readonly) NSButton* linkView; -@end - -#endif // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_ALERT_H_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.mm deleted file mode 100644 index cbcdbbc2..0000000 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.mm +++ /dev/null
@@ -1,291 +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. - -#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h" - -#import "base/logging.h" -#import "chrome/browser/ui/cocoa/chrome_style.h" -#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" -#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_control_utils.h" -#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h" -#import "chrome/browser/ui/cocoa/hover_close_button.h" -#include "skia/ext/skia_utils_mac.h" -#include "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h" -#include "ui/base/cocoa/controls/hyperlink_button_cell.h" -#include "ui/base/cocoa/window_size_constants.h" - -namespace { - -const CGFloat kConstrainedWindowMinWidth = 500; -const CGFloat kConstrainedWindowButtonGap = 6; - -} // namespace - -@interface ConstrainedWindowAlert () -// Position the alert buttons within the given window width. -- (void)layoutButtonsWithWindowWidth:(CGFloat)windowWidth; -// Resize the given text field to fit within the window and position it starting -// at |yPos|. Returns the new value of yPos. -- (CGFloat)layoutTextField:(NSTextField*)textField - yPos:(CGFloat)yPos - windowWidth:(CGFloat)windowWidth; -// If a link has been set, resizes the link to fit within the window and -// position it starting at |yPos|. Returns the new value of yPos. -- (CGFloat)layoutLinkAtYPos:(CGFloat)yPos - windowWidth:(CGFloat)windowWidth; -// Positions the accessory view starting at yPos. Returns the new value of yPos. -- (CGFloat)layoutAccessoryViewAtYPos:(CGFloat)yPos; -// Update the position of the close button. -- (void)layoutCloseButtonWithWindowWidth:(CGFloat)windowWidth - windowHeight:(CGFloat)windowHeight; -@end - -@implementation ConstrainedWindowAlert - -- (id)init { - if ((self = [super init])) { - window_.reset([[ConstrainedWindowCustomWindow alloc] - initWithContentRect:ui::kWindowSizeDeterminedLater]); - NSView* contentView = [window_ contentView]; - - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - - informativeTextField_.reset([constrained_window::CreateLabel() retain]); - [informativeTextField_ setSelectable:YES]; - [informativeTextField_ setAlignment:NSNaturalTextAlignment]; - if (@available(macOS 10.10, *)) { - [informativeTextField_ setLineBreakMode:NSLineBreakByWordWrapping]; - } else { - [[informativeTextField_ cell] setLineBreakMode:NSLineBreakByWordWrapping]; - } - [informativeTextField_ - setFont:rb.GetFont(chrome_style::kTextFontStyle).GetNativeFont()]; - [contentView addSubview:informativeTextField_]; - - messageTextField_.reset([constrained_window::CreateLabel() retain]); - [messageTextField_ setSelectable:YES]; - [messageTextField_ setAlignment:NSNaturalTextAlignment]; - if (@available(macOS 10.10, *)) { - [messageTextField_ setLineBreakMode:NSLineBreakByWordWrapping]; - } else { - [[messageTextField_ cell] setLineBreakMode:NSLineBreakByWordWrapping]; - } - [messageTextField_ - setFont:rb.GetFont(chrome_style::kTitleFontStyle).GetNativeFont()]; - [contentView addSubview:messageTextField_]; - - closeButton_.reset( - [[WebUIHoverCloseButton alloc] initWithFrame:NSZeroRect]); - [contentView addSubview:closeButton_]; - } - return self; -} - -- (NSString*)informativeText { - return [informativeTextField_ stringValue]; -} - -- (void)setInformativeText:(NSString*)string { - [informativeTextField_ setStringValue:string]; -} - -- (NSString*)messageText { - return [messageTextField_ stringValue]; -} - -- (void)setMessageText:(NSString*)string { - [messageTextField_ setStringValue:string]; -} - -- (void)setLinkText:(NSString*)text target:(id)target action:(SEL)action { - if (![text length]) { - [linkView_ removeFromSuperview]; - linkView_.reset(nil); - return; - } - - if (!linkView_.get()) { - linkView_.reset( - [[HyperlinkButtonCell buttonWithString:[NSString string]] retain]); - [[window_ contentView] addSubview:linkView_]; - } - - [linkView_ setTitle:text]; - [linkView_ setTarget:target]; - [linkView_ setAction:action]; -} - -- (NSView*)accessoryView { - return accessoryView_; -} - -- (void)setAccessoryView:(NSView*)accessoryView { - [accessoryView_ removeFromSuperview]; - accessoryView_.reset([accessoryView retain]); - [[window_ contentView] addSubview:accessoryView_]; -} - -- (NSArray*)buttons { - return buttons_; -} - -- (NSButton*)closeButton { - return closeButton_; -} - -- (NSWindow*)window { - return window_; -} - -- (void)addButtonWithTitle:(NSString*)title - keyEquivalent:(NSString*)keyEquivalent - target:(id)target - action:(SEL)action { - if (!buttons_.get()) - buttons_.reset([[NSMutableArray alloc] init]); - base::scoped_nsobject<NSButton> button( - [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]); - [button setTitle:title]; - [button setKeyEquivalent:keyEquivalent]; - [button setTarget:target]; - [button setAction:action]; - [buttons_ addObject:button]; - [[window_ contentView] addSubview:button]; -} - -- (void)layout { - // Button width. - CGFloat buttonWidth = 0; - for (NSButton* button in buttons_.get()) { - [button sizeToFit]; - NSSize size = [button frame].size; - buttonWidth += size.width; - } - if ([buttons_ count]) - buttonWidth += ([buttons_ count] - 1) * kConstrainedWindowButtonGap; - - // Window width. - CGFloat windowWidth = buttonWidth; - if (accessoryView_.get()) - windowWidth = std::max(windowWidth, NSWidth([accessoryView_ frame])); - windowWidth += chrome_style::kHorizontalPadding * 2; - windowWidth = std::max(windowWidth, kConstrainedWindowMinWidth); - - // Layout controls. - [self layoutButtonsWithWindowWidth:windowWidth]; - CGFloat curY = [buttons_ count] ? NSMaxY([[buttons_ lastObject] frame]) - : chrome_style::kClientBottomPadding; - CGFloat availableMessageWidth = windowWidth - - chrome_style::GetCloseButtonSize() - - kConstrainedWindowButtonGap; - curY = [self layoutLinkAtYPos:curY - windowWidth:availableMessageWidth]; - curY = [self layoutAccessoryViewAtYPos:curY]; - curY = [self layoutTextField:informativeTextField_ - yPos:curY - windowWidth:windowWidth]; - curY = [self layoutTextField:messageTextField_ - yPos:curY - windowWidth:availableMessageWidth]; - - CGFloat windowHeight = curY + chrome_style::kTitleTopPadding; - [self layoutCloseButtonWithWindowWidth:windowWidth - windowHeight:windowHeight]; - - // Update window frame. - NSRect windowFrame = NSMakeRect(0, 0, windowWidth, windowHeight); - windowFrame = [window_ frameRectForContentRect:windowFrame]; - [window_ setFrame:windowFrame display:NO]; -} - -- (void)layoutButtonsWithWindowWidth:(CGFloat)windowWidth { - // Layout first 2 button right to left. - CGFloat curX = windowWidth - chrome_style::kHorizontalPadding; - const int buttonCount = [buttons_ count]; - for (int i = 0; i < std::min(2, buttonCount); ++i) { - NSButton* button = [buttons_ objectAtIndex:i]; - NSRect rect = [button frame]; - rect.origin.x = curX - NSWidth(rect); - rect.origin.y = chrome_style::kClientBottomPadding; - [button setFrameOrigin:rect.origin]; - curX = NSMinX(rect) - kConstrainedWindowButtonGap; - } - - // Layout remaining buttons left to right. - curX = chrome_style::kHorizontalPadding; - for (int i = buttonCount - 1; i >= 2; --i) { - NSButton* button = [buttons_ objectAtIndex:i]; - [button setFrameOrigin: - NSMakePoint(curX, chrome_style::kClientBottomPadding)]; - curX += NSMaxX([button frame]) + kConstrainedWindowButtonGap; - } -} - -- (CGFloat)layoutTextField:(NSTextField*)textField - yPos:(CGFloat)yPos - windowWidth:(CGFloat)windowWidth { - if (![[textField stringValue] length]) { - [textField setHidden:YES]; - return yPos; - } - - [textField setHidden:NO]; - NSRect rect; - rect.origin.y = yPos + chrome_style::kRowPadding; - rect.origin.x = chrome_style::kHorizontalPadding; - rect.size.width = windowWidth - - chrome_style::kHorizontalPadding * 2; - rect.size.height = 1; - [textField setFrame:rect]; - [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField]; - return NSMaxY([textField frame]); -} - -- (CGFloat)layoutLinkAtYPos:(CGFloat)yPos - windowWidth:(CGFloat)windowWidth { - if (!linkView_.get()) - return yPos; - - NSRect availableBounds = NSMakeRect( - 0, - 0, - windowWidth - chrome_style::kHorizontalPadding * 2, - CGFLOAT_MAX); - NSSize size = [[linkView_ cell] cellSizeForBounds:availableBounds]; - - NSRect rect; - rect.origin.y = yPos + chrome_style::kRowPadding; - rect.origin.x = chrome_style::kHorizontalPadding; - rect.size = size; - [linkView_ setFrame:rect]; - return NSMaxY([linkView_ frame]); -} - -- (CGFloat)layoutAccessoryViewAtYPos:(CGFloat)yPos { - if (!accessoryView_.get()) - return yPos; - NSRect frame = [accessoryView_ frame]; - frame.origin.y = yPos + chrome_style::kRowPadding; - frame.origin.x = chrome_style::kHorizontalPadding; - [accessoryView_ setFrameOrigin:frame.origin]; - return NSMaxY(frame); -} - -- (void)layoutCloseButtonWithWindowWidth:(CGFloat)windowWidth - windowHeight:(CGFloat)windowHeight { - NSRect frame; - frame.size.width = chrome_style::GetCloseButtonSize(); - frame.size.height = chrome_style::GetCloseButtonSize(); - frame.origin.x = windowWidth - - chrome_style::kCloseButtonPadding - NSWidth(frame); - frame.origin.y = windowHeight - - chrome_style::kCloseButtonPadding - NSHeight(frame); - [closeButton_ setFrame:frame]; -} - -- (NSButton*)linkView { - return linkView_; -} - -@end
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm deleted file mode 100644 index 87e29ce..0000000 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm +++ /dev/null
@@ -1,103 +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. - -#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_alert.h" - -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#import "testing/gtest_mac.h" - -class ConstrainedWindowAlertTest : public CocoaTest { -}; - -@interface ConstrainedWindowAlertTestTarget : NSObject { - @private - int linkClickedCount_; -} -@property(nonatomic, readonly) int linkClickedCount; - -- (void)onLinkClicked:(id)sender; -@end - -@implementation ConstrainedWindowAlertTestTarget - -@synthesize linkClickedCount = linkClickedCount_; - -- (void)onLinkClicked:(id)sender { - ++linkClickedCount_; -} - -@end - -// Test showing the alert. -TEST_F(ConstrainedWindowAlertTest, Show) { - base::scoped_nsobject<ConstrainedWindowAlert> alert( - [[ConstrainedWindowAlert alloc] init]); - EXPECT_TRUE([alert window]); - EXPECT_TRUE([alert closeButton]); - - [alert setMessageText:@"Message text"]; - [alert setInformativeText:@"Informative text"]; - [alert addButtonWithTitle:@"OK" keyEquivalent:@"" target:nil action:NULL]; - [alert addButtonWithTitle:@"Cancel" keyEquivalent:@"" target:nil action:NULL]; - - [alert layout]; - [[alert window] makeKeyAndOrderFront:nil]; -} - -// Test showing the alert with no buttons. -TEST_F(ConstrainedWindowAlertTest, NoButtons) { - base::scoped_nsobject<ConstrainedWindowAlert> alert( - [[ConstrainedWindowAlert alloc] init]); - [alert layout]; - [[alert window] makeKeyAndOrderFront:nil]; -} - -// Test adding an accessory view to an alert. -TEST_F(ConstrainedWindowAlertTest, AccessoryView) { - base::scoped_nsobject<ConstrainedWindowAlert> alert( - [[ConstrainedWindowAlert alloc] init]); - [alert addButtonWithTitle:@"OK" keyEquivalent:@"" target:nil action:NULL]; - [alert addButtonWithTitle:@"Cancel" keyEquivalent:@"" target:nil action:NULL]; - - NSRect view_rect = NSMakeRect(0, 0, 700, 300); - base::scoped_nsobject<NSView> view([[NSView alloc] initWithFrame:view_rect]); - EXPECT_FALSE([alert accessoryView]); - [alert setAccessoryView:view]; - EXPECT_NSEQ([alert accessoryView], view); - - [alert layout]; - NSRect window_rect = [[alert window] frame]; - EXPECT_GT(NSWidth(window_rect), NSWidth(view_rect)); - EXPECT_GT(NSHeight(window_rect), NSHeight(view_rect)); - - [[alert window] makeKeyAndOrderFront:nil]; -} - -// Test adding a link to an alert. -TEST_F(ConstrainedWindowAlertTest, LinkView) { - base::scoped_nsobject<ConstrainedWindowAlert> alert( - [[ConstrainedWindowAlert alloc] init]); - base::scoped_nsobject<ConstrainedWindowAlertTestTarget> target( - [[ConstrainedWindowAlertTestTarget alloc] init]); - - [alert layout]; - NSRect initial_window_rect = [[alert window] frame]; - - EXPECT_EQ(nil, [alert linkView]); - NSString* linkText = @"Text of the link"; - [alert setLinkText:linkText - target:target.get() - action:@selector(onLinkClicked:)]; - EXPECT_EQ([linkText length], [[[alert linkView] title] length]); - - [alert layout]; - NSRect window_rect = [[alert window] frame]; - - EXPECT_GT(NSHeight(window_rect), NSHeight(initial_window_rect)); - - [[alert window] makeKeyAndOrderFront:nil]; - - [[alert linkView] performClick:nil]; - EXPECT_EQ(1, [target linkClickedCount]); -}
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h deleted file mode 100644 index d70fea4..0000000 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h +++ /dev/null
@@ -1,59 +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 CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_BUTTON_H_ -#define CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_BUTTON_H_ - -#import <Cocoa/Cocoa.h> - -#import "ui/base/cocoa/tracking_area.h" - -namespace constrained_window_button { -const CGFloat kButtonMinWidth = 72; -} - -@protocol ConstrainedWindowButtonDrawableCell -@property (nonatomic, assign) BOOL isMouseInside; -- (BOOL)isEnabled; -- (BOOL)isHighlighted; -@end - -// A push button for use in a constrained window. Specialized constrained -// windows that need a push button should use this class instead of NSButton. -@interface ConstrainedWindowButton : NSButton { - @private - ui::ScopedCrTrackingArea trackingArea_; -} - -extern const CGFloat buttonMinWidth_; - -// Draws the background and shadow inside |path| with the appropriate -// colors for |buttonState|, onto |view|. -+ (void)DrawBackgroundAndShadowForPath:(NSBezierPath*)path - withCell:(id<ConstrainedWindowButtonDrawableCell>)cell - inView:(NSView*)view; - -// Draws the highlight inside |path|, with the color for |buttonState|, -// onto |view|. -+ (void)DrawInnerHighlightForPath:(NSBezierPath*)path - withCell:(id<ConstrainedWindowButtonDrawableCell>)cell - inView:(NSView*)view; - -// Draws the border along |path|, with a color according to |buttonState|, -// onto |view|. -+ (void)DrawBorderForPath:(NSBezierPath*)path - withCell:(id<ConstrainedWindowButtonDrawableCell>)cell - inView:(NSView*)view; -@end - -// A button cell used by ConstrainedWindowButton. -@interface ConstrainedWindowButtonCell : - NSButtonCell<ConstrainedWindowButtonDrawableCell> { - @private - BOOL isMouseInside_; -} - -@end - -#endif // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.mm deleted file mode 100644 index 9ea5fe9..0000000 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button.mm +++ /dev/null
@@ -1,290 +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. - -#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/key_equivalent_constants.h" -#include "skia/ext/skia_utils_mac.h" -#import "third_party/molokocacao/NSBezierPath+MCAdditions.h" -#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" - -@interface ConstrainedWindowButton () -- (BOOL)isMouseReallyInside; -@end - -namespace { - -enum ButtonState { - BUTTON_NORMAL, - BUTTON_HOVER, - BUTTON_PRESSED, - BUTTON_DISABLED, -}; - -const CGFloat kButtonHeight = 28; -const CGFloat kButtonPaddingX = 14; - -ButtonState cellButtonState(id<ConstrainedWindowButtonDrawableCell> cell) { - if (!cell) - return BUTTON_NORMAL; - if (![cell isEnabled]) - return BUTTON_DISABLED; - if ([cell isHighlighted]) - return BUTTON_PRESSED; - if ([cell isMouseInside]) - return BUTTON_HOVER; - return BUTTON_NORMAL; -} - -// The functions below use hex color values to make it easier to compare -// the code with the spec. Table of hex values are also more readable -// then tables of NSColor constructors. - -NSGradient* GetButtonGradient(ButtonState button_state) { - const SkColor start[] = {0xFFF0F0F0, 0xFFF4F4F4, 0xFFEBEBEB, 0xFFEDEDED}; - const SkColor end[] = {0xFFE0E0E0, 0xFFE4E4E4, 0xFFDBDBDB, 0xFFDEDEDE}; - - NSColor* start_color = skia::SkColorToCalibratedNSColor(start[button_state]); - NSColor* end_color = skia::SkColorToCalibratedNSColor(end[button_state]); - return [[[NSGradient alloc] initWithColorsAndLocations: - start_color, 0.0, - start_color, 0.38, - end_color, 1.0, - nil] autorelease]; -} - -NSShadow* GetButtonHighlight(ButtonState button_state) { - const SkColor color[] = {0xBFFFFFFF, 0xF2FFFFFF, 0x24000000, 0x00000000}; - - NSShadow* shadow = [[[NSShadow alloc] init] autorelease]; - [shadow setShadowColor:skia::SkColorToCalibratedNSColor(color[button_state])]; - [shadow setShadowOffset:NSMakeSize(0, -1)]; - [shadow setShadowBlurRadius:2]; - return shadow; -} - -NSShadow* GetButtonShadow(ButtonState button_state) { - const SkColor color[] = {0x14000000, 0x1F000000, 0x00000000, 0x00000000}; - - NSShadow* shadow = [[[NSShadow alloc] init] autorelease]; - [shadow setShadowColor:skia::SkColorToCalibratedNSColor(color[button_state])]; - [shadow setShadowOffset:NSMakeSize(0, -1)]; - [shadow setShadowBlurRadius:0]; - return shadow; -} - -NSColor* GetButtonBorderColor(ButtonState button_state) { - const SkColor color[] = {0x40000000, 0x4D000000, 0x4D000000, 0x1F000000}; - - return skia::SkColorToCalibratedNSColor(color[button_state]); -} - -NSAttributedString* GetButtonAttributedString( - NSString* title, - NSString* key_equivalent, - id<ConstrainedWindowButtonDrawableCell> cell) { - const SkColor text_color[] = {0xFF333333, 0XFF000000, 0xFF000000, 0xFFAAAAAA}; - // The shadow color should be 0xFFF0F0F0 but that doesn't show up so use - // pure white instead. - const SkColor shadow_color[] = - {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF}; - - base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]); - [shadow setShadowColor: - skia::SkColorToCalibratedNSColor(shadow_color[cellButtonState(cell)])]; - [shadow setShadowOffset:NSMakeSize(0, -1)]; - [shadow setShadowBlurRadius:0]; - - base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( - [[NSMutableParagraphStyle alloc] init]); - [paragraphStyle setAlignment:NSCenterTextAlignment]; - - NSFont* font = nil; - if ([key_equivalent isEqualToString:kKeyEquivalentReturn]) - font = [NSFont boldSystemFontOfSize:12]; - else - font = [NSFont systemFontOfSize:12]; - - NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys: - font, NSFontAttributeName, - skia::SkColorToCalibratedNSColor(text_color[cellButtonState(cell)]), - NSForegroundColorAttributeName, - shadow.get(), NSShadowAttributeName, - paragraphStyle.get(), NSParagraphStyleAttributeName, - nil]; - return [[[NSAttributedString alloc] initWithString:title - attributes:attributes] autorelease]; -} - -void DrawBackgroundAndShadow(const NSRect& frame, - id<ConstrainedWindowButtonDrawableCell> cell, - NSView* view) { - NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:frame - xRadius:2 - yRadius:2]; - [ConstrainedWindowButton DrawBackgroundAndShadowForPath:path - withCell:cell - inView:view]; -} - -void DrawInnerHighlight(const NSRect& frame, - id<ConstrainedWindowButtonDrawableCell> cell, - NSView* view) { - NSBezierPath* path = - [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 1, 1) - xRadius:2 - yRadius:2]; - [ConstrainedWindowButton DrawInnerHighlightForPath:path - withCell:cell - inView:view]; -} - -void DrawBorder(const NSRect& frame, - id<ConstrainedWindowButtonDrawableCell> cell, - NSView* view) { - NSBezierPath* path = - [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 0.5, 0.5) - xRadius:2 - yRadius:2]; - [ConstrainedWindowButton DrawBorderForPath:path - withCell:cell - inView:view]; -} - -} // namespace - -@implementation ConstrainedWindowButton - -+ (Class)cellClass { - return [ConstrainedWindowButtonCell class]; -} - -- (void)updateTrackingAreas { - BOOL mouseInView = [self isMouseReallyInside]; - - if (trackingArea_.get()) - [self removeTrackingArea:trackingArea_.get()]; - - NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | - NSTrackingActiveInActiveApp | - NSTrackingInVisibleRect; - if (mouseInView) - options |= NSTrackingAssumeInside; - - trackingArea_.reset([[CrTrackingArea alloc] - initWithRect:NSZeroRect - options:options - owner:self - userInfo:nil]); - [self addTrackingArea:trackingArea_.get()]; - if ([[self cell] isMouseInside] != mouseInView) { - [[self cell] setIsMouseInside:mouseInView]; - [self setNeedsDisplay:YES]; - } -} - -- (void)mouseEntered:(NSEvent*)theEvent { - [[self cell] setIsMouseInside:YES]; - [self setNeedsDisplay:YES]; -} - -- (void)mouseExited:(NSEvent*)theEvent { - [[self cell] setIsMouseInside:YES]; - [[self cell] setIsMouseInside:NO]; - [self setNeedsDisplay:YES]; -} - -- (BOOL)isMouseReallyInside { - BOOL mouseInView = NO; - NSWindow* window = [self window]; - if (window) { - NSPoint mousePoint = [window mouseLocationOutsideOfEventStream]; - mousePoint = [self convertPoint:mousePoint fromView:nil]; - mouseInView = [self mouse:mousePoint inRect:[self bounds]]; - } - return mouseInView; -} - -- (void)sizeToFit { - [super sizeToFit]; - NSSize size = [self frame].size; - if (size.width < constrained_window_button::kButtonMinWidth) { - size.width = constrained_window_button::kButtonMinWidth; - [self setFrameSize:size]; - } -} - -+ (void)DrawBackgroundAndShadowForPath:(NSBezierPath*)path - withCell:(id<ConstrainedWindowButtonDrawableCell>)cell - inView:(NSView*)view { - ButtonState buttonState = cellButtonState(cell); - { - gfx::ScopedNSGraphicsContextSaveGState scopedGState; - [GetButtonShadow(buttonState) set]; - [[[view window] backgroundColor] set]; - [path fill]; - } - [GetButtonGradient(buttonState) drawInBezierPath:path angle:90.0]; -} - -+ (void)DrawInnerHighlightForPath:(NSBezierPath*)path - withCell:(id<ConstrainedWindowButtonDrawableCell>)cell - inView:(NSView*)view { - [path fillWithInnerShadow:GetButtonHighlight(cellButtonState(cell))]; -} - -+ (void)DrawBorderForPath:(NSBezierPath*)path - withCell:(id<ConstrainedWindowButtonDrawableCell>)cell - inView:(NSView*)view { - if ([[[view window] firstResponder] isEqual:view]) - [[NSColor colorWithCalibratedRed:0.30 green:0.57 blue:1.0 alpha:1.0] set]; - else - [GetButtonBorderColor(cellButtonState(cell)) set]; - [path stroke]; -} - -@end - -@implementation ConstrainedWindowButtonCell - -@synthesize isMouseInside = isMouseInside_; - -- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView*)controlView { - // Inset to leave room for shadow. - --frame.size.height; - - // Background and shadow - DrawBackgroundAndShadow(frame, self, controlView); - - // Inner highlight - DrawInnerHighlight(frame, self, controlView); - - // Border - DrawBorder(frame, self, controlView); -} - -- (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView*)controlView { - // Inset to leave room for shadow. - --frame.size.height; - NSAttributedString* title = GetButtonAttributedString( - [self title], [self keyEquivalent], self); - [self drawTitle:title withFrame:frame inView:controlView]; -} - -- (NSSize)cellSize { - NSAttributedString* title = GetButtonAttributedString( - [self title], [self keyEquivalent], self); - NSSize size = [title size]; - size.height = std::max(size.height, kButtonHeight); - size.width += kButtonPaddingX * 2; - return size; -} - -- (NSAttributedString*)getAttributedTitle { - return GetButtonAttributedString( - [self title], [self keyEquivalent], self); -} - -@end
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm deleted file mode 100644 index b0e148c..0000000 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm +++ /dev/null
@@ -1,61 +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. - -#import "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" -#import "ui/events/test/cocoa_test_event_utils.h" - -class ConstrainedWindowButtonTest : public CocoaTest { - public: - ConstrainedWindowButtonTest() { - NSRect frame = NSMakeRect(0, 0, 50, 30); - button_.reset([[ConstrainedWindowButton alloc] initWithFrame:frame]); - [button_ setTitle:@"Abcdefg"]; - [button_ sizeToFit]; - [[test_window() contentView] addSubview:button_]; - } - - protected: - base::scoped_nsobject<ConstrainedWindowButton> button_; -}; - -TEST_VIEW(ConstrainedWindowButtonTest, button_) - -// Test hover, mostly to ensure nothing leaks or crashes. -TEST_F(ConstrainedWindowButtonTest, DisplayWithHover) { - [[button_ cell] setIsMouseInside:NO]; - [button_ display]; - [[button_ cell] setIsMouseInside:YES]; - [button_ display]; -} - -// Test disabled, mostly to ensure nothing leaks or crashes. -TEST_F(ConstrainedWindowButtonTest, DisplayWithDisable) { - [button_ setEnabled:YES]; - [button_ display]; - [button_ setEnabled:NO]; - [button_ display]; -} - -// Test pushed, mostly to ensure nothing leaks or crashes. -TEST_F(ConstrainedWindowButtonTest, DisplayWithPushed) { - [[button_ cell] setHighlighted:NO]; - [button_ display]; - [[button_ cell] setHighlighted:YES]; - [button_ display]; -} - -// Tracking rects -TEST_F(ConstrainedWindowButtonTest, TrackingRects) { - ConstrainedWindowButtonCell* cell = [button_ cell]; - EXPECT_FALSE([cell isMouseInside]); - - [button_ mouseEntered:cocoa_test_event_utils::EnterEvent()]; - EXPECT_TRUE([cell isMouseInside]); - [button_ mouseExited:cocoa_test_event_utils::ExitEvent()]; - EXPECT_FALSE([cell isMouseInside]); -}
diff --git a/chrome/browser/ui/cocoa/create_native_web_modal_manager_cocoa.mm b/chrome/browser/ui/cocoa/create_native_web_modal_manager_cocoa.mm deleted file mode 100644 index dcd5d83b..0000000 --- a/chrome/browser/ui/cocoa/create_native_web_modal_manager_cocoa.mm +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" - -namespace web_modal { - -SingleWebContentsDialogManager* -WebContentsModalDialogManager::CreateNativeWebModalManager( - gfx::NativeWindow dialog, - web_modal::SingleWebContentsDialogManagerDelegate* delegate) { - return new SingleWebContentsDialogManagerViewsMac(dialog, delegate); -} - -} // namespace web_modal
diff --git a/chrome/browser/ui/cocoa/image_button_cell.h b/chrome/browser/ui/cocoa/image_button_cell.h deleted file mode 100644 index 9fc9b03..0000000 --- a/chrome/browser/ui/cocoa/image_button_cell.h +++ /dev/null
@@ -1,87 +0,0 @@ -// Copyright (c) 2011 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_COCOA_IMAGE_BUTTON_CELL_H_ -#define CHROME_BROWSER_UI_COCOA_IMAGE_BUTTON_CELL_H_ - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" - -namespace ui { -class ThemeProvider; -} - -namespace image_button_cell { - -// Possible states -enum ButtonState { - kDefaultState = 0, - kHoverState, - kPressedState, - kDisabledState, - // The same as above, but for non-main, non-key windows. - kDefaultStateBackground, - kHoverStateBackground, - kButtonStateCount -}; - -} // namespace ImageButtonCell - -@protocol ImageButton -@optional -// Sent from an ImageButtonCell to its view when the mouse enters or exits the -// cell. -- (void)mouseInsideStateDidChange:(BOOL)isInside; -@end - -// A button cell that can disable a different image for each possible button -// state. Images are specified by image IDs. -@interface ImageButtonCell : NSButtonCell { - @private - struct { - // At most one of these two fields will be non-null. - int imageId; - base::scoped_nsobject<NSImage> image; - } image_[image_button_cell::kButtonStateCount]; - BOOL isMouseInside_; - - // Disables the hover effect if set to true. - BOOL isHoverDisabled_; -} - -@property(assign, nonatomic) BOOL isMouseInside; - -// Gets the image for the given button state. Will load from a resource pak if -// the image was originally set using an image ID. -- (NSImage*)imageForState:(image_button_cell::ButtonState)state - view:(NSView*)controlView; - -// Sets the image for the given button state using an image ID. -// The image will be lazy loaded from a resource pak -- important because -// this is in the hot path for startup. -- (void)setImageID:(NSInteger)imageID - forButtonState:(image_button_cell::ButtonState)state; - -// Sets the image for the given button state using an image. -- (void)setImage:(NSImage*)image - forButtonState:(image_button_cell::ButtonState)state; - -// Gets the alpha to use to draw the button for the current window focus state. -- (CGFloat)imageAlphaForWindowState:(NSWindow*)window; - -// Returns the theme provider for the given |window|; this allows subclasses to -// pass in a different theme provider to use if appropriate. -- (const ui::ThemeProvider*)themeProviderForWindow:(NSWindow*)window; - -// Draws the cell's image within |cellFrame|. -- (void)drawImageWithFrame:(NSRect)cellFrame inView:(NSView*)controlView; - -// Setter for |isHoverDisabled|. If |disable| is true, set |isMouseInside_| to -// false. -- (void)setIsHoverDisabled:(BOOL)disable; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_IMAGE_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/image_button_cell.mm b/chrome/browser/ui/cocoa/image_button_cell.mm deleted file mode 100644 index f864db1..0000000 --- a/chrome/browser/ui/cocoa/image_button_cell.mm +++ /dev/null
@@ -1,279 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/image_button_cell.h" - -#include "base/logging.h" -#include "base/mac/mac_util.h" -#import "chrome/browser/themes/theme_service.h" -#import "chrome/browser/ui/cocoa/rect_path_utils.h" -#import "chrome/browser/ui/cocoa/themed_window.h" -#import "ui/base/cocoa/nsview_additions.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" - -// When the window doesn't have focus then we want to draw the button with a -// slightly lighter color. We do this by just reducing the alpha. -const CGFloat kImageNoFocusAlpha = 0.65; - -const CGFloat kHoverAnimationDuration = 0.2; // seconds - -namespace { - -NSRect CenterImageInFrame(NSImage* image, NSRect frame) { - NSRect rect; - rect.size = [image size]; - rect.origin.x = - frame.origin.x + std::round((NSWidth(frame) - NSWidth(rect)) / 2.0); - rect.origin.y = - frame.origin.y + std::round((NSHeight(frame) - NSHeight(rect)) / 2.0); - return rect; -} -} - -@interface ImageButtonCell (Private) -- (void)sharedInit; -- (image_button_cell::ButtonState)currentButtonState; -- (NSImage*)imageForID:(NSInteger)imageID - controlView:(NSView*)controlView; -- (void)animationDidProgress; -@end - -@interface HoverAnimation : NSAnimation -- (id)initWithOwner:(ImageButtonCell*)owner; -- (void)setCurrentProgress:(NSAnimationProgress)progress; -@end - -@implementation HoverAnimation { - ImageButtonCell* owner_; -} - -- (id)initWithOwner:(ImageButtonCell*)owner { - if ((self = [super initWithDuration:kHoverAnimationDuration - animationCurve:NSAnimationEaseInOut])) { - [self setAnimationBlockingMode:NSAnimationNonblocking]; - owner_ = owner; - } - return self; -} - -- (void)setCurrentProgress:(NSAnimationProgress)progress { - [super setCurrentProgress:progress]; - [owner_ animationDidProgress]; -} - -@end - -@implementation ImageButtonCell { - NSAnimation* hoverAnimation_; - image_button_cell::ButtonState oldState_; -} - -@synthesize isMouseInside = isMouseInside_; - -// For nib instantiations -- (id)initWithCoder:(NSCoder*)decoder { - if ((self = [super initWithCoder:decoder])) { - [self sharedInit]; - } - return self; -} - -// For programmatic instantiations -- (id)initTextCell:(NSString*)string { - if ((self = [super initTextCell:string])) { - [self sharedInit]; - } - return self; -} - -- (void)sharedInit { - [self setHighlightsBy:NSNoCellMask]; - - // We need to set this so that we can override |-mouseEntered:| and - // |-mouseExited:| to change the button image on hover states. - [self setShowsBorderOnlyWhileMouseInside:YES]; - - hoverAnimation_ = [[HoverAnimation alloc] initWithOwner:self]; -} - -- (void)dealloc { - [hoverAnimation_ stopAnimation]; - [hoverAnimation_ release]; - [super dealloc]; -} - -- (NSImage*)imageForState:(image_button_cell::ButtonState)state - view:(NSView*)controlView{ - if (image_[state].imageId) - return [self imageForID:image_[state].imageId controlView:controlView]; - return image_[state].image; -} - -- (void)drawImageWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - image_button_cell::ButtonState state = [self currentButtonState]; - BOOL windowHasFocus = [[controlView window] isMainWindow] || - [[controlView window] isKeyWindow]; - CGFloat alpha = [self imageAlphaForWindowState:[controlView window]]; - NSImage* image = [self imageForState:state view:controlView]; - NSImage* oldImage = nil; - CGFloat oldAlpha = 0.0; - - if (!windowHasFocus) { - NSImage* defaultImage = [self - imageForState:image_button_cell::kDefaultStateBackground - view:controlView]; - NSImage* hoverImage = [self - imageForState:image_button_cell::kHoverStateBackground - view:controlView]; - if ([self currentButtonState] == image_button_cell::kDefaultState && - defaultImage) { - image = defaultImage; - alpha = 1.0; - } else if ([self currentButtonState] == image_button_cell::kHoverState && - hoverImage) { - image = hoverImage; - alpha = 1.0; - } - } - - if ([hoverAnimation_ isAnimating]) { - oldImage = [self imageForState:oldState_ view:controlView]; - oldAlpha = 1.0 - [hoverAnimation_ currentValue] * alpha; - alpha *= [hoverAnimation_ currentValue]; - } - - NSRect imageRect = CenterImageInFrame(image, cellFrame); - NSCompositingOperation op = [[controlView window] hasDarkTheme] - ? NSCompositePlusLighter - : NSCompositePlusDarker; - - if (oldImage) { - NSRect oldImageRect = CenterImageInFrame(oldImage, cellFrame); - [oldImage drawInRect:oldImageRect - fromRect:NSZeroRect - operation:op - fraction:oldAlpha - respectFlipped:YES - hints:nil]; - } - - [image drawInRect:imageRect - fromRect:NSZeroRect - operation:op - fraction:alpha - respectFlipped:YES - hints:nil]; -} - -- (void)setIsHoverDisabled:(BOOL)disable { - if (disable) - [self setIsMouseInside:NO]; - - isHoverDisabled_ = disable; -} - -- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - [self drawImageWithFrame:cellFrame inView:controlView]; -} - -- (void)setImageID:(NSInteger)imageID - forButtonState:(image_button_cell::ButtonState)state { - DCHECK_GE(state, 0); - DCHECK_LT(state, image_button_cell::kButtonStateCount); - - image_[state].image.reset(); - image_[state].imageId = imageID; - [[self controlView] setNeedsDisplay:YES]; -} - -// Sets the image for the given button state using an image. -- (void)setImage:(NSImage*)image - forButtonState:(image_button_cell::ButtonState)state { - DCHECK_GE(state, 0); - DCHECK_LT(state, image_button_cell::kButtonStateCount); - - image_[state].image.reset([image retain]); - image_[state].imageId = 0; - [[self controlView] setNeedsDisplay:YES]; -} - -- (CGFloat)imageAlphaForWindowState:(NSWindow*)window { - BOOL windowHasFocus = [window isMainWindow] || [window isKeyWindow]; - return windowHasFocus ? 1.0 : kImageNoFocusAlpha; -} - -- (const ui::ThemeProvider*)themeProviderForWindow:(NSWindow*)window { - return [window themeProvider]; -} - -- (image_button_cell::ButtonState)currentButtonState { - bool (^has)(image_button_cell::ButtonState) = - ^(image_button_cell::ButtonState state) { - return image_[state].image || image_[state].imageId; - }; - if (![self isEnabled] && has(image_button_cell::kDisabledState)) - return image_button_cell::kDisabledState; - if ([self isHighlighted] && has(image_button_cell::kPressedState)) - return image_button_cell::kPressedState; - if ([self isMouseInside] && has(image_button_cell::kHoverState)) - return image_button_cell::kHoverState; - return image_button_cell::kDefaultState; -} - -- (NSImage*)imageForID:(NSInteger)imageID - controlView:(NSView*)controlView { - if (!imageID) - return nil; - - const ui::ThemeProvider* themeProvider = - [self themeProviderForWindow:[controlView window]]; - if (!themeProvider) - return nil; - - return themeProvider->GetNSImageNamed(imageID); -} - -- (void)animationDidProgress { - NSView<ImageButton>* control = - static_cast<NSView<ImageButton>*>([self controlView]); - [control setNeedsDisplay:YES]; -} - -- (void)setIsMouseInside:(BOOL)isMouseInside { - if (isHoverDisabled_) - return; - - if (isMouseInside_ != isMouseInside) { - oldState_ = [self currentButtonState]; - isMouseInside_ = isMouseInside; - [hoverAnimation_ startAnimation]; - NSView<ImageButton>* control = - static_cast<NSView<ImageButton>*>([self controlView]); - if ([control respondsToSelector:@selector(mouseInsideStateDidChange:)]) { - [control mouseInsideStateDidChange:isMouseInside]; - } - [control setNeedsDisplay:YES]; - } -} - -- (void)setShowsBorderOnlyWhileMouseInside:(BOOL)show { - VLOG_IF(1, !show) << "setShowsBorderOnlyWhileMouseInside:NO ignored"; -} - -- (BOOL)showsBorderOnlyWhileMouseInside { - // Always returns YES so that buttons always get mouse tracking even when - // disabled. The reload button (and possibly others) depend on this. - return YES; -} - -- (void)mouseEntered:(NSEvent*)theEvent { - [self setIsMouseInside:YES]; -} - -- (void)mouseExited:(NSEvent*)theEvent { - [self setIsMouseInside:NO]; -} - -@end
diff --git a/chrome/browser/ui/cocoa/image_button_cell_unittest.mm b/chrome/browser/ui/cocoa/image_button_cell_unittest.mm deleted file mode 100644 index 6fcc36f..0000000 --- a/chrome/browser/ui/cocoa/image_button_cell_unittest.mm +++ /dev/null
@@ -1,92 +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 "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/image_button_cell.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#include "chrome/grit/theme_resources.h" - -namespace { - -class ImageButtonCellTest : public CocoaTest { - public: - ImageButtonCellTest() { - NSRect frame = NSMakeRect(0, 0, 50, 30); - base::scoped_nsobject<NSButton> view( - [[NSButton alloc] initWithFrame:frame]); - view_ = view.get(); - base::scoped_nsobject<ImageButtonCell> cell( - [[ImageButtonCell alloc] initTextCell:@""]); - [view_ setCell:cell.get()]; - [[test_window() contentView] addSubview:view_]; - } - - void SetImages() { - [[view_ cell] setImageID:IDR_BACK - forButtonState:image_button_cell::kDefaultState]; - [[view_ cell] setImageID:IDR_BACK_H - forButtonState:image_button_cell::kHoverState]; - [[view_ cell] setImageID:IDR_BACK_P - forButtonState:image_button_cell::kPressedState]; - [[view_ cell] setImageID:IDR_BACK_D - forButtonState:image_button_cell::kDisabledState]; - } - - NSButton* view_; -}; - -// Test drawing, mostly to ensure nothing leaks or crashes. -TEST_F(ImageButtonCellTest, DisplayWithHover) { - SetImages(); - EXPECT_FALSE([[view_ cell] isMouseInside]); - [view_ display]; - [[view_ cell] setIsMouseInside:YES]; - [view_ display]; - - // Unset the hover image and draw. - [[view_ cell] setImageID:0 - forButtonState:image_button_cell::kHoverState]; - [view_ display]; -} - -// Test drawing, mostly to ensure nothing leaks or crashes. -TEST_F(ImageButtonCellTest, DisplayWithPressed) { - SetImages(); - EXPECT_FALSE([[view_ cell] isHighlighted]); - [view_ display]; - [[view_ cell] setHighlighted:YES]; - [view_ display]; - - // Unset the pressed image and draw. - [[view_ cell] setImageID:0 - forButtonState:image_button_cell::kPressedState]; - [view_ display]; -} - -// Test drawing, mostly to ensure nothing leaks or crashes. -TEST_F(ImageButtonCellTest, DisplayWithDisabled) { - SetImages(); - EXPECT_TRUE([[view_ cell] isEnabled]); - [view_ display]; - [[view_ cell] setEnabled:NO]; - [view_ display]; - - // Unset the disabled image and draw. - [[view_ cell] setImageID:0 - forButtonState:image_button_cell::kDisabledState]; - [view_ display]; -} - -TEST_F(ImageButtonCellTest, NewImageCausesDisplay) { - [[view_ cell] setImageID:IDR_FORWARD - forButtonState:image_button_cell::kDefaultState]; - [view_ display]; - EXPECT_FALSE([view_ needsDisplay]); - - [[view_ cell] setImageID:IDR_FORWARD_D - forButtonState:image_button_cell::kDefaultState]; - EXPECT_TRUE([view_ needsDisplay]); -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/menu_button.h b/chrome/browser/ui/cocoa/menu_button.h deleted file mode 100644 index 84487ff..0000000 --- a/chrome/browser/ui/cocoa/menu_button.h +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright (c) 2011 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_COCOA_MENU_BUTTON_H_ -#define CHROME_BROWSER_UI_COCOA_MENU_BUTTON_H_ - -#import <Cocoa/Cocoa.h> - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h" - -// This a button which displays a user-provided menu "attached" below it upon -// being clicked or dragged (or clicked and held). It expects a -// |ClickHoldButtonCell| as cell. -// -// There are two different behaviors of this button depending on the value of -// the |openMenuOnClick| property. If YES, the target-action mechanism will be -// handled internally to always show the menu when clicked. This behavior is -// used for the App menu, for example. When the property is NO, the button can -// have a separate target-action but will open the menu when clicked and held. -// This is used for the toolbar back/forward buttons, which have a primary -// action and the menu as a secondary click-hold action. The default value is NO -// so that custom actions can be hooked up in Interface Builder. -// The click-hold behavior can be disabled entirely through the -// |openMenuOnClickHold| property. -@interface MenuButton : ToolbarButtonCocoa { - @private - base::scoped_nsobject<NSMenu> attachedMenu_; - BOOL openMenuOnClick_; - BOOL openMenuOnRightClick_; - BOOL openMenuOnClickHold_; -} - -// The menu to display. Note that it should have no (i.e., a blank) title and -// that the 0-th entry should be blank (and won't be displayed). (This is -// because we use a pulldown list, for which Cocoa uses the 0-th item as "title" -// in the button. This might change if we ever switch to a pop-up. Our direct -// use of the given NSMenu object means that the one can set and use NSMenu's -// delegate as usual.) -@property(retain, nonatomic) IBOutlet NSMenu* attachedMenu; - -// Whether or not to open the menu when the button is clicked. Otherwise, the -// menu will only be opened when clicked and held, if that behavior has not -// been disabled. -@property(assign, nonatomic) BOOL openMenuOnClick; - -// Whether or not to open the menu when the right button is clicked. -@property(assign, nonatomic) BOOL openMenuOnRightClick; - -// Whether the menu should open if a user clicks and holds on the button. The -// default is YES. This does require that the user drag the mouse a small -// distance "pull open" the menu. -@property(assign, nonatomic) BOOL openMenuOnClickHold; - -// Returns the rectangle that menus are anchored at. Can be overridden by -// subclasses, returns -bounds by default. -- (NSRect)menuRect; - -@end // @interface MenuButton - -// Available for subclasses. -@interface MenuButton (Protected) -- (void)configureCell; -@end - -#endif // CHROME_BROWSER_UI_COCOA_MENU_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/menu_button.mm b/chrome/browser/ui/cocoa/menu_button.mm deleted file mode 100644 index 4bd4a99..0000000 --- a/chrome/browser/ui/cocoa/menu_button.mm +++ /dev/null
@@ -1,220 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/menu_button.h" - -#include "base/logging.h" -#import "chrome/browser/ui/cocoa/clickhold_button_cell.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" -#include "ui/base/material_design/material_design_controller.h" -#import "ui/base/cocoa/nsview_additions.h" -#include "ui/base/material_design/material_design_controller.h" - -@interface MenuButton (Private) -- (void)showMenu:(BOOL)isDragging; -- (void)clickShowMenu:(id)sender; -- (void)dragShowMenu:(id)sender; -@end // @interface MenuButton (Private) - -@implementation MenuButton - -@synthesize openMenuOnClick = openMenuOnClick_; -@synthesize openMenuOnRightClick = openMenuOnRightClick_; -@synthesize openMenuOnClickHold = openMenuOnClickHold_; - -// Overrides: - -+ (Class)cellClass { - return [ClickHoldButtonCell class]; -} - -- (id)init { - if ((self = [super init])) { - openMenuOnClickHold_ = YES; - [self configureCell]; - } - return self; -} - -- (id)initWithCoder:(NSCoder*)decoder { - if ((self = [super initWithCoder:decoder])) { - openMenuOnClickHold_ = YES; - [self configureCell]; - } - return self; -} - -- (id)initWithFrame:(NSRect)frameRect { - if ((self = [super initWithFrame:frameRect])) { - openMenuOnClickHold_ = YES; - [self configureCell]; - } - return self; -} - -- (void)dealloc { - self.attachedMenu = nil; - [super dealloc]; -} - -- (void)awakeFromNib { - [self configureCell]; -} - -- (void)setCell:(NSCell*)cell { - [super setCell:cell]; - [self configureCell]; -} - -- (void)rightMouseDown:(NSEvent*)theEvent { - if (!openMenuOnRightClick_) { - [super rightMouseDown:theEvent]; - return; - } - - [self clickShowMenu:self]; -} - -// Accessors and mutators: - -- (NSMenu*)attachedMenu { - return attachedMenu_.get(); -} - -- (void)setAttachedMenu:(NSMenu*)menu { - attachedMenu_.reset([menu retain]); - [self configureCell]; -} - -- (void)setOpenMenuOnClick:(BOOL)enabled { - openMenuOnClick_ = enabled; - [self configureCell]; -} - -- (void)setOpenMenuOnRightClick:(BOOL)enabled { - openMenuOnRightClick_ = enabled; - [self configureCell]; -} - -- (void)setOpenMenuOnClickHold:(BOOL)enabled { - openMenuOnClickHold_ = enabled; - [self configureCell]; -} - -- (NSRect)menuRect { - return [self bounds]; -} - -@end // @implementation MenuButton - -@implementation MenuButton (Private) - -// Synchronize the state of this class with its ClickHoldButtonCell. -- (void)configureCell { - ClickHoldButtonCell* cell = [self cell]; - DCHECK([cell isKindOfClass:[ClickHoldButtonCell class]]); - - if (![self attachedMenu]) { - [cell setEnableClickHold:NO]; - [cell setEnableRightClick:NO]; - [cell setClickHoldAction:nil]; - [cell setClickHoldTarget:nil]; - [cell setAccessibilityShowMenuAction:nil]; - [cell setAccessibilityShowMenuTarget:nil]; - return; - } - - if (openMenuOnClick_) { - [cell setClickHoldTimeout:0.0]; // Make menu trigger immediately. - [cell setAction:@selector(clickShowMenu:)]; - [cell setTarget:self]; - } else { - [cell setClickHoldTimeout:0.25]; // Default value. - } - - // Regardless of the left-or-right click behaviors, the button needs to allow - // the classic click-hold-drag behavior to "pull open" the menu. - [cell setEnableClickHold:openMenuOnClickHold_]; - [cell setClickHoldAction:@selector(dragShowMenu:)]; - [cell setClickHoldTarget:self]; - - [cell setEnableRightClick:openMenuOnRightClick_]; - if (!openMenuOnClick_ || openMenuOnRightClick_) { - [cell setAccessibilityShowMenuAction:@selector(clickShowMenu:)]; - [cell setAccessibilityShowMenuTarget:self]; - } else { - [cell setAccessibilityShowMenuAction:nil]; - [cell setAccessibilityShowMenuTarget:nil]; - } -} - -// Actually show the menu (in the correct location). |isDragging| indicates -// whether the mouse button is still down or not. -- (void)showMenu:(BOOL)isDragging { - if (![self attachedMenu]) { - LOG(WARNING) << "No menu available."; - if (isDragging) { - // If we're dragging, wait for mouse up. - [NSApp nextEventMatchingMask:NSLeftMouseUpMask - untilDate:[NSDate distantFuture] - inMode:NSEventTrackingRunLoopMode - dequeue:YES]; - } - return; - } - - // TODO(viettrungluu): We have some fudge factors below to make things line up - // (approximately). I wish I knew how to get rid of them. (Note that our view - // is flipped, and that frame should be in our coordinates.) The y/height is - // very odd, since it doesn't seem to respond to changes the way that it - // should. I don't understand it. - NSRect frame = [self menuRect]; - frame.origin.x -= 2.0; - frame.size.height -= 19.0 - NSHeight(frame); - - // The button's icon has a different relationship to its bounds, so have to - // adjust the menu location by that delta. - frame.origin.x -= [ToolbarController materialDesignButtonInset]; - frame.origin.y += [ToolbarController materialDesignButtonInset]; - - // Make our pop-up button cell and set things up. This is, as of 10.5, the - // official Apple-recommended hack. Later, perhaps |-[NSMenu - // popUpMenuPositioningItem:atLocation:inView:]| may be a better option. - // However, using a pulldown has the benefit that Cocoa automatically places - // the menu correctly even when we're at the edge of the screen (including - // "dragging upwards" when the button is close to the bottom of the screen). - base::scoped_nsobject<NSPopUpButtonCell> popUpCell( - [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:YES]); - - [popUpCell setMenu:[self attachedMenu]]; - [popUpCell selectItem:nil]; - [popUpCell attachPopUpWithFrame:frame inView:self]; - [popUpCell performClickWithFrame:frame inView:self]; - - // Once the menu is dismissed send a mouseExited event if necessary. If the - // menu action caused the super view to resize then we won't automatically - // get a mouseExited event so we need to do this manually. - // See http://crbug.com/82456 - if (![self cr_isMouseInView]) { - if ([[self cell] respondsToSelector:@selector(mouseExited:)]) - [[self cell] mouseExited:nil]; - } -} - -// Called when the button is clicked and released. (Shouldn't happen with -// timeout of 0, though there may be some strange pointing devices out there.) -- (void)clickShowMenu:(id)sender { - // We shouldn't get here unless the menu is enabled. - DCHECK([self attachedMenu]); - [self showMenu:NO]; -} - -// Called when the button is clicked and dragged/held. -- (void)dragShowMenu:(id)sender { - // We shouldn't get here unless the menu is enabled. - DCHECK([self attachedMenu]); - [self showMenu:YES]; -} - -@end // @implementation MenuButton (Private)
diff --git a/chrome/browser/ui/cocoa/menu_button_unittest.mm b/chrome/browser/ui/cocoa/menu_button_unittest.mm deleted file mode 100644 index e5c9c25..0000000 --- a/chrome/browser/ui/cocoa/menu_button_unittest.mm +++ /dev/null
@@ -1,264 +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. - -#import "chrome/browser/ui/cocoa/menu_button.h" - -#import "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/clickhold_button_cell.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#import "ui/base/test/menu_test_observer.h" -#include "ui/events/test/cocoa_test_event_utils.h" - -namespace { - -class MenuButtonTest : public CocoaTest { - public: - MenuButtonTest() { - NSRect frame = NSMakeRect(0, 0, 50, 30); - base::scoped_nsobject<MenuButton> button( - [[MenuButton alloc] initWithFrame:frame]); - button_ = button; - base::scoped_nsobject<ClickHoldButtonCell> cell( - [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]); - [button_ setCell:cell]; - [[test_window() contentView] addSubview:button_]; - } - - base::scoped_nsobject<NSMenu> CreateMenu() { - base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]); - [menu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0]; - [menu insertItemWithTitle:@"foo" action:nil keyEquivalent:@"" atIndex:1]; - [menu insertItemWithTitle:@"bar" action:nil keyEquivalent:@"" atIndex:2]; - [menu insertItemWithTitle:@"baz" action:nil keyEquivalent:@"" atIndex:3]; - return menu; - } - - NSEvent* MouseEvent(NSEventType type) { - NSPoint location; - if (button_) { - // Offset the button's origin to ensure clicks aren't routed to the - // border, which may not trigger. - location = [button_ frame].origin; - location.x += 10; - location.y += 10; - } else { - location.x = location.y = 0; - } - - return cocoa_test_event_utils::MouseEventAtPointInWindow(location, type, - test_window(), 1); - } - - MenuButton* button_; // Weak, owned by test_window(). -}; - -TEST_VIEW(MenuButtonTest, button_); - -// Test assigning a menu, again mostly to ensure nothing leaks or crashes. -TEST_F(MenuButtonTest, MenuAssign) { - base::scoped_nsobject<NSMenu> menu(CreateMenu()); - ASSERT_TRUE(menu); - - [button_ setAttachedMenu:menu]; - EXPECT_TRUE([button_ attachedMenu]); -} - -TEST_F(MenuButtonTest, OpenOnClick) { - base::scoped_nsobject<NSMenu> menu(CreateMenu()); - ASSERT_TRUE(menu); - - base::scoped_nsobject<MenuTestObserver> observer( - [[MenuTestObserver alloc] initWithMenu:menu]); - ASSERT_TRUE(observer); - [observer setCloseAfterOpening:YES]; - - [button_ setAttachedMenu:menu]; - [button_ setOpenMenuOnClick:YES]; - - EXPECT_FALSE([observer isOpen]); - EXPECT_FALSE([observer didOpen]); - - // Should open the menu. - [button_ performClick:nil]; - - EXPECT_TRUE([observer didOpen]); - EXPECT_FALSE([observer isOpen]); -} - -void OpenOnClickAndHold(MenuButtonTest* test, BOOL does_open_on_click_hold) { - base::scoped_nsobject<NSMenu> menu(test->CreateMenu()); - ASSERT_TRUE(menu); - - MenuButton* button = test->button_; - - base::scoped_nsobject<MenuTestObserver> observer( - [[MenuTestObserver alloc] initWithMenu:menu]); - ASSERT_TRUE(observer); - [observer setCloseAfterOpening:YES]; - - [button setAttachedMenu:menu]; - [button setOpenMenuOnClick:NO]; - [button setOpenMenuOnClickHold:does_open_on_click_hold]; - - EXPECT_FALSE([observer isOpen]); - EXPECT_FALSE([observer didOpen]); - - // Post a click-hold-drag event sequence in reverse. The final drag events - // needs to have a location that is far enough away from the initial drag - // point to cause the menu to open. - NSEvent* event = cocoa_test_event_utils::MouseEventAtPointInWindow( - NSMakePoint(600, 600), NSLeftMouseUp, test->test_window(), 0); - [NSApp postEvent:event atStart:YES]; - - event = cocoa_test_event_utils::MouseEventAtPointInWindow( - NSMakePoint(500, 500), NSLeftMouseDragged, test->test_window(), 0); - [NSApp postEvent:event atStart:YES]; - - [NSApp postEvent:test->MouseEvent(NSLeftMouseDragged) atStart:YES]; - - // This will cause the tracking loop to start. - [button mouseDown:test->MouseEvent(NSLeftMouseDown)]; - - EXPECT_EQ(does_open_on_click_hold, [observer didOpen]); - EXPECT_FALSE([observer isOpen]); -} - -// Test classic Mac menu behavior. -TEST_F(MenuButtonTest, OpenOnClickAndHold) { - OpenOnClickAndHold(this, YES); -} - -TEST_F(MenuButtonTest, OpenOnClickAndHoldDisabled) { - OpenOnClickAndHold(this, NO); -} - -TEST_F(MenuButtonTest, OpenOnRightClick) { - base::scoped_nsobject<NSMenu> menu(CreateMenu()); - ASSERT_TRUE(menu); - - base::scoped_nsobject<MenuTestObserver> observer( - [[MenuTestObserver alloc] initWithMenu:menu]); - ASSERT_TRUE(observer); - [observer setCloseAfterOpening:YES]; - - [button_ setAttachedMenu:menu]; - [button_ setOpenMenuOnClick:YES]; - // Right click is enabled. - [button_ setOpenMenuOnRightClick:YES]; - - EXPECT_FALSE([observer isOpen]); - EXPECT_FALSE([observer didOpen]); - - // Should open the menu. - NSEvent* event = MouseEvent(NSRightMouseDown); - [button_ rightMouseDown:event]; - - EXPECT_TRUE([observer didOpen]); - EXPECT_FALSE([observer isOpen]); -} - -TEST_F(MenuButtonTest, DontOpenOnRightClickWithoutSetRightClick) { - base::scoped_nsobject<NSMenu> menu(CreateMenu()); - ASSERT_TRUE(menu); - - base::scoped_nsobject<MenuTestObserver> observer( - [[MenuTestObserver alloc] initWithMenu:menu]); - ASSERT_TRUE(observer); - [observer setCloseAfterOpening:YES]; - - [button_ setAttachedMenu:menu]; - [button_ setOpenMenuOnClick:YES]; - - EXPECT_FALSE([observer isOpen]); - EXPECT_FALSE([observer didOpen]); - - // Should not open the menu. - NSEvent* event = MouseEvent(NSRightMouseDown); - [button_ rightMouseDown:event]; - - EXPECT_FALSE([observer didOpen]); - EXPECT_FALSE([observer isOpen]); - - // Should open the menu in this case. - [button_ performClick:nil]; - - EXPECT_TRUE([observer didOpen]); - EXPECT_FALSE([observer isOpen]); -} - -TEST_F(MenuButtonTest, OpenOnAccessibilityPerformAction) { - base::scoped_nsobject<NSMenu> menu(CreateMenu()); - ASSERT_TRUE(menu); - - base::scoped_nsobject<MenuTestObserver> observer( - [[MenuTestObserver alloc] initWithMenu:menu]); - ASSERT_TRUE(observer); - [observer setCloseAfterOpening:YES]; - - [button_ setAttachedMenu:menu]; - NSCell* buttonCell = [button_ cell]; - - EXPECT_FALSE([observer isOpen]); - EXPECT_FALSE([observer didOpen]); - - [button_ setOpenMenuOnClick:YES]; - - // NSAccessibilityShowMenuAction should not be available but - // NSAccessibilityPressAction should. - NSArray* actionNames = [buttonCell accessibilityActionNames]; - EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]); - EXPECT_TRUE([actionNames containsObject:NSAccessibilityPressAction]); - - [button_ setOpenMenuOnClick:NO]; - - // NSAccessibilityPressAction should not be the one used to open the menu now. - actionNames = [buttonCell accessibilityActionNames]; - EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]); - EXPECT_TRUE([actionNames containsObject:NSAccessibilityPressAction]); - - [buttonCell accessibilityPerformAction:NSAccessibilityShowMenuAction]; - EXPECT_TRUE([observer didOpen]); - EXPECT_FALSE([observer isOpen]); -} - -TEST_F(MenuButtonTest, OpenOnAccessibilityPerformActionWithSetRightClick) { - base::scoped_nsobject<NSMenu> menu(CreateMenu()); - ASSERT_TRUE(menu); - - base::scoped_nsobject<MenuTestObserver> observer( - [[MenuTestObserver alloc] initWithMenu:menu]); - ASSERT_TRUE(observer); - [observer setCloseAfterOpening:YES]; - - [button_ setAttachedMenu:menu]; - NSCell* buttonCell = [button_ cell]; - - EXPECT_FALSE([observer isOpen]); - EXPECT_FALSE([observer didOpen]); - - [button_ setOpenMenuOnClick:YES]; - - // Command to open the menu should not be available. - NSArray* actionNames = [buttonCell accessibilityActionNames]; - EXPECT_FALSE([actionNames containsObject:NSAccessibilityShowMenuAction]); - - [button_ setOpenMenuOnRightClick:YES]; - - // Command to open the menu should now become available. - actionNames = [buttonCell accessibilityActionNames]; - EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]); - - [button_ setOpenMenuOnClick:NO]; - - // Command should still be available, even when both click + hold and right - // click are turned on. - actionNames = [buttonCell accessibilityActionNames]; - EXPECT_TRUE([actionNames containsObject:NSAccessibilityShowMenuAction]); - - [buttonCell accessibilityPerformAction:NSAccessibilityShowMenuAction]; - EXPECT_TRUE([observer didOpen]); - EXPECT_FALSE([observer isOpen]); -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm index a73ad31..6123359 100644 --- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm +++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm
@@ -10,7 +10,6 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/cocoa/browser_window_cocoa.h" #include "chrome/browser/ui/cocoa/browser_window_controller.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/test/base/in_process_browser_test.h" #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm index 2ca85a5d..76a1d0e 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm +++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -33,7 +33,6 @@ #include "chrome/browser/ui/browser_tabstrip.h" #import "chrome/browser/ui/cocoa/browser_window_controller.h" #include "chrome/browser/ui/cocoa/drag_util.h" -#import "chrome/browser/ui/cocoa/image_button_cell.h" #include "chrome/browser/ui/cocoa/l10n_util.h" #import "chrome/browser/ui/cocoa/tab_contents/favicon_util_mac.h" #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
diff --git a/chrome/browser/ui/cocoa/toolbar/OWNERS b/chrome/browser/ui/cocoa/toolbar/OWNERS deleted file mode 100644 index fdbfdb1..0000000 --- a/chrome/browser/ui/cocoa/toolbar/OWNERS +++ /dev/null
@@ -1,2 +0,0 @@ -avi@chromium.org -rohitrao@chromium.org
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h deleted file mode 100644 index 2ce1c5203..0000000 --- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_H_ -#define CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_H_ - -#import <Cocoa/Cocoa.h> - -#include <memory> - -#import "chrome/browser/ui/cocoa/menu_button.h" -#include "chrome/browser/ui/toolbar/app_menu_icon_controller.h" - -class AnimatedIcon; - -// Button for the app toolbar button. -@interface AppToolbarButton : MenuButton { - @private - AppMenuIconController::Severity severity_; - AppMenuIconController::IconType type_; - - // Used for animating and drawing the icon. - std::unique_ptr<AnimatedIcon> animatedIcon_; - - // Value of the kAnimatedAppMenuIcon feature's "HasDelay" param. - BOOL isDelayEnabled_; - - // Used to delay the animation. Not used if |isDelayEnabled_| is false. - // We own the timer and release it when it's completed. - NSTimer* animationDelayTimer_; - - // Set true if the timer should be disabled for testing. If it's true, - // the timer will still be created but the duration will be set to 0. - BOOL disableTimerForTesting_; -} - -- (void)setSeverity:(AppMenuIconController::Severity)severity - iconType:(AppMenuIconController::IconType)iconType - shouldAnimate:(BOOL)shouldAnimate; - -// Animates the icon if possible. If |isDelayEnabled_| and |delay| -// is true, then set |animationDelayTimer_| if it's not already set. -- (void)animateIfPossibleWithDelay:(BOOL)delay; - -@end - -@interface AppToolbarButton (ExposedForTesting) - -// Returns |animatedIcon_|.get(). -- (AnimatedIcon*)animatedIcon; - -// Sets |animatedIcon_|. -- (void)setAnimatedIcon:(AnimatedIcon*)icon; - -// Returns |animationDelayTimer_|. -- (NSTimer*)animationDelayTimer; - -// Sets |disableTimerForTesting_|. -- (void)setDisableTimerForTest:(BOOL)disable; -@end - -#endif // CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.mm b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.mm deleted file mode 100644 index 06bacf1..0000000 --- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button.mm +++ /dev/null
@@ -1,245 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h" - -#include "base/macros.h" -#include "base/metrics/field_trial_params.h" -#include "chrome/app/vector_icons/vector_icons.h" -#import "chrome/browser/themes/theme_properties.h" -#include "chrome/browser/themes/theme_service.h" -#include "chrome/browser/ui/cocoa/animated_icon.h" -#import "chrome/browser/ui/cocoa/themed_window.h" -#import "chrome/browser/ui/cocoa/view_id_util.h" -#include "chrome/common/chrome_features.h" -#include "chrome/grit/chromium_strings.h" -#include "ui/base/l10n/l10n_util_mac.h" -#include "ui/base/material_design/material_design_controller.h" -#include "ui/base/theme_provider.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" - -namespace { - -// The duration of the delay in seconds. -constexpr NSTimeInterval kAnimationDelay = 1.5; - -} // namespace. - -@interface AppToolbarButton () -- (void)commonInit; -- (void)updateAnimatedIconColor; -- (SkColor)vectorIconBaseColor:(BOOL)themeIsDark; -- (void)updateAnimatedIconColor; -- (void)animateAndResetTimer; -@end - -@implementation AppToolbarButton - -- (instancetype)initWithFrame:(NSRect)frame { - if ((self = [super initWithFrame:frame])) { - [self commonInit]; - - if (base::FeatureList::IsEnabled(features::kAnimatedAppMenuIcon)) { - animatedIcon_.reset(new AnimatedIcon(kBrowserToolsAnimatedIcon, self)); - [self updateAnimatedIconColor]; - - NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; - [center addObserver:self - selector:@selector(themeDidChangeNotification:) - name:kBrowserThemeDidChangeNotification - object:nil]; - - isDelayEnabled_ = base::GetFieldTrialParamByFeatureAsBool( - features::kAnimatedAppMenuIcon, "HasDelay", false); - } - } - return self; -} - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - // Release the timer. - [animationDelayTimer_ invalidate]; - animationDelayTimer_ = nil; - - [super dealloc]; -} - -- (void)awakeFromNib { - [self commonInit]; -} - -- (void)viewDidMoveToWindow { - [super viewDidMoveToWindow]; - [self updateAnimatedIconColor]; -} - -- (void)drawRect:(NSRect)frame { - [super drawRect:frame]; - - if (animatedIcon_) { - gfx::ScopedNSGraphicsContextSaveGState save_graphics_state; - NSAffineTransform* transform = [NSAffineTransform transform]; - [transform translateXBy:-0.5 yBy:0]; - [transform concat]; - animatedIcon_->PaintIcon(frame); - } -} - -- (void)commonInit { - view_id_util::SetID(self, VIEW_ID_APP_MENU); - severity_ = AppMenuIconController::Severity::NONE; - type_ = AppMenuIconController::IconType::NONE; - [self setToolTip:l10n_util::GetNSString(IDS_APPMENU_TOOLTIP)]; -} - -- (SkColor)vectorIconBaseColor:(BOOL)themeIsDark { - const ui::ThemeProvider* provider = [[self window] themeProvider]; - return themeIsDark ? SK_ColorWHITE - : (provider && provider->ShouldIncreaseContrast() - ? SK_ColorBLACK - : gfx::kChromeIconGrey); -} - -- (void)updateAnimatedIconColor { - if (!animatedIcon_) - return; - - const ui::ThemeProvider* provider = [[self window] themeProvider]; - BOOL themeIsDark = [[self window] hasDarkTheme]; - SkColor color = provider && provider->UsingSystemTheme() - ? [self vectorIconColor:themeIsDark] - : [self vectorIconBaseColor:themeIsDark]; - animatedIcon_->set_color(color); -} - -- (const gfx::VectorIcon*)vectorIcon { - if (animatedIcon_) - return nullptr; - - switch (type_) { - case AppMenuIconController::IconType::NONE: - DCHECK_EQ(severity_, AppMenuIconController::Severity::NONE); - return &kBrowserToolsIcon; - case AppMenuIconController::IconType::UPGRADE_NOTIFICATION: - return &kBrowserToolsUpdateIcon; - case AppMenuIconController::IconType::GLOBAL_ERROR: - return &kBrowserToolsErrorIcon; - } - - return nullptr; -} - -- (SkColor)vectorIconColor:(BOOL)themeIsDark { - switch (severity_) { - case AppMenuIconController::Severity::NONE: - return [self vectorIconBaseColor:themeIsDark]; - break; - - case AppMenuIconController::Severity::LOW: - return themeIsDark ? gfx::kGoogleGreen300 : gfx::kGoogleGreen700; - break; - - case AppMenuIconController::Severity::MEDIUM: - return themeIsDark ? gfx::kGoogleYellow300 : gfx::kGoogleYellow700; - break; - - case AppMenuIconController::Severity::HIGH: - return themeIsDark ? gfx::kGoogleRed300 : gfx::kGoogleRed700; - break; - - default: - break; - } -} - -- (void)setSeverity:(AppMenuIconController::Severity)severity - iconType:(AppMenuIconController::IconType)type - shouldAnimate:(BOOL)shouldAnimate { - if (severity != severity_ || type != type_) { - severity_ = severity; - type_ = type; - - [self setToolTip:severity_ == AppMenuIconController::Severity::NONE - ? l10n_util::GetNSString(IDS_APPMENU_TOOLTIP) - : l10n_util::GetNSString( - IDS_APPMENU_TOOLTIP_UPDATE_AVAILABLE)]; - - if (animatedIcon_) { - [self updateAnimatedIconColor]; - [self animateIfPossibleWithDelay:YES]; - } - // Update the button state images with the new severity color or icon - // type. - [self resetButtonStateImages]; - } -} - -- (void)themeDidChangeNotification:(NSNotification*)aNotification { - [self updateAnimatedIconColor]; -} - -- (void)animateAndResetTimer { - animatedIcon_->Animate(); - - [animationDelayTimer_ invalidate]; - animationDelayTimer_ = nil; -} - -- (void)animateIfPossibleWithDelay:(BOOL)delay { - if (!animatedIcon_ || severity_ == AppMenuIconController::Severity::NONE) - return; - - if (!isDelayEnabled_ || animatedIcon_->IsAnimating()) { - // The timer should be nil if the icon is already animating or - // the feature's "HasDelay" param is false. - DCHECK(!animationDelayTimer_); - animatedIcon_->Animate(); - return; - } - - // If there's no delay, fire the animation and remove the timer. - if (!delay) { - [self animateAndResetTimer]; - return; - } - - // Set the delay timer. - if (!animationDelayTimer_) { - NSTimeInterval delayInterval = - disableTimerForTesting_ ? 0 : kAnimationDelay; - animationDelayTimer_ = - [NSTimer timerWithTimeInterval:delayInterval - target:self - selector:@selector(animateAndResetTimer) - userInfo:nil - repeats:NO]; - [[NSRunLoop currentRunLoop] addTimer:animationDelayTimer_ - forMode:NSRunLoopCommonModes]; - } -} - -@end - -@implementation AppToolbarButton (ExposedForTest) - -- (AnimatedIcon*)animatedIcon { - return animatedIcon_.get(); -} - -- (void)setAnimatedIcon:(AnimatedIcon*)icon { - animatedIcon_.reset(icon); -} - -- (NSTimer*)animationDelayTimer { - return animationDelayTimer_; -} - -- (void)setDisableTimerForTest:(BOOL)disable { - disableTimerForTesting_ = disable; -} - -@end
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h deleted file mode 100644 index b8ffa69..0000000 --- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_CELL_H_ -#define CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_CELL_H_ - -#import <Cocoa/Cocoa.h> - -#include <memory> - -#import "chrome/browser/ui/cocoa/clickhold_button_cell.h" - - -// Cell for the app toolbar button. This is used to draw the app menu icon -// and paint severity levels. -@interface AppToolbarButtonCell : ClickHoldButtonCell { -} - -@end - -#endif // CHROME_BROWSER_UI_COCOA_TOOLBAR_APP_TOOLBAR_BUTTON_CELL_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.mm b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.mm deleted file mode 100644 index 43c26ea..0000000 --- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.mm +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright (c) 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. - -#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h" - -#include "base/macros.h" -#import "chrome/browser/ui/cocoa/themed_window.h" -#include "ui/gfx/canvas_skia_paint.h" -#include "ui/gfx/geometry/rect.h" - -@interface AppToolbarButtonCell () -- (void)commonInit; -@end - -@implementation AppToolbarButtonCell - -- (id)initTextCell:(NSString*)text { - if ((self = [super initTextCell:text])) { - [self commonInit]; - } - return self; -} - -- (id)initWithCoder:(NSCoder*)decoder { - if ((self = [super initWithCoder:decoder])) { - [self commonInit]; - } - return self; -} - -- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - gfx::CanvasSkiaPaint canvas(cellFrame, false); - canvas.set_composite_alpha(true); - canvas.SaveLayerAlpha(255 * - [self imageAlphaForWindowState:[controlView window]]); - - canvas.Restore(); -} - -- (void)commonInit { -} - -@end
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm deleted file mode 100644 index 25603a3..0000000 --- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright (c) 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. - -#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h" - -#include "base/macros.h" -#include "base/test/scoped_task_environment.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" - -@interface TestAppToolbarButton : NSButton -@end - -@implementation TestAppToolbarButton - -+ (Class)cellClass { - return [AppToolbarButtonCell class]; -} - -@end - -class AppToolbarButtonCellTest : public CocoaTest { - protected: - AppToolbarButtonCellTest() - : scoped_task_environment_( - base::test::ScopedTaskEnvironment::MainThreadType::UI) { - base::scoped_nsobject<NSButton> button([[TestAppToolbarButton alloc] - initWithFrame:NSMakeRect(0, 0, 29, 29)]); - button_ = button; - [[test_window() contentView] addSubview:button_]; - } - - NSButton* button_; - base::scoped_nsobject<AppToolbarButtonCell> cell_; - - // Needed for gfx::Animation. - base::test::ScopedTaskEnvironment scoped_task_environment_; - - private: - DISALLOW_COPY_AND_ASSIGN(AppToolbarButtonCellTest); -}; - -TEST_VIEW(AppToolbarButtonCellTest, button_)
diff --git a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_unittest.mm b/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_unittest.mm deleted file mode 100644 index 0ddb8bd..0000000 --- a/chrome/browser/ui/cocoa/toolbar/app_toolbar_button_unittest.mm +++ /dev/null
@@ -1,194 +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. - -#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h" - -#include "base/metrics/field_trial.h" -#include "base/metrics/field_trial_param_associator.h" -#include "base/metrics/field_trial_params.h" -#include "base/test/scoped_feature_list.h" -#include "chrome/app/vector_icons/vector_icons.h" -#include "chrome/browser/ui/cocoa/animated_icon.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#include "chrome/browser/ui/cocoa/test/run_loop_testing.h" -#include "chrome/common/chrome_features.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -// Test class for AnimatedIcon. Used to check if Animate() is called. -class TestAnimatedIcon : public AnimatedIcon { - public: - TestAnimatedIcon(); - - // AnimatedIcon: - void Animate() override; - bool IsAnimating() const override; - - // Sets |is_animating_| to false. - void ResetAnimatingFlag(); - - bool is_animating() const { return is_animating_; } - - private: - bool is_animating_; - - DISALLOW_COPY_AND_ASSIGN(TestAnimatedIcon); -}; - -TestAnimatedIcon::TestAnimatedIcon() - : AnimatedIcon(kBrowserToolsAnimatedIcon, nil), is_animating_(false) {} - -void TestAnimatedIcon::Animate() { - is_animating_ = true; -} - -bool TestAnimatedIcon::IsAnimating() const { - return is_animating_; -} - -void TestAnimatedIcon::ResetAnimatingFlag() { - is_animating_ = false; -} - -class AppToolbarButtonTest : public CocoaTest { - protected: - AppToolbarButtonTest() - : field_trial_list_(new base::FieldTrialList(nullptr)) {} - - // Enables the Animated App Menu Icon feature and set the "HasDelay" - // parameter to |with_delay|. - void EnableFeatureList(bool with_delay) { - field_trial_list_.reset(); - field_trial_list_.reset(new base::FieldTrialList(nullptr)); - - base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting(); - const char kTrialName[] = "TrialName"; - const char kGroupName[] = "GroupName"; - - std::map<std::string, std::string> params; - params["HasDelay"] = with_delay ? "true" : "false"; - ASSERT_TRUE( - base::AssociateFieldTrialParams(kTrialName, kGroupName, params)); - base::FieldTrial* field_trial = - base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName); - - std::unique_ptr<base::FeatureList> feature_list( - std::make_unique<base::FeatureList>()); - feature_list->RegisterFieldTrialOverride( - features::kAnimatedAppMenuIcon.name, - base::FeatureList::OVERRIDE_ENABLE_FEATURE, field_trial); - scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); - } - - // Sets the severity level of |button_|. - void SetSeverityLevel(AppMenuIconController::Severity level) { - [button_ setSeverity:level - iconType:AppMenuIconController::IconType::NONE - shouldAnimate:YES]; - } - - base::test::ScopedFeatureList scoped_feature_list_; - - std::unique_ptr<base::FieldTrialList> field_trial_list_; - - base::scoped_nsobject<AppToolbarButton> button_; - - private: - DISALLOW_COPY_AND_ASSIGN(AppToolbarButtonTest); -}; - -// Tests the old icon. |animatedIcon_| in |button_| should be nil. -TEST_F(AppToolbarButtonTest, OldAppToolbarIcon) { - scoped_feature_list_.InitAndDisableFeature(features::kAnimatedAppMenuIcon); - button_.reset([[AppToolbarButton alloc] initWithFrame:NSZeroRect]); - EXPECT_FALSE([button_ animatedIcon]); -} - -// Tests the new icon with "HasDelay" set to false. -TEST_F(AppToolbarButtonTest, NewAppToolbarIcon_NoDelay) { - EnableFeatureList(false); - button_.reset([[AppToolbarButton alloc] initWithFrame:NSZeroRect]); - EXPECT_TRUE([button_ animatedIcon]); - - TestAnimatedIcon* test_icon = new TestAnimatedIcon(); - [button_ setAnimatedIcon:test_icon]; - [button_ setDisableTimerForTest:YES]; - - // Icon should not animate for the NONE severity level. - SetSeverityLevel(AppMenuIconController::Severity::NONE); - EXPECT_FALSE([button_ animationDelayTimer]); - EXPECT_FALSE(test_icon->is_animating()); - - test_icon->ResetAnimatingFlag(); - - // Icon should animate for the other severity levels. - // The animationDelayTimer should always be nil since "HasDelay" param of - // the feature is false. - SetSeverityLevel(AppMenuIconController::Severity::LOW); - EXPECT_FALSE([button_ animationDelayTimer]); - EXPECT_TRUE(test_icon->is_animating()); - - test_icon->ResetAnimatingFlag(); - - SetSeverityLevel(AppMenuIconController::Severity::MEDIUM); - EXPECT_FALSE([button_ animationDelayTimer]); - EXPECT_TRUE(test_icon->is_animating()); - - test_icon->ResetAnimatingFlag(); - - SetSeverityLevel(AppMenuIconController::Severity::HIGH); - EXPECT_FALSE([button_ animationDelayTimer]); - EXPECT_TRUE(test_icon->is_animating()); -} - -// Tests the new icon with "HasDelay" set to true. -TEST_F(AppToolbarButtonTest, NewAppToolbarIcon_HasDelay) { - EnableFeatureList(true); - button_.reset([[AppToolbarButton alloc] initWithFrame:NSZeroRect]); - EXPECT_TRUE([button_ animatedIcon]); - - TestAnimatedIcon* test_icon = new TestAnimatedIcon(); - [button_ setAnimatedIcon:test_icon]; - [button_ setDisableTimerForTest:YES]; - - // Icon should not animate for the NONE severity level. - SetSeverityLevel(AppMenuIconController::Severity::NONE); - EXPECT_FALSE([button_ animationDelayTimer]); - EXPECT_FALSE(test_icon->is_animating()); - - test_icon->ResetAnimatingFlag(); - - // Icon should try to animate for the other severity levels. Since the - // "HasDelay" param of the feature is true, the icon shouldn't animate. - // Instead, the animation delay timer should be set. - SetSeverityLevel(AppMenuIconController::Severity::LOW); - chrome::testing::NSRunLoopRunAllPending(); - EXPECT_FALSE([button_ animationDelayTimer]); - EXPECT_TRUE(test_icon->is_animating()); - - test_icon->ResetAnimatingFlag(); - - SetSeverityLevel(AppMenuIconController::Severity::MEDIUM); - chrome::testing::NSRunLoopRunAllPending(); - EXPECT_FALSE([button_ animationDelayTimer]); - EXPECT_TRUE(test_icon->is_animating()); - - test_icon->ResetAnimatingFlag(); - - SetSeverityLevel(AppMenuIconController::Severity::HIGH); - chrome::testing::NSRunLoopRunAllPending(); - EXPECT_FALSE([button_ animationDelayTimer]); - EXPECT_TRUE(test_icon->is_animating()); - - // Animate the icon without delay. The animation delay should be nil. - [button_ animateIfPossibleWithDelay:NO]; - EXPECT_FALSE([button_ animationDelayTimer]); - EXPECT_TRUE(test_icon->is_animating()); - - // Calling [animateIfPossibleWithDelay:YES] should re-animate the icon - // without delay if the icon is already animating. - [button_ animateIfPossibleWithDelay:YES]; - EXPECT_FALSE([button_ animationDelayTimer]); - EXPECT_TRUE(test_icon->is_animating()); -}
diff --git a/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h b/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h deleted file mode 100644 index 7aa41fb..0000000 --- a/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h +++ /dev/null
@@ -1,46 +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 CHROME_BROWSER_UI_COCOA_TOOLBAR_BACK_FORWARD_MENU_CONTROLLER_H_ -#define CHROME_BROWSER_UI_COCOA_TOOLBAR_BACK_FORWARD_MENU_CONTROLLER_H_ - -#import <Cocoa/Cocoa.h> - -#include <memory> - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/has_weak_browser_pointer.h" -#include "chrome/browser/ui/toolbar/back_forward_menu_model.h" - -@class MenuButton; - -typedef BackForwardMenuModel::ModelType BackForwardMenuType; -const BackForwardMenuType BACK_FORWARD_MENU_TYPE_BACK = - BackForwardMenuModel::ModelType::kBackward; -const BackForwardMenuType BACK_FORWARD_MENU_TYPE_FORWARD = - BackForwardMenuModel::ModelType::kForward; - -// A class that manages the back/forward menu (and delayed-menu button, and -// model). -// Implement HasWeakBrowserPointer so we can clean up if the Browser is -// destroyed. -@interface BackForwardMenuController - : NSObject<NSMenuDelegate, HasWeakBrowserPointer> { - @private - BackForwardMenuType type_; - MenuButton* button_; // Weak; comes from nib. - std::unique_ptr<BackForwardMenuModel> model_; - base::scoped_nsobject<NSMenu> backForwardMenu_; -} - -// Type (back or forwards); can only be set on initialization. -@property(readonly, nonatomic) BackForwardMenuType type; - -- (id)initWithBrowser:(Browser*)browser - modelType:(BackForwardMenuType)type - button:(MenuButton*)button; - -@end // @interface BackForwardMenuController - -#endif // CHROME_BROWSER_UI_COCOA_TOOLBAR_BACK_FORWARD_MENU_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.mm b/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.mm deleted file mode 100644 index 4c79dff..0000000 --- a/chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.mm +++ /dev/null
@@ -1,107 +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. - -#import "chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h" - -#include <memory> - -#include "base/logging.h" -#include "base/strings/sys_string_conversions.h" -#import "chrome/browser/ui/cocoa/menu_button.h" -#include "chrome/browser/ui/toolbar/back_forward_menu_model.h" -#import "ui/events/event_utils.h" -#include "ui/gfx/image/image.h" - -using base::SysUTF16ToNSString; - -@implementation BackForwardMenuController - -// Accessors and mutators: - -@synthesize type = type_; - -// Own methods: - -- (id)initWithBrowser:(Browser*)browser - modelType:(BackForwardMenuType)type - button:(MenuButton*)button { - if ((self = [super init])) { - type_ = type; - button_ = button; - model_.reset(new BackForwardMenuModel(browser, type_)); - DCHECK(model_.get()); - backForwardMenu_.reset([[NSMenu alloc] initWithTitle:@""]); - DCHECK(backForwardMenu_.get()); - [backForwardMenu_ setDelegate:self]; - - [button_ setAttachedMenu:backForwardMenu_]; - [button_ setOpenMenuOnClick:NO]; - } - return self; -} - -- (void)browserWillBeDestroyed { - [button_ setAttachedMenu:nil]; - [backForwardMenu_ setDelegate:nil]; - backForwardMenu_.reset(); - model_.reset(); -} - -// Methods as delegate: - -// Called by backForwardMenu_ just before tracking begins. -//TODO(viettrungluu): should we do anything for chapter stops (see model)? -- (void)menuNeedsUpdate:(NSMenu*)menu { - DCHECK(menu == backForwardMenu_); - - // Remove old menu items (backwards order is as good as any). - for (NSInteger i = [menu numberOfItems]; i > 0; i--) - [menu removeItemAtIndex:(i - 1)]; - - // 0-th item must be blank. (This is because we use a pulldown list, for which - // Cocoa uses the 0-th item as "title" in the button.) - [menu insertItemWithTitle:@"" - action:nil - keyEquivalent:@"" - atIndex:0]; - for (int menuID = 0; menuID < model_->GetItemCount(); menuID++) { - if (model_->IsSeparator(menuID)) { - [menu insertItem:[NSMenuItem separatorItem] - atIndex:(menuID + 1)]; - } else { - // Create a menu item with the right label. - NSMenuItem* menuItem = [[NSMenuItem alloc] - initWithTitle:SysUTF16ToNSString(model_->GetLabelAt(menuID)) - action:nil - keyEquivalent:@""]; - [menuItem autorelease]; - - gfx::Image icon; - // Icon (if it has one). - if (model_->GetIconAt(menuID, &icon)) - [menuItem setImage:icon.ToNSImage()]; - - // This will make it call our |-executeMenuItem:| method. We store the - // |menuID| (or |menu_id|) in the tag. - [menuItem setTag:menuID]; - [menuItem setTarget:self]; - [menuItem setAction:@selector(executeMenuItem:)]; - - // Put it in the menu! - [menu insertItem:menuItem - atIndex:(menuID + 1)]; - } - } -} - -// Action methods: - -- (void)executeMenuItem:(id)sender { - DCHECK([sender isKindOfClass:[NSMenuItem class]]); - int menuID = [sender tag]; - int event_flags = ui::EventFlagsFromNative([NSApp currentEvent]); - model_->ActivatedAt(menuID, event_flags); -} - -@end // @implementation BackForwardMenuController
diff --git a/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h b/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h deleted file mode 100644 index 17af843f..0000000 --- a/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright (c) 2011 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_COCOA_TOOLBAR_RELOAD_BUTTON_COCOA_H_ -#define CHROME_BROWSER_UI_COCOA_TOOLBAR_RELOAD_BUTTON_COCOA_H_ - -#import <Cocoa/Cocoa.h> - -#import "chrome/browser/ui/cocoa/clickhold_button_cell.h" -#import "chrome/browser/ui/cocoa/menu_button.h" - -// ToolbarButtonCocoa subclass which defers certain state changes when the mouse -// is hovering over it. - -class CommandUpdater; - -@interface ReloadButtonCocoa : MenuButton<ImageButton> { - @private - // Timer used when setting reload mode while the mouse is hovered. - NSTimer* pendingReloadTimer_; - base::scoped_nsobject<NSMenu> menu_; - CommandUpdater* commandUpdater_; // weak, set by toolbar controller. -} - -// Update the tag, and the image and tooltip to match. If |anInt| -// matches the current tag, no action is taken. |anInt| must be -// either |IDC_STOP| or |IDC_RELOAD|. -- (void)updateTag:(NSInteger)anInt; - -// Update the button to be a reload button or stop button depending on -// |isLoading|. If |force|, always sets the indicated mode. If -// |!force|, and the mouse is over the button, defer the transition -// from stop button to reload button until the mouse has left the -// button, or until |pendingReloadTimer_| fires. This prevents an -// inadvertent click _just_ as the state changes. -- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force; - -// Changes whether reload button shows menu. -- (void)setMenuEnabled:(BOOL)enabled; - -- (void)setCommandUpdater:(CommandUpdater*)commandUpdater; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_TOOLBAR_RELOAD_BUTTON_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.mm deleted file mode 100644 index a5acb2c..0000000 --- a/chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.mm +++ /dev/null
@@ -1,273 +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. - -#import "chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h" - -#include <stddef.h> - -#include "base/macros.h" -#include "chrome/app/chrome_command_ids.h" -#include "chrome/app/vector_icons/vector_icons.h" -#include "chrome/browser/command_updater.h" -#include "chrome/browser/global_keyboard_shortcuts_mac.h" -#import "chrome/browser/ui/cocoa/accelerators_cocoa.h" -#import "chrome/browser/ui/cocoa/themed_window.h" -#import "chrome/browser/ui/cocoa/view_id_util.h" -#include "chrome/grit/generated_resources.h" -#include "components/vector_icons/vector_icons.h" -#include "ui/base/accelerators/platform_accelerator_cocoa.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/l10n_util_mac.h" -#include "ui/base/material_design/material_design_controller.h" -#import "ui/events/event_utils.h" - -namespace { - -// Constant matches Windows. -NSTimeInterval kPendingReloadTimeout = 1.35; - -// Contents of the Reload drop-down menu. -const int kReloadMenuItems[] = { - IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM, - IDS_RELOAD_MENU_HARD_RELOAD_ITEM, - IDS_RELOAD_MENU_EMPTY_AND_HARD_RELOAD_ITEM, -}; -// Note: must have the same size as |kReloadMenuItems|. -const int kReloadMenuCommands[] = { - IDC_RELOAD, - IDC_RELOAD_BYPASSING_CACHE, - IDC_RELOAD_CLEARING_CACHE, -}; - -} // namespace - -@interface ReloadButtonCocoa () -- (void)invalidatePendingReloadTimer; -- (void)forceReloadState:(NSTimer *)timer; -- (void)populateMenu; -@end - -@implementation ReloadButtonCocoa - -+ (Class)cellClass { - return [ClickHoldButtonCell class]; -} - -- (id)initWithFrame:(NSRect)frameRect { - if ((self = [super initWithFrame:frameRect])) { - // Since this is not a custom view, -awakeFromNib won't be called twice. - [self awakeFromNib]; - } - return self; -} - -- (void)viewWillMoveToWindow:(NSWindow *)newWindow { - // If this view is moved to a new window, reset its state. - [self setIsLoading:NO force:YES]; - [super viewWillMoveToWindow:newWindow]; -} - -- (void)awakeFromNib { - // Don't allow multi-clicks, because the user probably wouldn't ever - // want to stop+reload or reload+stop. - [self setIgnoresMultiClick:YES]; - - [self setOpenMenuOnRightClick:YES]; - [self setOpenMenuOnClick:NO]; - - menu_.reset([[NSMenu alloc] initWithTitle:@""]); - [self populateMenu]; - [self setAttachedMenu:menu_]; -} - -- (BOOL)shouldMirrorInRTL { - return NO; -} - -- (void)invalidatePendingReloadTimer { - [pendingReloadTimer_ invalidate]; - pendingReloadTimer_ = nil; -} - -- (void)updateTag:(NSInteger)anInt { - if ([self tag] == anInt) - return; - - // Forcibly remove any stale tooltip which is being displayed. - [self removeAllToolTips]; - [self setTag:anInt]; - - [self resetButtonStateImages]; - if (anInt == IDC_RELOAD) { - [self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_RELOAD)]; - } else if (anInt == IDC_STOP) { - [self setToolTip:l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STOP)]; - } else { - NOTREACHED(); - } -} - -- (id)accessibilityAttributeValue:(NSString *)attribute { - if ([attribute isEqualToString:NSAccessibilityEnabledAttribute] && - pendingReloadTimer_) { - return [NSNumber numberWithBool:NO]; - } else { - return [super accessibilityAttributeValue:attribute]; - } -} - -- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force { - // Can always transition to stop mode. Only transition to reload - // mode if forced or if the mouse isn't hovering. Otherwise, note - // that reload mode is desired and disable the button. - if (isLoading) { - [self invalidatePendingReloadTimer]; - [self updateTag:IDC_STOP]; - } else if (force) { - [self invalidatePendingReloadTimer]; - [self updateTag:IDC_RELOAD]; - } else if ([self tag] == IDC_STOP && - !pendingReloadTimer_ && - [[self cell] isMouseInside]) { - [self resetButtonStateImages]; - NSImage* disabledStopImage = - [[self cell] imageForState:image_button_cell::kDisabledState - view:self]; - [[self cell] setImage:disabledStopImage - forButtonState:image_button_cell::kDefaultState]; - [[self cell] setImage:disabledStopImage - forButtonState:image_button_cell::kHoverState]; - [[self cell] setImage:disabledStopImage - forButtonState:image_button_cell::kPressedState]; - pendingReloadTimer_ = - [NSTimer timerWithTimeInterval:kPendingReloadTimeout - target:self - selector:@selector(forceReloadState:) - userInfo:nil - repeats:NO]; - // Must add the timer to |NSRunLoopCommonModes| because - // it should run in |NSEventTrackingRunLoopMode| as well as - // |NSDefaultRunLoopMode|. - [[NSRunLoop currentRunLoop] addTimer:pendingReloadTimer_ - forMode:NSRunLoopCommonModes]; - } else { - [self invalidatePendingReloadTimer]; - [self updateTag:IDC_RELOAD]; - } - [self setEnabled:pendingReloadTimer_ == nil]; -} - -- (void)setMenuEnabled:(BOOL)enabled { - [self setOpenMenuOnRightClick:enabled]; - [self setOpenMenuOnClickHold:enabled]; -} - -- (void)setCommandUpdater:(CommandUpdater*)commandUpdater { - commandUpdater_ = commandUpdater; -} - -- (void)forceReloadState:(NSTimer *)timer { - DCHECK_EQ(timer, pendingReloadTimer_); - [self setIsLoading:NO force:YES]; - // Verify that |pendingReloadTimer_| is nil so it is not left dangling. - DCHECK(!pendingReloadTimer_); -} - -- (BOOL)sendAction:(SEL)theAction to:(id)theTarget { - if ([self tag] == IDC_STOP) { - if (pendingReloadTimer_) { - // If |pendingReloadTimer_| then the control is currently being - // drawn in a disabled state, so just return. The control is NOT actually - // disabled, otherwise mousetracking (courtesy of the NSButtonCell) - // would not work. - return YES; - } else { - // When the stop is processed, immediately change to reload mode, - // even though the IPC still has to bounce off the renderer and - // back before the regular |-setIsLoaded:force:| will be called. - // [This is how views and gtk do it.] - BOOL ret = [super sendAction:theAction to:theTarget]; - if (ret) - [self forceReloadState:pendingReloadTimer_]; - return ret; - } - } - - return [super sendAction:theAction to:theTarget]; -} - -- (ViewID)viewID { - return VIEW_ID_RELOAD_BUTTON; -} - -- (const gfx::VectorIcon*)vectorIcon { - if ([self tag] == IDC_RELOAD) { - return &vector_icons::kReloadIcon; - } else if ([self tag] == IDC_STOP) { - return &kNavigateStopIcon; - } else { - NOTREACHED(); - } - - return nullptr; -} - -- (void)mouseInsideStateDidChange:(BOOL)isInside { - [pendingReloadTimer_ fire]; -} - -- (void)populateMenu { - [menu_ setAutoenablesItems:NO]; - // 0-th item must be blank. (This is because we use a pulldown list, for which - // Cocoa uses the 0-th item as "title" in the button.) - [menu_ addItemWithTitle:@"" - action:nil - keyEquivalent:@""]; - for (size_t i = 0; i < arraysize(kReloadMenuItems); ++i) { - NSString* title = l10n_util::GetNSStringWithFixup(kReloadMenuItems[i]); - base::scoped_nsobject<NSMenuItem> item( - [[NSMenuItem alloc] initWithTitle:title - action:@selector(executeMenuItem:) - keyEquivalent:@""]); - - ui::Accelerator accelerator; - bool found = GetDefaultMacAcceleratorForCommandId(kReloadMenuCommands[i], - &accelerator); - if (found) { - NSString* key_equivalent; - NSUInteger modifier_mask; - GetKeyEquivalentAndModifierMaskFromAccelerator( - accelerator, &key_equivalent, &modifier_mask); - [item setKeyEquivalent:key_equivalent]; - [item setKeyEquivalentModifierMask:modifier_mask]; - } - - [item setTag:kReloadMenuCommands[i]]; - [item setTarget:self]; - [item setEnabled:YES]; - - [menu_ addItem:item]; - } -} - -// Action for menu items. -- (void)executeMenuItem:(id)sender { - if (!commandUpdater_) - return; - DCHECK([sender isKindOfClass:[NSMenuItem class]]); - int command = [sender tag]; - int event_flags = ui::EventFlagsFromNative([NSApp currentEvent]); - commandUpdater_->ExecuteCommandWithDisposition( - command, ui::DispositionFromEventFlags(event_flags)); -} - -@end // ReloadButtonCocoa - -@implementation ReloadButtonCocoa (Testing) - -+ (void)setPendingReloadTimeout:(NSTimeInterval)seconds { - kPendingReloadTimeout = seconds; -} - -@end
diff --git a/chrome/browser/ui/cocoa/toolbar/reload_button_unittest_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/reload_button_unittest_cocoa.mm deleted file mode 100644 index ca4ec407..0000000 --- a/chrome/browser/ui/cocoa/toolbar/reload_button_unittest_cocoa.mm +++ /dev/null
@@ -1,311 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import <Cocoa/Cocoa.h> - -#import "chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h" - -#include "base/mac/scoped_nsobject.h" -#include "chrome/app/chrome_command_ids.h" -#import "chrome/browser/ui/cocoa/image_button_cell.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#import "testing/gtest_mac.h" -#include "testing/platform_test.h" -#import "third_party/ocmock/OCMock/OCMock.h" -#import "ui/base/test/menu_test_observer.h" -#import "ui/events/test/cocoa_test_event_utils.h" - -@interface ReloadButtonCocoa (TestForwardDeclares) -+ (void)setPendingReloadTimeout:(NSTimeInterval)seconds; -@end - -@implementation ReloadButtonCocoa (TestImplementation) -- (NSMenu*)menuForTesting { - return menu_; -} -@end - -@interface ReloadButtonTarget : NSObject -- (void)anAction:(id)sender; -@end - -@implementation ReloadButtonTarget -- (void)anAction:(id)sender { -} -@end - -namespace { - -class ReloadButtonCocoaTest : public CocoaTest { - public: - ReloadButtonCocoaTest() { - NSRect frame = NSMakeRect(0, 0, 20, 20); - base::scoped_nsobject<ReloadButtonCocoa> button( - [[ReloadButtonCocoa alloc] initWithFrame:frame]); - button_ = button; - - // Set things up so unit tests have a reliable baseline. - [button_ setTag:IDC_RELOAD]; - [button_ awakeFromNib]; - - [[test_window() contentView] addSubview:button_]; - } - - bool IsMouseInside() { - return [[button_ cell] isMouseInside]; - } - - void MouseEnter() { - [[button_ cell] mouseEntered:cocoa_test_event_utils::EnterEvent()]; - } - - void MouseExit() { - [[button_ cell] mouseExited:cocoa_test_event_utils::ExitEvent()]; - } - - ReloadButtonCocoa* button_; // Weak, owned by test_window(). -}; - -TEST_VIEW(ReloadButtonCocoaTest, button_) - -// Test that mouse-tracking is setup and does the right thing. -TEST_F(ReloadButtonCocoaTest, IsMouseInside) { - EXPECT_FALSE(IsMouseInside()); - MouseEnter(); - EXPECT_TRUE(IsMouseInside()); - MouseExit(); -} - -// Verify that multiple clicks do not result in multiple messages to -// the target. -TEST_F(ReloadButtonCocoaTest, IgnoredMultiClick) { - base::scoped_nsobject<ReloadButtonTarget> target( - [[ReloadButtonTarget alloc] init]); - id mock_target = [OCMockObject partialMockForObject:target]; - [button_ setTarget:mock_target]; - [button_ setAction:@selector(anAction:)]; - - // Expect the action once. - [[mock_target expect] anAction:button_]; - - const std::pair<NSEvent*,NSEvent*> click_one = - cocoa_test_event_utils::MouseClickInView(button_, 1); - const std::pair<NSEvent*,NSEvent*> click_two = - cocoa_test_event_utils::MouseClickInView(button_, 2); - [NSApp postEvent:click_one.second atStart:YES]; - [button_ mouseDown:click_one.first]; - [NSApp postEvent:click_two.second atStart:YES]; - [button_ mouseDown:click_two.first]; - - [button_ setTarget:nil]; -} - -TEST_F(ReloadButtonCocoaTest, UpdateTag) { - [button_ setTag:IDC_STOP]; - - [button_ updateTag:IDC_RELOAD]; - EXPECT_EQ(IDC_RELOAD, [button_ tag]); - NSString* const reloadToolTip = [button_ toolTip]; - - [button_ updateTag:IDC_STOP]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - NSString* const stopToolTip = [button_ toolTip]; - EXPECT_NSNE(reloadToolTip, stopToolTip); - - [button_ updateTag:IDC_RELOAD]; - EXPECT_EQ(IDC_RELOAD, [button_ tag]); - EXPECT_NSEQ(reloadToolTip, [button_ toolTip]); -} - -// Test that when forcing the mode, it takes effect immediately, -// regardless of whether the mouse is hovering. -TEST_F(ReloadButtonCocoaTest, SetIsLoadingForce) { - EXPECT_FALSE(IsMouseInside()); - EXPECT_EQ(IDC_RELOAD, [button_ tag]); - - // Changes to stop immediately. - [button_ setIsLoading:YES force:YES]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - - // Changes to reload immediately. - [button_ setIsLoading:NO force:YES]; - EXPECT_EQ(IDC_RELOAD, [button_ tag]); - - // Changes to stop immediately when the mouse is hovered, and - // doesn't change when the mouse exits. - MouseEnter(); - EXPECT_TRUE(IsMouseInside()); - [button_ setIsLoading:YES force:YES]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - MouseExit(); - EXPECT_FALSE(IsMouseInside()); - EXPECT_EQ(IDC_STOP, [button_ tag]); - - // Changes to reload immediately when the mouse is hovered, and - // doesn't change when the mouse exits. - MouseEnter(); - EXPECT_TRUE(IsMouseInside()); - [button_ setIsLoading:NO force:YES]; - EXPECT_EQ(IDC_RELOAD, [button_ tag]); - MouseExit(); - EXPECT_FALSE(IsMouseInside()); - EXPECT_EQ(IDC_RELOAD, [button_ tag]); -} - -// Test that without force, stop mode is set immediately, but reload -// is affected by the hover status. -TEST_F(ReloadButtonCocoaTest, SetIsLoadingNoForceUnHover) { - EXPECT_FALSE(IsMouseInside()); - EXPECT_EQ(IDC_RELOAD, [button_ tag]); - - // Changes to stop immediately when the mouse is not hovering. - [button_ setIsLoading:YES force:NO]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - - // Changes to reload immediately when the mouse is not hovering. - [button_ setIsLoading:NO force:NO]; - EXPECT_EQ(IDC_RELOAD, [button_ tag]); - - // Changes to stop immediately when the mouse is hovered, and - // doesn't change when the mouse exits. - MouseEnter(); - EXPECT_TRUE(IsMouseInside()); - [button_ setIsLoading:YES force:NO]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - MouseExit(); - EXPECT_FALSE(IsMouseInside()); - EXPECT_EQ(IDC_STOP, [button_ tag]); - - // Does not change to reload immediately when the mouse is hovered, - // changes when the mouse exits. - MouseEnter(); - EXPECT_TRUE(IsMouseInside()); - [button_ setIsLoading:NO force:NO]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - MouseExit(); - EXPECT_FALSE(IsMouseInside()); - EXPECT_EQ(IDC_RELOAD, [button_ tag]); -} - -// Test that without force, stop mode is set immediately, and reload -// will be set after a timeout. -// TODO(shess): Reenable, http://crbug.com/61485 -TEST_F(ReloadButtonCocoaTest, DISABLED_SetIsLoadingNoForceTimeout) { - // When the event loop first spins, some delayed tracking-area setup - // is done, which causes -mouseExited: to be called. Spin it at - // least once, and dequeue any pending events. - // TODO(shess): It would be more reasonable to have an MockNSTimer - // factory for the class to use, which this code could fire - // directly. - while ([NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue:YES]) { - } - - const NSTimeInterval kShortTimeout = 0.1; - [ReloadButtonCocoa setPendingReloadTimeout:kShortTimeout]; - - EXPECT_FALSE(IsMouseInside()); - EXPECT_EQ(IDC_RELOAD, [button_ tag]); - - // Move the mouse into the button and press it. - MouseEnter(); - EXPECT_TRUE(IsMouseInside()); - [button_ setIsLoading:YES force:NO]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - - // Does not change to reload immediately when the mouse is hovered. - EXPECT_TRUE(IsMouseInside()); - [button_ setIsLoading:NO force:NO]; - EXPECT_TRUE(IsMouseInside()); - EXPECT_EQ(IDC_STOP, [button_ tag]); - EXPECT_TRUE(IsMouseInside()); - - // Spin event loop until the timeout passes. - NSDate* pastTimeout = [NSDate dateWithTimeIntervalSinceNow:2 * kShortTimeout]; - [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:pastTimeout - inMode:NSDefaultRunLoopMode - dequeue:NO]; - - // Mouse is still hovered, button is in reload mode. If the mouse - // is no longer hovered, see comment at top of function. - EXPECT_TRUE(IsMouseInside()); - EXPECT_EQ(IDC_RELOAD, [button_ tag]); -} - -// Test that pressing stop after reload mode has been requested -// doesn't forward the stop message. -TEST_F(ReloadButtonCocoaTest, StopAfterReloadSet) { - base::scoped_nsobject<ReloadButtonTarget> target( - [[ReloadButtonTarget alloc] init]); - id mock_target = [OCMockObject partialMockForObject:target]; - [button_ setTarget:mock_target]; - [button_ setAction:@selector(anAction:)]; - - EXPECT_FALSE(IsMouseInside()); - - // Get to stop mode. - [button_ setIsLoading:YES force:YES]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - EXPECT_TRUE([button_ isEnabled]); - - // Expect the action once. - [[mock_target expect] anAction:button_]; - - // Clicking in stop mode should send the action and transition to - // reload mode. - const std::pair<NSEvent*,NSEvent*> click = - cocoa_test_event_utils::MouseClickInView(button_, 1); - [NSApp postEvent:click.second atStart:YES]; - [button_ mouseDown:click.first]; - EXPECT_EQ(IDC_RELOAD, [button_ tag]); - EXPECT_TRUE([button_ isEnabled]); - - // Get back to stop mode. - [button_ setIsLoading:YES force:YES]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - EXPECT_TRUE([button_ isEnabled]); - - // If hover prevented reload mode immediately taking effect, clicks should do - // nothing, because the button should be disabled. - MouseEnter(); - EXPECT_TRUE(IsMouseInside()); - [button_ setIsLoading:NO force:NO]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - EXPECT_FALSE([button_ isEnabled]); - [NSApp postEvent:click.second atStart:YES]; - [button_ mouseDown:click.first]; - EXPECT_EQ(IDC_STOP, [button_ tag]); - - [button_ setTarget:nil]; -} - -TEST_F(ReloadButtonCocoaTest, RightClickMenu) { - base::scoped_nsobject<MenuTestObserver> observer( - [[MenuTestObserver alloc] initWithMenu:[button_ menuForTesting]]); - [observer setCloseAfterOpening:YES]; - - // When the menu is enabled, it should open on right click only. - [button_ setMenuEnabled:YES]; - - NSEvent* event = cocoa_test_event_utils::LeftMouseDownAtPoint(NSZeroPoint); - [button_ performClick:event]; - EXPECT_FALSE([observer didOpen]); - - event = cocoa_test_event_utils::RightMouseDownAtPoint(NSZeroPoint); - [button_ rightMouseDown:event]; - EXPECT_TRUE([observer didOpen]); - - [observer setDidOpen:NO]; - - // If the menu is disabled, nothing should happen. - event = cocoa_test_event_utils::RightMouseDownAtPoint(NSZeroPoint); - [button_ setMenuEnabled:NO]; - [button_ rightMouseDown:event]; - EXPECT_FALSE([observer didOpen]); -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h deleted file mode 100644 index 4e314037..0000000 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright (c) 2011 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_COCOA_TOOLBAR_TOOLBAR_BUTTON_COCOA_H_ -#define CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_BUTTON_COCOA_H_ - -#import <Cocoa/Cocoa.h> - -#import "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/themed_window.h" -#import "ui/gfx/color_utils.h" - -namespace gfx { -struct VectorIcon; -} - -enum class ToolbarButtonImageBackgroundStyle { - DEFAULT, - HOVER, - HOVER_THEMED, - PRESSED, - PRESSED_THEMED, -}; - -// NSButton subclass which handles middle mouse clicking. -@interface ToolbarButtonCocoa : NSButton<ThemedWindowDrawing> { - @protected - // The toolbar button's image, as assigned by setImage:. - base::scoped_nsobject<NSImage> image_; - - // YES when middle mouse clicks should be handled. - BOOL handleMiddleClick_; -} - -// Return the size of toolbar buttons. -+ (NSSize)toolbarButtonSize; -// Whether or not to handle the mouse middle click events. -@property(assign, nonatomic) BOOL handleMiddleClick; -// Whether this button should mirror in RTL. Defaults to YES. -@property(assign, nonatomic, readonly) BOOL shouldMirrorInRTL; -// Override point for subclasses to return their vector icon. -- (const gfx::VectorIcon*)vectorIcon; -// Override point for subclasses to return their vector icon color. -- (SkColor)vectorIconColor:(BOOL)themeIsDark; -// When in Material Design mode, sets the images for each of the -// ToolbarButtonCocoa's states from the specified image. -- (void)setImage:(NSImage*)anImage; -// Resets the images for each of the ToolbarButtonCocoa's states from its vector -// icon id or its main image. Should only be called when in Material Design -// mode. -- (void)resetButtonStateImages; -@end - -@interface ToolbarButtonCocoa (ExposedForTesting) -- (BOOL)shouldHandleEvent:(NSEvent*)theEvent; -@end - -#endif // CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_BUTTON_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm deleted file mode 100644 index ba42b98..0000000 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm +++ /dev/null
@@ -1,399 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h" - -#include "base/mac/foundation_util.h" -#include "base/mac/sdk_forward_declarations.h" -#include "chrome/app/vector_icons/vector_icons.h" -#import "chrome/browser/ui/cocoa/image_button_cell.h" -#import "chrome/browser/ui/cocoa/l10n_util.h" -#import "chrome/browser/ui/cocoa/view_id_util.h" -#include "components/vector_icons/vector_icons.h" -#include "skia/ext/skia_utils_mac.h" -#import "ui/base/cocoa/nsview_additions.h" -#include "ui/base/material_design/material_design_controller.h" -#include "ui/base/theme_provider.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/image/image_skia_util_mac.h" -#include "ui/gfx/paint_vector_icon.h" - -namespace { - -// Toolbar buttons are 24x24 in Material Design. -const NSRect kMDButtonBounds = NSMakeRect(0, 0, 24, 24); - -// The size of a toolbar button icon in Material Design. A toolbar button image -// consists of a border and background, with a centered icon. -const NSSize kMDButtonIconSize = NSMakeSize(16, 16); - -} // namespace - -// An NSCustomImageRep subclass that creates the "three dots" image of the -// Material Design browser tools icon. -@interface BrowserToolsImageRep : NSCustomImageRep -@property (retain, nonatomic) NSColor* fillColor; -// NSCustomImageRep delegate method that performs the drawing. -+ (void)drawBrowserToolsIcon:(BrowserToolsImageRep*)imageRep; -@end - -@implementation BrowserToolsImageRep - -@synthesize fillColor = fillColor_; - -- (void)dealloc { - [fillColor_ release]; - [super dealloc]; -} - -+ (void)drawBrowserToolsIcon:(BrowserToolsImageRep*)imageRep { - [imageRep.fillColor set]; - NSBezierPath* dotPath = - [NSBezierPath bezierPathWithOvalInRect:NSMakeRect(6.5, 1.5, 3, 3)]; - CGContextRef context = static_cast<CGContextRef>( - [[NSGraphicsContext currentContext] graphicsPort]); - // Draw the three dots by drawing |dotPath| in three different locations. - for (NSUInteger i = 0; i < 3; i++) { - [dotPath fill]; - CGContextTranslateCTM(context, 0, 5); - } -} - -@end - -// An NSCustomImageRep subclass that draws a Material Design background behind -// and border around a centered icon image. -@interface ToolbarButtonImageRep : NSCustomImageRep -@property (retain, nonatomic) NSImage* icon; -@property (assign, nonatomic) ToolbarButtonImageBackgroundStyle style; -// NSCustomImageRep delegate method that performs the drawing. -+ (void)drawImage:(ToolbarButtonImageRep*)imageRep; -@end - -@implementation ToolbarButtonImageRep - -@synthesize icon = icon_; -@synthesize style = style_; - -- (void)dealloc { - [icon_ release]; - [super dealloc]; -} - -+ (void)drawImage:(ToolbarButtonImageRep*)imageRep { - ToolbarButtonImageBackgroundStyle displayStyle = [imageRep style]; - - // Non-default styles draw a background. - if (displayStyle != ToolbarButtonImageBackgroundStyle::DEFAULT) { - // Create the path used for the background fill. - const int kCornerRadius = 2; - NSBezierPath* roundedRectPath = - [NSBezierPath bezierPathWithRoundedRect:kMDButtonBounds - xRadius:kCornerRadius - yRadius:kCornerRadius]; - - // Determine the fill color. - NSColor* fillColor = nil; - const CGFloat kEightPercentAlpha = 0.08; - const CGFloat kTwelvePercentAlpha = 0.12; - const CGFloat kSixteenPercentAlpha = 0.16; - switch (displayStyle) { - case ToolbarButtonImageBackgroundStyle::HOVER: - fillColor = [NSColor colorWithCalibratedWhite:0 - alpha:kEightPercentAlpha]; - break; - case ToolbarButtonImageBackgroundStyle::HOVER_THEMED: - fillColor = [NSColor colorWithCalibratedWhite:1 - alpha:kTwelvePercentAlpha]; - break; - case ToolbarButtonImageBackgroundStyle::PRESSED: - fillColor = [NSColor colorWithCalibratedWhite:0 - alpha:kTwelvePercentAlpha]; - break; - case ToolbarButtonImageBackgroundStyle::PRESSED_THEMED: - fillColor = [NSColor colorWithCalibratedWhite:1 - alpha:kSixteenPercentAlpha]; - break; - case ToolbarButtonImageBackgroundStyle::DEFAULT: - NOTREACHED(); - } - - // Fill the path. - [fillColor set]; - [roundedRectPath fill]; - } - - // Center the icon within the button. - NSSize iconSize = [imageRep.icon size]; - CGFloat iconInset = (kMDButtonBounds.size.width - iconSize.width) / 2; - NSRect iconDestRect = NSInsetRect(kMDButtonBounds, iconInset, iconInset); - [imageRep.icon drawInRect:iconDestRect - fromRect:NSZeroRect - operation:NSCompositeSourceOver - fraction:1]; -} - -@end - -@interface ToolbarButtonCocoa () -// Returns an image that draws the browser tools button icon using vector -// commands. -- (NSImage*)browserToolsIconForFillColor:(SkColor)fillColor; -// Returns an button image by combining |iconImage| with the specified button -// background. -- (NSImage*)imageForIcon:(NSImage*)iconImage - withBackgroundStyle:(ToolbarButtonImageBackgroundStyle)style; -// Implemented to set the button's icon when added to the browser window. We -// can't set the image before this because its appearance depends upon the -// browser window's theme. -- (void)viewDidMoveToWindow; - -@end - -@implementation ToolbarButtonCocoa - -@synthesize handleMiddleClick = handleMiddleClick_; - -+ (NSSize)toolbarButtonSize { - return kMDButtonBounds.size; -} - -- (void)otherMouseDown:(NSEvent*)theEvent { - if (![self shouldHandleEvent:theEvent]) { - [super otherMouseDown:theEvent]; - return; - } - - NSEvent* nextEvent = theEvent; - BOOL isInside; - - // Loop until middle button is released. Also, the mouse cursor is outside of - // the button, the button should not be highlighted. - do { - NSPoint mouseLoc = [self convertPoint:[nextEvent locationInWindow] - fromView:nil]; - isInside = [self mouse:mouseLoc inRect:[self bounds]]; - [self highlight:isInside]; - [self setState:isInside ? NSOnState : NSOffState]; - - NSUInteger mask = NSOtherMouseDraggedMask | NSOtherMouseUpMask; - nextEvent = [[self window] nextEventMatchingMask:mask]; - } while (!([nextEvent buttonNumber] == 2 && - [nextEvent type] == NSOtherMouseUp)); - - // Discard the events before the middle button up event. - // If we don't discard it, the events will be re-processed later. - [[self window] discardEventsMatchingMask:NSAnyEventMask - beforeEvent:nextEvent]; - - [self highlight:NO]; - [self setState:NSOffState]; - if (isInside) - [self sendAction:[self action] to:[self target]]; -} - -- (BOOL)shouldHandleEvent:(NSEvent*)theEvent { - // |buttonNumber| is the mouse button whose action triggered theEvent. - // 2 corresponds to the middle mouse button. - return handleMiddleClick_ && [theEvent buttonNumber] == 2; -} - -- (BOOL)shouldMirrorInRTL { - return YES; -} - -- (void)drawFocusRingMask { - // Match the hover image's bezel. - [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect([self bounds], 2, 2) - xRadius:2 - yRadius:2] fill]; -} - -- (const gfx::VectorIcon*)vectorIcon { - switch ([self viewID]) { - case VIEW_ID_BACK_BUTTON: - return &vector_icons::kBackArrowIcon; - case VIEW_ID_FORWARD_BUTTON: - return &vector_icons::kForwardArrowIcon; - case VIEW_ID_HOME_BUTTON: - return &kNavigateHomeIcon; - case VIEW_ID_APP_MENU: - return &kBrowserToolsIcon; - default: - break; - } - - return nullptr; -} - -- (SkColor)vectorIconColor:(BOOL)themeIsDark { - const ui::ThemeProvider* provider = [[self window] themeProvider]; - return themeIsDark ? SK_ColorWHITE - : (provider && provider->ShouldIncreaseContrast() - ? SK_ColorBLACK - : gfx::kChromeIconGrey); -} - -- (NSImage*)browserToolsIconForFillColor:(SkColor)fillColor { - // Create a |BrowserToolsImageRep| to draw the browser tools icon using - // the provided fill color. - base::scoped_nsobject<BrowserToolsImageRep> imageRep( - [[BrowserToolsImageRep alloc] - initWithDrawSelector:@selector(drawBrowserToolsIcon:) - delegate:[BrowserToolsImageRep class]]); - [imageRep setFillColor:skia::SkColorToSRGBNSColor(fillColor)]; - - // Create the image from the image rep. - NSImage* browserToolsIcon = - [[[NSImage alloc] initWithSize:kMDButtonIconSize] autorelease]; - [browserToolsIcon setCacheMode:NSImageCacheAlways]; - [browserToolsIcon addRepresentation:imageRep]; - - return browserToolsIcon; -} - -- (NSImage*)imageForIcon:(NSImage*)iconImage - withBackgroundStyle:(ToolbarButtonImageBackgroundStyle)style { - // Create a |ToolbarButtonImageRep| to draw the button image using - // the provided icon and background style. - base::scoped_nsobject<ToolbarButtonImageRep> imageRep( - [[ToolbarButtonImageRep alloc] - initWithDrawSelector:@selector(drawImage:) - delegate:[ToolbarButtonImageRep class]]); - [imageRep setIcon:iconImage]; - [imageRep setStyle:style]; - - // Create the image from the image rep. - NSImage* image = - [[[NSImage alloc] initWithSize:kMDButtonBounds.size] autorelease]; - [image setCacheMode:NSImageCacheAlways]; - [image addRepresentation:imageRep]; - - return image; -} - -- (NSImage*)image { - // setImage: stores the image in an ivar. - return image_.get(); -} - -- (void)setImage:(NSImage*)anImage { - // We want to set the default image as the image for kDefaultState. Setting it - // as the default image (via setImage:) can cause ghosting from the two - // default images being drawn over each other. However we also need to keep - // the default image around for resetButtonStateImages, so stick it in an - // ivar. - image_.reset([anImage retain]); - [self resetButtonStateImages]; -} - -- (void)resetButtonStateImages { - NSImage* normalIcon = nil; - NSImage* disabledIcon = nil; - BOOL isDarkTheme = NO; - - const gfx::VectorIcon* icon = [self vectorIcon]; - if (!icon) { - // If the button does not have a vector icon (e.g. it's an extension - // button), use its image. The hover, etc. images will be created using - // imageForIcon:withBackgroundStyle: so do the same for the default image. - // If we don't do this, the icon may not appear in the same place as in the - // other states, causing the icon to appear to shift as you mouse over the - // button. - NSImage* defaultImage = - [self imageForIcon:[self image] - withBackgroundStyle:ToolbarButtonImageBackgroundStyle::DEFAULT]; - normalIcon = disabledIcon = defaultImage; - } else { - // Compute the normal and disabled vector icon colors. - isDarkTheme = [[self window] hasDarkTheme]; - const SkColor vectorIconColor = [self vectorIconColor:isDarkTheme]; - CGFloat normalAlpha = isDarkTheme ? 0xCC : 0xFF; - const SkColor normalColor = SkColorSetA(vectorIconColor, normalAlpha); - const SkColor disabledColor = SkColorSetA(vectorIconColor, 0x33); - - // Create the normal and disabled state icons. These icons are always the - // same shape but use a different color. - if (icon == &kBrowserToolsIcon) { - normalIcon = [self browserToolsIconForFillColor:normalColor]; - disabledIcon = [self browserToolsIconForFillColor:disabledColor]; - } else { - BOOL shouldMirror = cocoa_l10n_util::ShouldDoExperimentalRTLLayout() && - self.shouldMirrorInRTL; - normalIcon = NSImageFromImageSkia( - gfx::CreateVectorIcon(*icon, - kMDButtonIconSize.width, - normalColor)); - if (shouldMirror) - normalIcon = cocoa_l10n_util::FlippedImage(normalIcon); - // The home button has no icon for its disabled state. - if (icon != &vector_icons::kReloadIcon) { - disabledIcon = NSImageFromImageSkia( - gfx::CreateVectorIcon(*icon, - kMDButtonIconSize.width, - disabledColor)); - if (shouldMirror) - disabledIcon = cocoa_l10n_util::FlippedImage(disabledIcon); - } - } - } - - ImageButtonCell* theCell = base::mac::ObjCCast<ImageButtonCell>([self cell]); - // Set the image for the default state, which is just the icon. - [theCell setImage:normalIcon forButtonState:image_button_cell::kDefaultState]; - - // Determine the appropriate image background style for the hover and pressed - // states. - ToolbarButtonImageBackgroundStyle hoverStyle = - ToolbarButtonImageBackgroundStyle::HOVER; - ToolbarButtonImageBackgroundStyle pressedStyle = - ToolbarButtonImageBackgroundStyle::PRESSED; - - // Use the themed style for custom themes and Incognito mode. - const ui::ThemeProvider* themeProvider = [[self window] themeProvider]; - bool incongitoMode = themeProvider && themeProvider->InIncognitoMode(); - if (isDarkTheme || incongitoMode) { - hoverStyle = ToolbarButtonImageBackgroundStyle::HOVER_THEMED; - pressedStyle = ToolbarButtonImageBackgroundStyle::PRESSED_THEMED; - } - - // Create and set the hover state image. - NSImage* hoverImage = - [self imageForIcon:normalIcon withBackgroundStyle:hoverStyle]; - [theCell setImage:hoverImage - forButtonState:image_button_cell::kHoverState]; - - // Create and set the pressed state image. - NSImage* pressedImage = - [self imageForIcon:normalIcon withBackgroundStyle:pressedStyle]; - [theCell setImage:pressedImage - forButtonState:image_button_cell::kPressedState]; - - // Set the disabled state image. - [theCell setImage:disabledIcon - forButtonState:image_button_cell::kDisabledState]; - - [self setNeedsDisplay:YES]; -} - -- (void)viewDidMoveToWindow { - // In Material Design we want to catch when the button is attached to its - // window so that we can configure its appearance based on the window's - // theme. - if ([self window]) { - [self resetButtonStateImages]; - } -} - -// ThemedWindowDrawing implementation. - -- (void)windowDidChangeTheme { - // Update the hover and pressed image backgrounds to match the current theme. - [self resetButtonStateImages]; -} - -- (void)windowDidChangeActive { -} - -@end
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm deleted file mode 100644 index c504348e..0000000 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_unittest.mm +++ /dev/null
@@ -1,312 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import <Cocoa/Cocoa.h> - -#import "base/mac/scoped_nsobject.h" -#include "chrome/app/chrome_command_ids.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h" -#import "testing/gtest_mac.h" -#import "ui/events/test/cocoa_test_event_utils.h" - -@interface TestableToolbarButton : ToolbarButtonCocoa { - @private - NSInteger numOfClick_; - NSInteger lastCommand_; -} - -@property(assign, nonatomic) NSInteger numOfClick; -@property(assign, nonatomic) NSInteger lastCommand; - -- (id)initWithFrame:(NSRect)frame; -- (void)doAction:(id)sender; -@end - -@implementation TestableToolbarButton - -@synthesize numOfClick = numOfClick_; -@synthesize lastCommand = lastCommand_; - -- (id)initWithFrame:(NSRect)frame { - if ((self = [super initWithFrame:frame])) { - lastCommand_ = IDC_STOP; - } - return self; -} - -- (void)doAction:(id)sender { - lastCommand_ = [sender tag]; - if (lastCommand_ == [self tag]) - ++numOfClick_; -} - -- (BOOL)shouldHandleEvent:(NSEvent*)theEvent { - return handleMiddleClick_; -} - -@end - -namespace { - -class ToolbarButtonTest : public CocoaTest { - public: - ToolbarButtonTest() { - NSRect frame = NSMakeRect(0, 0, 20, 20); - base::scoped_nsobject<TestableToolbarButton> button( - [[TestableToolbarButton alloc] initWithFrame:frame]); - button_ = button.get(); - - [button_ setTag:IDC_HOME]; - [button_ setTarget:button_]; - [button_ setAction:@selector(doAction:)]; - [[test_window() contentView] addSubview:button_]; - - NSRect bounds = [button_ bounds]; - NSPoint mid_point = NSMakePoint(NSMidX(bounds), NSMidY(bounds)); - NSPoint out_point = NSMakePoint(bounds.origin.x - 10, - bounds.origin.y - 10); - left_down_in_view = - cocoa_test_event_utils::MouseEventAtPoint(mid_point, - NSLeftMouseDown, - 0); - left_up_in_view = - cocoa_test_event_utils::MouseEventAtPoint(mid_point, - NSLeftMouseUp, - 0); - right_down_in_view = - cocoa_test_event_utils::MouseEventAtPoint(mid_point, - NSRightMouseDown, - 0); - right_up_in_view = - cocoa_test_event_utils::MouseEventAtPoint(mid_point, - NSRightMouseUp, - 0); - other_down_in_view = - cocoa_test_event_utils::MouseEventAtPoint(mid_point, - NSOtherMouseDown, - 0); - other_dragged_in_view = - cocoa_test_event_utils::MouseEventAtPoint(mid_point, - NSOtherMouseDragged, - 0); - other_up_in_view = - cocoa_test_event_utils::MouseEventAtPoint(mid_point, - NSOtherMouseUp, - 0); - other_down_out_view = - cocoa_test_event_utils::MouseEventAtPoint(out_point, - NSOtherMouseDown, - 0); - other_dragged_out_view = - cocoa_test_event_utils::MouseEventAtPoint(out_point, - NSOtherMouseDragged, - 0); - other_up_out_view = - cocoa_test_event_utils::MouseEventAtPoint(out_point, - NSOtherMouseUp, - 0); - } - - TestableToolbarButton* button_; - NSEvent* left_down_in_view; - NSEvent* left_up_in_view; - NSEvent* right_down_in_view; - NSEvent* right_up_in_view; - NSEvent* other_down_in_view; - NSEvent* other_dragged_in_view; - NSEvent* other_up_in_view; - NSEvent* other_down_out_view; - NSEvent* other_dragged_out_view; - NSEvent* other_up_out_view; -}; - -TEST_VIEW(ToolbarButtonTest, button_) - -TEST_F(ToolbarButtonTest, DoesNotSwallowClicksOnNO) { - // Middle button being down doesn't swallow right button clicks. But - // ToolbarButtonCocoa doesn't handle right button events. - [button_ otherMouseDown:other_down_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ rightMouseDown:right_down_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ rightMouseUp:right_up_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); - [button_ otherMouseUp:other_up_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); - - // Middle button being down doesn't swallows left button clicks. - [button_ otherMouseDown:other_down_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [NSApp postEvent:left_up_in_view atStart:YES]; - [button_ mouseDown:left_down_in_view]; - EXPECT_EQ(1, [button_ numOfClick]); - EXPECT_EQ(IDC_HOME, [button_ lastCommand]); - [button_ otherMouseUp:other_up_in_view]; - EXPECT_EQ(1, [button_ numOfClick]); - EXPECT_EQ(IDC_HOME, [button_ lastCommand]); -} - -TEST_F(ToolbarButtonTest, WithoutMouseDownOnNO) { - // Middle button mouse up without leading mouse down in the view. - [button_ otherMouseUp:other_up_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); - - // Middle button mouse dragged in the view and up without leading mouse down. - [button_ otherMouseDragged:other_dragged_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseUp:other_up_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); -} - -TEST_F(ToolbarButtonTest, MouseClickOnNO) { - // Middle button clicking in the view. - [button_ otherMouseDown:other_down_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseUp:other_up_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); - - // Middle button clicking outside of the view. - [button_ otherMouseDown:other_down_out_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseUp:other_up_out_view]; - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); -} - -TEST_F(ToolbarButtonTest, MouseDraggingOnNO) { - // Middle button being down in the view and up outside of the view. - [button_ otherMouseDown:other_down_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseDragged:other_dragged_out_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseUp:other_up_out_view]; - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); - - // Middle button being down on the button, move to outside and move on it - // again, then up on the button. - [button_ otherMouseDown:other_down_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseDragged:other_dragged_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseUp:other_up_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); -} - -TEST_F(ToolbarButtonTest, WithoutMouseDownOnYES) { - // Enable middle button handling. - [button_ setHandleMiddleClick:YES]; - - // Middle button mouse up without leading mouse down in the view. - [button_ otherMouseUp:other_up_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); - - // Middle button mouse dragged in the view and up without leading mouse down. - [button_ otherMouseDragged:other_dragged_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - [button_ otherMouseUp:other_up_in_view]; - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); -} - -TEST_F(ToolbarButtonTest, MouseClickInsideOnYES) { - // Enable middle button handling. - [button_ setHandleMiddleClick:YES]; - - // Middle button clicking in the view. - [NSApp postEvent:other_up_in_view atStart:YES]; - [button_ otherMouseDown:other_down_in_view]; - - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(1, [button_ numOfClick]); - EXPECT_EQ(IDC_HOME, [button_ lastCommand]); -} - -TEST_F(ToolbarButtonTest, MouseClickOutsideOnYES) { - // Enable middle button handling. - [button_ setHandleMiddleClick:YES]; - - // Middle button clicking outside of the view. - [NSApp postEvent:other_up_out_view atStart:YES]; - [button_ otherMouseDown:other_down_out_view]; - - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); -} - -TEST_F(ToolbarButtonTest, MouseDraggingOnYES) { - // Enable middle button handling. - [button_ setHandleMiddleClick:YES]; - - // Middle button being down in the view and up outside of the view. - [NSApp postEvent:other_up_out_view atStart:YES]; - [NSApp postEvent:other_dragged_out_view atStart:YES]; - [button_ otherMouseDown:other_down_in_view]; - - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(0, [button_ numOfClick]); - EXPECT_EQ(IDC_STOP, [button_ lastCommand]); - - // Middle button being down on the button, move to outside and move on it - // again, then up on the button. - [NSApp postEvent:other_up_in_view atStart:YES]; - [NSApp postEvent:other_dragged_in_view atStart:YES]; - [NSApp postEvent:other_dragged_out_view atStart:YES]; - [button_ otherMouseDown:other_down_in_view]; - - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(1, [button_ numOfClick]); - EXPECT_EQ(IDC_HOME, [button_ lastCommand]); -} - -TEST_F(ToolbarButtonTest, DoesSwallowRightClickOnYES) { - // Enable middle button handling. - [button_ setHandleMiddleClick:YES]; - - // Middle button being down should swallow right button clicks. - [NSApp postEvent:other_up_in_view atStart:YES]; - [NSApp postEvent:right_up_in_view atStart:YES]; - [NSApp postEvent:right_down_in_view atStart:YES]; - [button_ otherMouseDown:other_down_in_view]; - - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(1, [button_ numOfClick]); - EXPECT_EQ(IDC_HOME, [button_ lastCommand]); -} - -TEST_F(ToolbarButtonTest, DoesSwallowLeftClickOnYES) { - // Enable middle button handling. - [button_ setHandleMiddleClick:YES]; - - // Middle button being down swallows left button clicks. - [NSApp postEvent:other_up_in_view atStart:YES]; - [NSApp postEvent:left_up_in_view atStart:YES]; - [NSApp postEvent:left_down_in_view atStart:YES]; - [button_ otherMouseDown:other_down_in_view]; - - EXPECT_EQ(NSOffState, [button_ state]); - EXPECT_EQ(1, [button_ numOfClick]); - EXPECT_EQ(IDC_HOME, [button_ lastCommand]); -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h deleted file mode 100644 index 27e38c4..0000000 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h +++ /dev/null
@@ -1,190 +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 CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_CONTROLLER_H_ -#define CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_CONTROLLER_H_ - -#import <Cocoa/Cocoa.h> - -#include <memory> - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/has_weak_browser_pointer.h" -#import "chrome/browser/ui/cocoa/url_drop_target.h" -#import "chrome/browser/ui/cocoa/view_resizer.h" -#include "components/prefs/pref_member.h" -#import "ui/base/cocoa/tracking_area.h" - -@class BackForwardMenuController; -class Browser; -class CommandUpdater; -class LocationBarViewMac; -@class MenuButton; -class Profile; -@class ReloadButtonCocoa; -@class ToolbarButtonCocoa; -@class ToolbarViewCocoa; - -namespace content { -class WebContents; -} - -namespace ToolbarControllerInternal { -class CommandObserverBridge; -class NotificationBridge; -} - -// A controller for the toolbar in the browser window. Manages -// updating the state for location bar and back/fwd/reload/go buttons. -// Manages the bookmark bar and its position in the window relative to -// the web content view. - -@interface ToolbarController - : NSViewController<URLDropTargetController, HasWeakBrowserPointer> { - @protected - // The ordering is important for unit tests. If new items are added or the - // ordering is changed, make sure to update |-toolbarViews| and the - // corresponding enum in the unit tests. - IBOutlet MenuButton* backButton_; - IBOutlet MenuButton* forwardButton_; - IBOutlet ReloadButtonCocoa* reloadButton_; - IBOutlet ToolbarButtonCocoa* homeButton_; - IBOutlet MenuButton* appMenuButton_; - IBOutlet id locationBar_; - IBOutlet id browserActionsContainerView_; - - @private - CommandUpdater* commands_; // weak, one per window - Profile* profile_; // weak, one per window - Browser* browser_; // weak, one per window - std::unique_ptr<ToolbarControllerInternal::CommandObserverBridge> - commandObserver_; - std::unique_ptr<LocationBarViewMac> locationBarView_; - base::scoped_nsobject<BackForwardMenuController> backMenuController_; - base::scoped_nsobject<BackForwardMenuController> forwardMenuController_; - - // Used for monitoring the optional toolbar button prefs. - std::unique_ptr<ToolbarControllerInternal::NotificationBridge> - notificationBridge_; - BooleanPrefMember showHomeButton_; - BOOL hasToolbar_; // If NO, we may have only the location bar. - BOOL hasLocationBar_; // If |hasToolbar_| is YES, this must also be YES. - BOOL locationBarAtMinSize_; // If the location bar is at the minimum size. - - // Tracking area for mouse enter/exit/moved in the toolbar. - ui::ScopedCrTrackingArea trackingArea_; - - // We retain/release the hover button since interaction with the - // button may make it go away (e.g. delete menu option over a - // bookmark button). Thus this variable is not weak. The - // hoveredButton_ is required to have an NSCell that responds to - // setMouseInside:animate:. - NSButton* hoveredButton_; -} - -// Return the inset needed to center a toolbar button's icon within the 28x28 -// design area defined by Material Design. -+ (CGFloat)materialDesignButtonInset; - -// Initialize the toolbar and register for command updates. The profile is -// needed for initializing the location bar. The browser is needed for -// the toolbar model and back/forward menus. -- (id)initWithCommands:(CommandUpdater*)commands - profile:(Profile*)profile - browser:(Browser*)browser; - -// Strongly typed controlled view. -- (ToolbarViewCocoa*)toolbarView; - -// Get the C++ bridge object representing the location bar for this tab. -- (LocationBarViewMac*)locationBarBridge; - -// Called by the Window delegate so we can provide a custom field editor if -// needed. -// Note that this may be called for objects unrelated to the toolbar. -// returns nil if we don't want to override the custom field editor for |obj|. -- (id)customFieldEditorForObject:(id)obj; - -// Called by the |locationBar_| when it has been added to its window. -- (void)locationBarWasAddedToWindow; - -// Return YES if the location bar is the first responder. -- (BOOL)locationBarHasFocus; - -// Make the location bar the first responder, if possible. -- (void)focusLocationBar:(BOOL)selectAll; - -// Called by CommandObserverBridge when there is a state change for the given -// command. -- (void)enabledStateChangedForCommand:(int)command enabled:(bool)enabled; - -// Forces the toolbar (and transitively the location bar) to update its current -// state. If |tab| is non-NULL, we're switching (back?) to this tab and should -// restore any previous location bar state (such as user editing) as well. -- (void)updateToolbarWithContents:(content::WebContents*)tab; - -// Resets the state for |tab|. -- (void)resetTabState:(content::WebContents*)tab; - -// Sets whether or not the current page in the frontmost tab is bookmarked. -- (void)setStarredState:(BOOL)isStarred; - -// Sets whether or not the current page is translated. -- (void)setTranslateIconLit:(BOOL)on; - -// Happens when the zoom for the active tab changes, the active tab switches, or -// a new tab or browser window is created. |canShowBubble| indicates if it is -// appropriate to show a zoom bubble for the change. -- (void)zoomChangedForActiveTab:(BOOL)canShowBubble; - -// Called to update the loading state. Handles updating the go/stop -// button state. |force| is set if the update is due to changing -// tabs, as opposed to the page-load finishing. See comment in -// reload_button_cocoa.h. -- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force; - -// Allow turning off the toolbar (but we may keep the location bar without a -// surrounding toolbar). If |toolbar| is YES, the value of |hasLocationBar| is -// ignored. This changes the behavior of other methods, like |-view|. -- (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar; - -// Point on the star icon for the bookmark bubble to be - in the -// associated window's coordinate system. -- (NSPoint)bookmarkBubblePoint; - -// Point in the window's coordinate system for bubbles attached to the app menu. -- (NSPoint)appMenuBubblePoint; - -// Returns the desired toolbar height for the given compression factor. -- (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight; - -// Set the opacity of the divider (the line at the bottom) *if* we have a -// |ToolbarViewCocoa| (0 means don't show it); no-op otherwise. -- (void)setDividerOpacity:(CGFloat)opacity; - -// Updates the visibility of the toolbar, with an optional animation. -- (void)updateVisibility:(BOOL)visible withAnimation:(BOOL)animate; - -// Returns the app menu button. -- (NSButton*)appMenuButton; - -// Returns true of the location bar is focused. -- (BOOL)isLocationBarFocused; - -@end - -// A set of private methods used by tests, in the absence of "friends" in ObjC. -@interface ToolbarController(PrivateTestMethods) -// Returns an array of views in the order of the outlets above. -- (NSArray*)toolbarViews; -- (void)showOptionalHomeButton; -// Return a hover button for the current event. -- (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent; -// Adjusts browser actions container view in response to toolbar frame changes. -// Outside of tests, called in response to frame changed/new window -// notifications. -- (void)toolbarFrameChanged; -@end - -#endif // CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm deleted file mode 100644 index bb8a778..0000000 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm +++ /dev/null
@@ -1,762 +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. - -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" - -#include <algorithm> - -#include "base/mac/bundle_locations.h" -#include "base/mac/foundation_util.h" -#include "base/mac/mac_util.h" -#include "base/mac/sdk_forward_declarations.h" -#include "base/macros.h" -#include "base/memory/singleton.h" -#include "base/strings/string_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/app/chrome_command_ids.h" -#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/command_observer.h" -#include "chrome/browser/command_updater.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/recovery/recovery_install_global_error_factory.h" -#include "chrome/browser/search/search.h" -#include "chrome/browser/themes/theme_service.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_commands.h" -#include "chrome/browser/ui/browser_window.h" -#import "chrome/browser/ui/cocoa/background_gradient_view.h" -#include "chrome/browser/ui/cocoa/drag_util.h" -#import "chrome/browser/ui/cocoa/image_button_cell.h" -#import "chrome/browser/ui/cocoa/l10n_util.h" -#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" -#import "chrome/browser/ui/cocoa/menu_button.h" -#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h" -#import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button_cell.h" -#import "chrome/browser/ui/cocoa/toolbar/back_forward_menu_controller.h" -#import "chrome/browser/ui/cocoa/toolbar/reload_button_cocoa.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h" -#import "chrome/browser/ui/cocoa/view_id_util.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/browser/ui/toolbar/app_menu_icon_controller.h" -#include "chrome/browser/ui/toolbar/app_menu_model.h" -#include "chrome/common/pref_names.h" -#include "chrome/grit/chromium_strings.h" -#include "chrome/grit/generated_resources.h" -#include "components/omnibox/browser/autocomplete_classifier.h" -#include "components/omnibox/browser/autocomplete_match.h" -#include "components/omnibox/browser/omnibox_edit_model.h" -#include "components/omnibox/browser/omnibox_view.h" -#include "components/prefs/pref_service.h" -#include "components/search_engines/template_url_service.h" -#include "components/strings/grit/components_strings.h" -#include "components/url_formatter/url_fixer.h" -#include "content/public/browser/web_contents.h" -#include "third_party/metrics_proto/omnibox_event.pb.h" -#import "ui/base/cocoa/menu_controller.h" -#import "ui/base/cocoa/nsview_additions.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/l10n_util_mac.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/image/image.h" - -using content::OpenURLParams; -using content::Referrer; -using content::WebContents; - -namespace { - -// Duration of the toolbar animation. -const NSTimeInterval kToolBarAnimationDuration = 0.12; - -// The height of the location bar. -const CGFloat kLocationBarHeight = 28; - -// The padding between the top of the toolbar and the top of the -// location bar. -const CGFloat kLocationBarPadding = 2; - -// The padding between elements and the edges of the toolbar. -const CGFloat kElementPadding = 4; - -// Toolbar buttons are 24x24 and centered in a 28x28 space, so there is a 2pt- -// wide inset. -const CGFloat kButtonInset = 2; - -} // namespace - -@interface ToolbarController() -@property(assign, nonatomic) Browser* browser; -// Height of the location bar. Used for animating the toolbar in and out when -// the location bar is displayed stand-alone for bookmark apps. -+ (CGFloat)locationBarHeight; -// Return the amount of horizontal padding that the app menu should have on -// each side. -+ (CGFloat)appMenuPadding; -- (void)cleanUp; -- (void)addAccessibilityDescriptions; -- (void)initCommandStatus:(CommandUpdater*)commands; -- (void)prefChanged:(const std::string&)prefName; -// Height of the toolbar in pixels when the bookmark bar is closed. -- (CGFloat)baseToolbarHeight; -- (void)toolbarFrameChanged; -- (void)maintainMinimumLocationBarWidth; -- (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate; -- (void)updateAppMenuButtonSeverity:(AppMenuIconController::Severity)severity - iconType:(AppMenuIconController::IconType)iconType - animate:(BOOL)animate; -@end - -namespace ToolbarControllerInternal { - -// A C++ bridge class that handles listening for updates to commands and -// passing them back to ToolbarController. ToolbarController will create one of -// these bridges, pass them to CommandUpdater::AddCommandObserver, and then wait -// for update notifications, delivered via -// -enabledStateChangedForCommand:enabled:. -class CommandObserverBridge : public CommandObserver { - public: - explicit CommandObserverBridge(ToolbarController* observer) - : observer_(observer) { - DCHECK(observer_); - } - - protected: - // Overridden from CommandObserver - void EnabledStateChangedForCommand(int command, bool enabled) override { - [observer_ enabledStateChangedForCommand:command enabled:enabled]; - } - - private: - ToolbarController* observer_; // weak, owns me - - DISALLOW_COPY_AND_ASSIGN(CommandObserverBridge); -}; - -// A class registered for C++ notifications. This is used to detect changes in -// preferences and upgrade available notifications. Bridges the notification -// back to the ToolbarController. -class NotificationBridge : public AppMenuIconController::Delegate { - public: - explicit NotificationBridge(ToolbarController* controller) - : controller_(controller), - app_menu_icon_controller_([controller browser]->profile(), this) {} - ~NotificationBridge() override {} - - void UpdateSeverity() { app_menu_icon_controller_.UpdateDelegate(); } - - void UpdateSeverity(AppMenuIconController::IconType type, - AppMenuIconController::Severity severity, - bool animate) override { - [controller_ updateAppMenuButtonSeverity:severity - iconType:type - animate:animate]; - } - - void OnPreferenceChanged(const std::string& pref_name) { - [controller_ prefChanged:pref_name]; - } - - private: - ToolbarController* controller_; // weak, owns us - - AppMenuIconController app_menu_icon_controller_; - - DISALLOW_COPY_AND_ASSIGN(NotificationBridge); -}; - -} // namespace ToolbarControllerInternal - -@implementation ToolbarController - -@synthesize browser = browser_; - -+ (CGFloat)locationBarHeight { - return kLocationBarHeight; -} - -+ (CGFloat)appMenuPadding { - return kElementPadding; -} - -+ (CGFloat)materialDesignButtonInset { - return kButtonInset; -} - -- (id)initWithCommands:(CommandUpdater*)commands - profile:(Profile*)profile - browser:(Browser*)browser { - DCHECK(commands && profile); - if ((self = [super initWithNibName:@"Toolbar" - bundle:base::mac::FrameworkBundle()])) { - commands_ = commands; - profile_ = profile; - browser_ = browser; - hasToolbar_ = YES; - hasLocationBar_ = YES; - - // Register for notifications about state changes for the toolbar buttons - commandObserver_.reset( - new ToolbarControllerInternal::CommandObserverBridge(self)); - - commands->AddCommandObserver(IDC_BACK, commandObserver_.get()); - commands->AddCommandObserver(IDC_FORWARD, commandObserver_.get()); - commands->AddCommandObserver(IDC_RELOAD, commandObserver_.get()); - commands->AddCommandObserver(IDC_HOME, commandObserver_.get()); - commands->AddCommandObserver(IDC_BOOKMARK_PAGE, commandObserver_.get()); - // NOTE: Don't remove the command observers. ToolbarController is - // autoreleased at about the same time as the CommandUpdater (owned by the - // Browser), so |commands_| may not be valid any more. - - // Start global error services now so we badge the menu correctly. - RecoveryInstallGlobalErrorFactory::GetForProfile(profile); - } - return self; -} - -// Called after the view is done loading and the outlets have been hooked up. -// Now we can hook up bridges that rely on UI objects such as the location bar -// and button state. -viewDidLoad is the recommended way to do this in 10.10 -// SDK. When running on 10.10 or above -awakeFromNib still works but for some -// reason is not guaranteed to be called (http://crbug.com/526276), so implement -// both. -- (void)awakeFromNib { - [self viewDidLoadImpl]; -} - -- (void)viewDidLoad { - [self viewDidLoadImpl]; -} - -- (void)viewDidLoadImpl { - // When linking and running on 10.10+, both -awakeFromNib and -viewDidLoad may - // be called, don't initialize twice. - if (locationBarView_) { - DCHECK(base::mac::IsAtLeastOS10_10()); - return; - } - - BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout(); - NSAutoresizingMaskOptions leadingButtonMask = - isRTL ? NSViewMinXMargin | NSViewMinYMargin - : NSViewMaxXMargin | NSViewMinYMargin; - NSAutoresizingMaskOptions trailingButtonMask = - isRTL ? NSViewMaxXMargin | NSViewMinYMargin - : NSViewMinXMargin | NSViewMinYMargin; - - // Make Material Design layout adjustments to the NIB items. - ToolbarViewCocoa* toolbarView = [self toolbarView]; - NSRect toolbarBounds = [toolbarView bounds]; - NSSize toolbarButtonSize = [ToolbarButtonCocoa toolbarButtonSize]; - - // Set the toolbar height. - NSRect frame = [toolbarView frame]; - frame.size.height = [self baseToolbarHeight]; - [toolbarView setFrame:frame]; - - NSArray* leadingButtons = - @[ backButton_, forwardButton_, reloadButton_, homeButton_ ]; - const CGFloat xStart = kElementPadding + kButtonInset; - const CGFloat xOffset = toolbarButtonSize.width + kButtonInset * 2; - const CGFloat yPosition = - NSMaxY(toolbarBounds) - kElementPadding - toolbarButtonSize.height; - for (NSUInteger i = 0; i < [leadingButtons count]; i++) { - NSButton* button = leadingButtons[i]; - NSRect buttonFrame = [button frame]; - buttonFrame.size = toolbarButtonSize; - buttonFrame.origin.y = yPosition; - const CGFloat xPosition = xStart + i * xOffset; - buttonFrame.origin.x = - isRTL ? NSWidth(frame) - toolbarButtonSize.width - xPosition - : xPosition; - [button setFrame:buttonFrame]; - [button setAutoresizingMask:leadingButtonMask]; - } - - // Replace the app button from the nib with an AppToolbarButton instance for - // Material Design. - AppToolbarButton* newMenuButton = - [[[AppToolbarButton alloc] initWithFrame:[appMenuButton_ frame]] - autorelease]; - [newMenuButton setAutoresizingMask:[appMenuButton_ autoresizingMask]]; - [[appMenuButton_ superview] addSubview:newMenuButton]; - [appMenuButton_ removeFromSuperview]; - appMenuButton_ = newMenuButton; - - // Adjust the menu button's position. - NSRect menuButtonFrame = [appMenuButton_ frame]; - if (isRTL) { - menuButtonFrame.origin.x = - [ToolbarController appMenuPadding] + kButtonInset; - } else { - CGFloat menuButtonFrameMaxX = - NSMaxX(toolbarBounds) - [ToolbarController appMenuPadding]; - menuButtonFrame.origin.x = - menuButtonFrameMaxX - kButtonInset - toolbarButtonSize.width; - } - menuButtonFrame.origin.y = yPosition; - menuButtonFrame.size = toolbarButtonSize; - [appMenuButton_ setFrame:menuButtonFrame]; - [appMenuButton_ setAutoresizingMask:trailingButtonMask]; - - // Adjust the size and location on the location bar to take up the - // space between the reload and menu buttons. - NSRect locationBarFrame = [locationBar_ frame]; - locationBarFrame.origin.x = isRTL - ? NSMaxX(menuButtonFrame) + kButtonInset - : NSMaxX([homeButton_ frame]) + kButtonInset; - if (![homeButton_ isHidden] && !isRTL) { - // Ensure proper spacing between the home button and location bar - locationBarFrame.origin.x += kElementPadding; - } - locationBarFrame.origin.y = - NSMaxY(toolbarBounds) - kLocationBarPadding - kLocationBarHeight; - CGFloat rightEdge = 0; - if (isRTL) { - rightEdge = NSMinX([homeButton_ frame]) - kButtonInset; - if (![homeButton_ isHidden]) - rightEdge -= kElementPadding; - } else { - rightEdge = NSMinX(menuButtonFrame); - } - locationBarFrame.size.width = rightEdge - NSMinX(locationBarFrame); - - locationBarFrame.size.height = kLocationBarHeight; - [locationBar_ setFrame:locationBarFrame]; - - notificationBridge_.reset( - new ToolbarControllerInternal::NotificationBridge(self)); - notificationBridge_->UpdateSeverity(); - - [appMenuButton_ setOpenMenuOnClick:YES]; - - [backButton_ setOpenMenuOnRightClick:YES]; - [forwardButton_ setOpenMenuOnRightClick:YES]; - - [backButton_ setHandleMiddleClick:YES]; - [forwardButton_ setHandleMiddleClick:YES]; - [reloadButton_ setHandleMiddleClick:YES]; - [homeButton_ setHandleMiddleClick:YES]; - - [self initCommandStatus:commands_]; - [reloadButton_ setCommandUpdater:commands_]; - - locationBarView_.reset(new LocationBarViewMac(commands_, profile_, browser_)); - - // Register pref observers for the optional home and page/options buttons - // and then add them to the toolbar based on those prefs. - PrefService* prefs = profile_->GetPrefs(); - showHomeButton_.Init( - prefs::kShowHomeButton, prefs, - base::Bind( - &ToolbarControllerInternal::NotificationBridge::OnPreferenceChanged, - base::Unretained(notificationBridge_.get()))); - [self showOptionalHomeButton]; - - // Create the controllers for the back/forward menus. - backMenuController_.reset([[BackForwardMenuController alloc] - initWithBrowser:browser_ - modelType:BACK_FORWARD_MENU_TYPE_BACK - button:backButton_]); - forwardMenuController_.reset([[BackForwardMenuController alloc] - initWithBrowser:browser_ - modelType:BACK_FORWARD_MENU_TYPE_FORWARD - button:forwardButton_]); - - trackingArea_.reset( - [[CrTrackingArea alloc] initWithRect:NSZeroRect // Ignored - options:NSTrackingMouseMoved | - NSTrackingInVisibleRect | - NSTrackingMouseEnteredAndExited | - NSTrackingActiveAlways - owner:self - userInfo:nil]); - NSView* parentView = [self view]; - [parentView addTrackingArea:trackingArea_.get()]; - - // If the user has any Browser Actions installed, the container view for them - // may have to be resized depending on the width of the toolbar frame. - [parentView setPostsFrameChangedNotifications:YES]; - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(toolbarFrameChanged) - name:NSViewFrameDidChangeNotification - object:parentView]; - - // Set ViewIDs for toolbar elements which don't have their dedicated class. - // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and - // |browserActionsContainerView_| are handled by themselves. - view_id_util::SetID(backButton_, VIEW_ID_BACK_BUTTON); - view_id_util::SetID(forwardButton_, VIEW_ID_FORWARD_BUTTON); - view_id_util::SetID(homeButton_, VIEW_ID_HOME_BUTTON); - view_id_util::SetID(appMenuButton_, VIEW_ID_APP_MENU); - - [self addAccessibilityDescriptions]; -} - -- (void)dealloc { - [self cleanUp]; - [super dealloc]; -} - -- (void)browserWillBeDestroyed { - // Clear resize delegate so it doesn't get called during stopAnimation, and - // stop any in-flight animation. - [[self toolbarView] setResizeDelegate:nil]; - [[self toolbarView] stopAnimation]; - - // Pass this call onto other reference counted objects. - [backMenuController_ browserWillBeDestroyed]; - [forwardMenuController_ browserWillBeDestroyed]; - - [self cleanUp]; -} - -- (void)cleanUp { - // Unset ViewIDs of toolbar elements. - // ViewIDs of |toolbarView|, |reloadButton_|, |locationBar_| and - // |browserActionsContainerView_| are handled by themselves. - view_id_util::UnsetID(backButton_); - view_id_util::UnsetID(forwardButton_); - view_id_util::UnsetID(homeButton_); - view_id_util::UnsetID(appMenuButton_); - - // Make sure any code in the base class which assumes [self view] is - // the "parent" view continues to work. - hasToolbar_ = YES; - hasLocationBar_ = YES; - - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - if (trackingArea_.get()) { - [[self view] removeTrackingArea:trackingArea_.get()]; - [trackingArea_.get() clearOwner]; - trackingArea_.reset(); - } - - // Destroy owned objects that hold a weak Browser*. - locationBarView_.reset(); - browser_ = nullptr; -} - -- (void)addAccessibilityDescriptions { - // Set accessibility descriptions. http://openradar.appspot.com/7496255 - NSString* description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_BACK); - [[backButton_ cell] - accessibilitySetOverrideValue:description - forAttribute:NSAccessibilityDescriptionAttribute]; - NSString* helpTag = l10n_util::GetNSStringWithFixup(IDS_ACCDESCRIPTION_BACK); - [[backButton_ cell] - accessibilitySetOverrideValue:helpTag - forAttribute:NSAccessibilityHelpAttribute]; - - description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_FORWARD); - [[forwardButton_ cell] - accessibilitySetOverrideValue:description - forAttribute:NSAccessibilityDescriptionAttribute]; - helpTag = l10n_util::GetNSStringWithFixup(IDS_ACCDESCRIPTION_FORWARD); - [[forwardButton_ cell] - accessibilitySetOverrideValue:helpTag - forAttribute:NSAccessibilityHelpAttribute]; - - description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_RELOAD); - [[reloadButton_ cell] - accessibilitySetOverrideValue:description - forAttribute:NSAccessibilityDescriptionAttribute]; - description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_HOME); - [[homeButton_ cell] - accessibilitySetOverrideValue:description - forAttribute:NSAccessibilityDescriptionAttribute]; - description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_APP); - [[appMenuButton_ cell] - accessibilitySetOverrideValue:description - forAttribute:NSAccessibilityDescriptionAttribute]; -} - -- (void)mouseExited:(NSEvent*)theEvent { - [[hoveredButton_ cell] setIsMouseInside:NO]; - [hoveredButton_ release]; - hoveredButton_ = nil; -} - -- (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent { - NSButton* targetView = (NSButton*)[[self view] - hitTest:[theEvent locationInWindow]]; - - // Only interpret the view as a hoverButton_ if it's both button and has a - // button cell that cares. GradientButtonCell derived cells care. - if (([targetView isKindOfClass:[NSButton class]]) && - ([[targetView cell] - respondsToSelector:@selector(setIsMouseInside:)])) - return targetView; - return nil; -} - -- (void)mouseMoved:(NSEvent*)theEvent { - NSButton* targetView = [self hoverButtonForEvent:theEvent]; - if (hoveredButton_ != targetView) { - [[hoveredButton_ cell] setIsMouseInside:NO]; - [[targetView cell] setIsMouseInside:YES]; - [hoveredButton_ release]; - hoveredButton_ = [targetView retain]; - } -} - -- (void)mouseEntered:(NSEvent*)event { - [self mouseMoved:event]; -} - -- (ToolbarViewCocoa*)toolbarView { - return base::mac::ObjCCastStrict<ToolbarViewCocoa>([self view]); -} - -- (LocationBarViewMac*)locationBarBridge { - return locationBarView_.get(); -} - -- (void)locationBarWasAddedToWindow { -} - -- (BOOL)locationBarHasFocus { - return NO; -} - -- (void)focusLocationBar:(BOOL)selectAll { -} - -// Called when the state for a command changes to |enabled|. Update the -// corresponding UI element. -- (void)enabledStateChangedForCommand:(int)command enabled:(bool)enabled { - NSButton* button = nil; - switch (command) { - case IDC_BACK: - button = backButton_; - break; - case IDC_FORWARD: - button = forwardButton_; - break; - case IDC_HOME: - button = homeButton_; - break; - } - [button setEnabled:enabled]; -} - -// Init the enabled state of the buttons on the toolbar to match the state in -// the controller. -- (void)initCommandStatus:(CommandUpdater*)commands { - [backButton_ setEnabled:commands->IsCommandEnabled(IDC_BACK) ? YES : NO]; - [forwardButton_ - setEnabled:commands->IsCommandEnabled(IDC_FORWARD) ? YES : NO]; - [reloadButton_ setEnabled:YES]; - [homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO]; -} - -- (void)updateToolbarWithContents:(WebContents*)tab { - BOOL needReloadMenu = chrome::IsDebuggerAttachedToCurrentTab(browser_); - [reloadButton_ setMenuEnabled:needReloadMenu]; -} - -- (void)resetTabState:(WebContents*)tab { -} - -- (void)setStarredState:(BOOL)isStarred { -} - -- (void)setTranslateIconLit:(BOOL)on { -} - -- (void)zoomChangedForActiveTab:(BOOL)canShowBubble { -} - -- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force { - [reloadButton_ setIsLoading:isLoading force:force]; -} - -- (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar { - [self view]; // Force nib loading. - - hasToolbar_ = toolbar; - - hasLocationBar_ = NO; - - // Decide whether to hide/show based on whether there's a location bar. - [[self view] setHidden:!toolbar]; -} - -- (id)customFieldEditorForObject:(id)obj { - return nil; -} - -// Returns an array of views, ordered leading to trailing. -- (NSArray*)toolbarViews { - return @[ - backButton_, forwardButton_, reloadButton_, homeButton_, locationBar_, - browserActionsContainerView_, appMenuButton_ - ]; -} - -// Show or hide the home button based on the pref. -- (void)showOptionalHomeButton { - // Ignore this message if only showing the URL bar. - if (!hasToolbar_) - return; - BOOL hide = showHomeButton_.GetValue() ? NO : YES; - if (hide == [homeButton_ isHidden]) - return; // Nothing to do, view state matches pref state. - - [homeButton_ setHidden:hide]; -} - -- (void)updateAppMenuButtonSeverity:(AppMenuIconController::Severity)severity - iconType:(AppMenuIconController::IconType)iconType - animate:(BOOL)animate { - AppToolbarButton* appMenuButton = - base::mac::ObjCCastStrict<AppToolbarButton>(appMenuButton_); - [appMenuButton setSeverity:severity iconType:iconType shouldAnimate:animate]; -} - -- (void)prefChanged:(const std::string&)prefName { - if (prefName == prefs::kShowHomeButton) { - [self showOptionalHomeButton]; - } -} - -- (void)updateVisibility:(BOOL)visible withAnimation:(BOOL)animate { - CGFloat newHeight = visible ? [ToolbarController locationBarHeight] : 0; - - // Perform the animation, which will cause the BrowserWindowController to - // resize this view in the browser layout as required. - if (animate) { - [[self toolbarView] animateToNewHeight:newHeight - duration:kToolBarAnimationDuration]; - } else { - [[self toolbarView] setHeight:newHeight]; - } -} - -- (void)maintainMinimumLocationBarWidth { -} - -- (void)toolbarFrameChanged { -} - -- (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate { -} - -- (NSPoint)bookmarkBubblePoint { - return [self appMenuBubblePoint]; -} - -- (NSPoint)appMenuBubblePoint { - NSRect frame = appMenuButton_.frame; - NSPoint point = NSMakePoint(NSMaxX(frame), NSMinY(frame)); - return [self.view convertPoint:point toView:nil]; -} - -- (CGFloat)baseToolbarHeight { - // Height of the toolbar in pixels when the bookmark bar is closed. - const CGFloat kBaseToolbarHeightNormal = 37; - return kBaseToolbarHeightNormal; -} - -- (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight { - // With no toolbar, just ignore the compression. - if (!hasToolbar_) - return NSHeight([locationBar_ frame]); - - return [self baseToolbarHeight] - compressByHeight; -} - -- (void)setDividerOpacity:(CGFloat)opacity { - ToolbarViewCocoa* toolbarView = [self toolbarView]; - [toolbarView setShowsDivider:(opacity > 0 ? YES : NO)]; - [toolbarView setDividerOpacity:opacity]; - [toolbarView setNeedsDisplay:YES]; -} - -- (NSView*)appMenuButton { - return appMenuButton_; -} - -- (BOOL)isLocationBarFocused { - return NO; -} - -// (URLDropTargetController protocol) -- (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point { - // TODO(viettrungluu): This code is more or less copied from the code in - // |TabStripControllerCocoa|. I'll refactor this soon to make it common and - // expand its capabilities (e.g., allow text DnD). - if ([urls count] < 1) { - NOTREACHED(); - return; - } - - for (NSUInteger index = 0; index < [urls count]; index++) { - // Refactor this code. - // https://crbug.com/665261. - GURL url = url_formatter::FixupURL( - base::SysNSStringToUTF8([urls objectAtIndex:index]), std::string()); - - // If the URL isn't valid, don't bother. - if (!url.is_valid()) - continue; - - // Security: Sanitize text to prevent self-XSS. - if (url.SchemeIs(url::kJavaScriptScheme)) - continue; - - WindowOpenDisposition disposition; - if (index == 0) - disposition = WindowOpenDisposition::CURRENT_TAB; - else - disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; - - OpenURLParams params(url, Referrer(), disposition, - ui::PAGE_TRANSITION_TYPED, false); - browser_->tab_strip_model()->GetActiveWebContents()->OpenURL(params); - } -} - -// (URLDropTargetController protocol) -- (void)dropText:(NSString*)text inView:(NSView*)view at:(NSPoint)point { - // TODO(viettrungluu): This code is more or less copied from the code in - // |TabStripControllerCocoa|. I'll refactor this soon to make it common and - // expand its capabilities (e.g., allow text DnD). - - // If the input is plain text, classify the input and make the URL. - AutocompleteMatch match; - AutocompleteClassifierFactory::GetForProfile(browser_->profile())->Classify( - base::SysNSStringToUTF16(text), false, false, - metrics::OmniboxEventProto::BLANK, &match, NULL); - GURL url(match.destination_url); - - // Security: Block JavaScript to prevent self-XSS. - if (url.SchemeIs(url::kJavaScriptScheme)) - return; - - OpenURLParams params(url, Referrer(), WindowOpenDisposition::CURRENT_TAB, - ui::PAGE_TRANSITION_TYPED, false); - browser_->tab_strip_model()->GetActiveWebContents()->OpenURL(params); -} - -// (URLDropTargetController protocol) -- (void)indicateDropURLsInView:(NSView*)view at:(NSPoint)point { - // Do nothing. -} - -// (URLDropTargetController protocol) -- (void)hideDropURLsIndicatorInView:(NSView*)view { - // Do nothing. -} - -// (URLDropTargetController protocol) -- (BOOL)isUnsupportedDropData:(id<NSDraggingInfo>)info { - return drag_util::IsUnsupportedDropData(profile_, info); -} - -@end
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h b/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h deleted file mode 100644 index 629ba8a5..0000000 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright (c) 2009 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_COCOA_TOOLBAR_TOOLBAR_VIEW_COCOA_H_ -#define CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_VIEW_COCOA_H_ - -#import <Cocoa/Cocoa.h> -#import "chrome/browser/ui/cocoa/animatable_view.h" - -// A view that handles any special rendering of the toolbar bar. At -// this time it only draws a gradient. Future changes (e.g. themes) -// may require new functionality here. - -@interface ToolbarViewCocoa : AnimatableView { - @private - // The opacity of the divider line (at the bottom of the toolbar); used when - // the detached bookmark bar is morphing to the normal bar and vice versa. - CGFloat dividerOpacity_; -} - -@property(assign, nonatomic) CGFloat dividerOpacity; -@end - -#endif // CHROME_BROWSER_UI_COCOA_TOOLBAR_TOOLBAR_VIEW_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.mm deleted file mode 100644 index 94798c3..0000000 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.mm +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h" - -#import "chrome/browser/ui/cocoa/view_id_util.h" -#import "ui/base/cocoa/nsview_additions.h" -#include "ui/base/material_design/material_design_controller.h" - -@implementation ToolbarViewCocoa - -@synthesize dividerOpacity = dividerOpacity_; - -// Prevent mouse down events from moving the parent window around. -- (BOOL)mouseDownCanMoveWindow { - return NO; -} - -- (void)drawRect:(NSRect)dirtyRect { - [self drawBackground:dirtyRect]; -} - -- (BOOL)accessibilityIsIgnored { - return NO; -} - -- (id)accessibilityAttributeValue:(NSString*)attribute { - if ([attribute isEqual:NSAccessibilityRoleAttribute]) - return NSAccessibilityToolbarRole; - - return [super accessibilityAttributeValue:attribute]; -} - -- (ViewID)viewID { - return VIEW_ID_TOOLBAR; -} - -- (BOOL)isOpaque { - return YES; -} - -// ThemedWindowDrawing overrides. - -- (void)windowDidChangeActive { - // Need to redraw the omnibox and toolbar buttons as well. - [self cr_recursivelySetNeedsDisplay:YES]; -} - -@end
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm deleted file mode 100644 index 373c596..0000000 --- a/chrome/browser/ui/cocoa/toolbar/toolbar_view_unittest.mm +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_view_cocoa.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace { - -class ToolbarViewTest : public CocoaTest { -}; - -// This class only needs to do one thing: prevent mouse down events from moving -// the parent window around. -TEST_F(ToolbarViewTest, CanDragWindow) { - base::scoped_nsobject<ToolbarViewCocoa> view([[ToolbarViewCocoa alloc] init]); - EXPECT_FALSE([view mouseDownCanMoveWindow]); -} - -} // namespace
diff --git a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h deleted file mode 100644 index 4e7302e..0000000 --- a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_WEB_CONTENTS_MODAL_DIALOG_MANAGER_VIEWS_MAC_H_ -#define CHROME_BROWSER_UI_COCOA_WEB_CONTENTS_MODAL_DIALOG_MANAGER_VIEWS_MAC_H_ - -#import "base/mac/scoped_nsobject.h" -#include "base/macros.h" -#include "components/web_modal/single_web_contents_dialog_manager.h" -#include "ui/views/widget/widget_observer.h" - -@class NSWindow; -@class WrappedConstrainedWindowSheet; - -// WebContents dialog manager for a toolkit-views dialog parented off a Cocoa -// browser window. Most of the modality behavior is still performed by the Cocoa -// based ConstrainedWindowSheetController. This class bridges the expectations -// of a toolkit-views dialog to the Cocoa ConstrainedWindowSheetController. -// Note that this is not a web_modal::ModalDialogHostObserver. This is because -// tabs in a Cocoa browser can't be dragged off their window if they have a tab- -// modal dialog open, so the ModalDialogHost is only used by the views plumbing -// when creating the dialog. -class SingleWebContentsDialogManagerViewsMac - : public web_modal::SingleWebContentsDialogManager, - public views::WidgetObserver { - public: - SingleWebContentsDialogManagerViewsMac( - NSWindow* dialog, - web_modal::SingleWebContentsDialogManagerDelegate* delegate); - - ~SingleWebContentsDialogManagerViewsMac() override; - - // SingleWebContentsDialogManager: - void Show() override; - void Hide() override; - void Close() override; - void Focus() override; - void Pulse() override; - void HostChanged(web_modal::WebContentsModalDialogHost* new_host) override; - gfx::NativeWindow dialog() override; - - // views::WidgetObserver: - void OnWidgetClosing(views::Widget* widget) override; - void OnWidgetDestroying(views::Widget* widget) override; - - private: - base::scoped_nsobject<WrappedConstrainedWindowSheet> sheet_; - // Weak. Owns this. - web_modal::SingleWebContentsDialogManagerDelegate* delegate_; - // Weak. Owned by parent window. - web_modal::WebContentsModalDialogHost* host_; - - views::Widget* widget_; // Weak. Deletes |this| when closing. - - bool was_shown_ = false; - - DISALLOW_COPY_AND_ASSIGN(SingleWebContentsDialogManagerViewsMac); -}; - -#endif // CHROME_BROWSER_UI_COCOA_WEB_CONTENTS_MODAL_DIALOG_MANAGER_VIEWS_MAC_H_
diff --git a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm deleted file mode 100644 index 9ee9b0e8..0000000 --- a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm +++ /dev/null
@@ -1,208 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h" - -#import <Cocoa/Cocoa.h> - -#import "base/mac/foundation_util.h" -#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h" -#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h" -#include "content/public/browser/web_contents.h" -#include "components/web_modal/web_contents_modal_dialog_host.h" -#import "ui/base/cocoa/constrained_window/constrained_window_animation.h" -#include "ui/views/widget/widget.h" - -// A wrapper for a views::Widget dialog to interact with a Cocoa browser's -// ContrainedWindowSheetController. Similar to CustomConstrainedWindowSheet, but -// since Widgets of dialog type animate themselves, and also manage their own -// parenting, there's not much to do except position properly. -@interface WrappedConstrainedWindowSheet : NSObject<ConstrainedWindowSheet> { - @private - base::scoped_nsobject<NSWindow> customWindow_; -} -- (id)initWithCustomWindow:(NSWindow*)customWindow; -@end - -@implementation WrappedConstrainedWindowSheet - -- (id)initWithCustomWindow:(NSWindow*)customWindow { - if ((self = [super init])) { - customWindow_.reset([customWindow retain]); - } - return self; -} - -// ConstrainedWindowSheet implementation. - -- (void)showSheetForWindow:(NSWindow*)window { - // This is only called for the initial show, then calls go to unhideSheet. - // Since Widget::Show() will be called, just update the position. - [self updateSheetPosition]; -} - -- (void)closeSheetWithAnimation:(BOOL)withAnimation { - // Nothing to do here. Either SingleWebContentsDialogManagerViewsMac::Close() - // was called or Widget::Close(). Both cases ending up in OnWidgetClosing() to - // call [ConstrainedWindowSheetController closeSheet:], which calls this. - // However, the Widget is already closing in those cases. - - // OnWidgetClosing() is also the _only_ trigger. The exception would be - // -[ConstrainedWindowSheetController onParentWindowWillClose:] which also - // calls closeSheetWithAnimation:, but a Widget never gets there because - // WebContentsModalDialogManager::CloseAllDialogs() is triggered from - // -[BrowserWindowController windowShouldClose:], but the notification that - // calls onParentWindowWillClose always happens once that has returned YES. - - // So, since onParentWindowWillClose never calls this, we can assert that - // withAnimation is YES, otherwise there's some code path that might not be - // catered for. - DCHECK(withAnimation); -} - -- (void)hideSheet { - // Hide the sheet window by setting the alpha to 0. This technique is used - // instead of -orderOut: because that may cause a Spaces change or window - // ordering change. - [customWindow_ setAlphaValue:0.0]; - // TODO(tapted): Support child windows. - DCHECK_EQ(0u, [[customWindow_ childWindows] count]); -} - -- (void)unhideSheet { - [customWindow_ setAlphaValue:1.0]; - DCHECK_EQ(0u, [[customWindow_ childWindows] count]); -} - -- (void)pulseSheet { - base::scoped_nsobject<NSAnimation> animation( - [[ConstrainedWindowAnimationPulse alloc] initWithWindow:customWindow_]); - [animation startAnimation]; -} - -- (void)makeSheetKeyAndOrderFront { - // If the window is not visible, do nothing. Widget::Show() is responsible for - // showing, and it may want to animate it. - if ([customWindow_ isVisible]) - [customWindow_ makeKeyAndOrderFront:nil]; -} - -- (void)updateSheetPosition { - ConstrainedWindowSheetController* controller = - [ConstrainedWindowSheetController controllerForSheet:self]; - NSPoint origin = [controller originForSheet:self - withWindowSize:[customWindow_ frame].size]; - [customWindow_ setFrameOrigin:origin]; -} - -- (void)resizeWithNewSize:(NSSize)size { - // NOOP -} - -- (NSWindow*)sheetWindow { - return customWindow_; -} - -@end - -SingleWebContentsDialogManagerViewsMac::SingleWebContentsDialogManagerViewsMac( - NSWindow* dialog, - web_modal::SingleWebContentsDialogManagerDelegate* delegate) - : delegate_(delegate), host_(nullptr) { - sheet_.reset( - [[WrappedConstrainedWindowSheet alloc] initWithCustomWindow:dialog]); - widget_ = views::Widget::GetWidgetForNativeWindow(dialog); - DCHECK(widget_); - widget_->AddObserver(this); -} - -SingleWebContentsDialogManagerViewsMac:: - ~SingleWebContentsDialogManagerViewsMac() { - DCHECK(!widget_->HasObserver(this)); -} - -void SingleWebContentsDialogManagerViewsMac::Show() { - DCHECK(host_); - - NSView* parent_view = host_->GetHostView(); - // Note that simply [parent_view window] for an inactive tab is nil. However, - // the following should always be non-nil for all WebContents containers. - NSWindow* parent_window = - delegate_->GetWebContents()->GetTopLevelNativeWindow(); - // Register with the ConstrainedWindowSheetController. This ensures that, e.g. - // the NSView that overlays the Cocoa WebContents to intercept clicks is - // installed and managed. - [[ConstrainedWindowSheetController controllerForParentWindow:parent_window] - showSheet:sheet_ - forParentView:parent_view]; - - if (!widget_->IsVisible()) { - if (was_shown_) { - // Disable animations when switching tabs. - widget_->SetVisibilityChangedAnimationsEnabled(false); - } - widget_->Show(); - widget_->SetVisibilityChangedAnimationsEnabled(true); - was_shown_ = true; - } -} - -void SingleWebContentsDialogManagerViewsMac::Hide() { - NSWindow* parent_window = - delegate_->GetWebContents()->GetTopLevelNativeWindow(); - [[ConstrainedWindowSheetController controllerForParentWindow:parent_window] - hideSheet:sheet_]; - - widget_->Hide(); -} - -void SingleWebContentsDialogManagerViewsMac::Close() { - // When the WebContents is destroyed, WebContentsModalDialogManager - // ::CloseAllDialogs will call this. Close the Widget in the same manner as - // the dialogs so that codepaths are consistent. - widget_->SetVisibilityChangedAnimationsEnabled(false); - widget_->Close(); // Note: Synchronously calls OnWidgetClosing() below. -} - -void SingleWebContentsDialogManagerViewsMac::Focus() { - [sheet_ makeSheetKeyAndOrderFront]; -} -void SingleWebContentsDialogManagerViewsMac::Pulse() { - // Handled by ConstrainedWindowSheetController. -} - -void SingleWebContentsDialogManagerViewsMac::HostChanged( - web_modal::WebContentsModalDialogHost* new_host) { - // No need to observe the host. For Cocoa, the constrained window controller - // will reposition the dialog when necessary. The host can also never change. - // Tabs showing a dialog can not be dragged off a Cocoa browser window. - // However, closing a tab with a dialog open will set the host back to null. - DCHECK_NE(!!host_, !!new_host); - host_ = new_host; -} - -gfx::NativeWindow SingleWebContentsDialogManagerViewsMac::dialog() { - return [sheet_ sheetWindow]; -} - -// views::WidgetObserver: -void SingleWebContentsDialogManagerViewsMac::OnWidgetClosing( - views::Widget* widget) { - DCHECK_EQ(widget, widget_); - widget->RemoveObserver(this); - [[ConstrainedWindowSheetController controllerForSheet:sheet_] - closeSheet:sheet_]; - delegate_->WillClose(dialog()); // Deletes |this|. -} - -void SingleWebContentsDialogManagerViewsMac::OnWidgetDestroying( - views::Widget* widget) { - // On Mac, this would only be reached if something called -[NSWindow close] - // on the dialog without going through Widget::Close or CloseNow(). In this - // case (only), OnWidgetClosing() is skipped, so invoke it here. Note: since - // dialogs have no titlebar, it "shouldn't" happen, but crashes in - // https://crbug.com/825809 suggest it can. Possibly this occurs via code - // injection or a third party tool. - OnWidgetClosing(widget); // Deletes |this|. -}
diff --git a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac_browsertest.mm b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac_browsertest.mm deleted file mode 100644 index 27e23fb..0000000 --- a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac_browsertest.mm +++ /dev/null
@@ -1,193 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h" - -#import <Cocoa/Cocoa.h> - -#include "base/location.h" -#include "base/macros.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/test/test_timeouts.h" -#include "base/threading/thread_task_runner_handle.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_window.h" -#include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "chrome/test/views/scoped_macviews_browser_mode.h" -#include "components/constrained_window/constrained_window_views.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_observer.h" -#include "ui/views/window/dialog_delegate.h" -#include "url/gurl.h" - -using views::Widget; - -namespace { - -class WebContentsModalDialogManagerViewsMacTest : public InProcessBrowserTest, - public views::WidgetObserver { - public: - WebContentsModalDialogManagerViewsMacTest() {} - - Widget* ShowViewsDialogOn(int web_contents_index, bool activate) { - if (activate) - browser()->tab_strip_model()->ActivateTabAt(web_contents_index, true); - content::WebContents* web_contents = - browser()->tab_strip_model()->GetWebContentsAt(web_contents_index); - - DCHECK(web_contents); - - // Show a dialog as a constrained window modal to the current tab. - Widget* widget = constrained_window::ShowWebModalDialogViews(new TestDialog, - web_contents); - widget->AddObserver(this); - return widget; - } - - void WaitForClose() { - last_destroyed_ = nullptr; - base::RunLoop run_loop; - run_loop_ = &run_loop; - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, run_loop.QuitClosure(), TestTimeouts::action_timeout()); - run_loop.Run(); - run_loop_ = nullptr; - } - - // views::WidgetObserver: - void OnWidgetDestroying(views::Widget* widget) override { - destroy_count_++; - widget->RemoveObserver(this); - last_destroyed_ = widget; - if (run_loop_) - run_loop_->Quit(); - } - - class TestDialog : public views::DialogDelegateView { - public: - TestDialog() {} - // WidgetDelegate: - ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_CHILD; } - - private: - DISALLOW_COPY_AND_ASSIGN(TestDialog); - }; - - protected: - int destroy_count_ = 0; - Widget* last_destroyed_ = nullptr; - base::RunLoop* run_loop_ = nullptr; - - private: - test::ScopedMacViewsBrowserMode cocoa_browser_mode_{false}; - - DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManagerViewsMacTest); -}; - -} // namespace - -// Basic test for showing and dismissing the dialog in a single tab. -IN_PROC_BROWSER_TEST_F(WebContentsModalDialogManagerViewsMacTest, Basic) { - NSArray* children = [browser()->window()->GetNativeWindow() childWindows]; - EXPECT_EQ(0u, [children count]); - - Widget* dialog = ShowViewsDialogOn(0, true); - EXPECT_TRUE(dialog->IsVisible()); - - // The browser window will get two child windows: a transparent overlay, and - // the views::Widget dialog. Ensure the dialog is on top. - children = [browser()->window()->GetNativeWindow() childWindows]; - EXPECT_EQ(2u, [children count]); - EXPECT_EQ(dialog->GetNativeWindow(), [children objectAtIndex:1]); - - // Toolkit-views dialogs use GetWidget()->Close() to dismiss themselves. - dialog->Close(); - EXPECT_EQ(0, destroy_count_); - WaitForClose(); - EXPECT_EQ(dialog, last_destroyed_); - EXPECT_EQ(1, destroy_count_); -} - -// Test for some code injection or third party tool invoking -[NSWindow close]. -IN_PROC_BROWSER_TEST_F(WebContentsModalDialogManagerViewsMacTest, NativeClose) { - NSArray* children = [browser()->window()->GetNativeWindow() childWindows]; - EXPECT_EQ(0u, [children count]); - - Widget* dialog = ShowViewsDialogOn(0, true); - EXPECT_TRUE(dialog->IsVisible()); - - // Chrome code never does this, but ensure the codepaths are robust to it. - // Invoking this will jump to SingleWebContentsDialogManagerViewsMac:: - // OnWidgetDestroying() without first encountering OnWidgetClosing(). - [dialog->GetNativeWindow() close]; - - EXPECT_EQ(1, destroy_count_); - EXPECT_EQ(dialog, last_destroyed_); -} - -// Test showing dialogs in two tabs, switch tabs, then close the background tab, -// then close the browser window. -IN_PROC_BROWSER_TEST_F(WebContentsModalDialogManagerViewsMacTest, - TwoDialogsThenCloseTabs) { - // Add a second tab, then show a dialog on each while the tab is active. - AddTabAtIndex(1, GURL("about:blank"), ui::PAGE_TRANSITION_LINK); - Widget* dialog1 = ShowViewsDialogOn(1, true); - Widget* dialog0 = ShowViewsDialogOn(0, true); - - // Tab 0 is active, so only |dialog0| should become visible. - EXPECT_TRUE(dialog0->IsVisible()); - EXPECT_FALSE(dialog1->IsVisible()); - - // The inactive, second dialog will also be fully transparent. - EXPECT_EQ(0.0, [dialog1->GetNativeWindow() alphaValue]); - EXPECT_EQ(1.0, [dialog0->GetNativeWindow() alphaValue]); - - // Activate the second tab, visibility should switch. - browser()->tab_strip_model()->ActivateTabAt(1, true); - EXPECT_EQ(1.0, [dialog1->GetNativeWindow() alphaValue]); - EXPECT_EQ(0.0, [dialog0->GetNativeWindow() alphaValue]); - EXPECT_FALSE(dialog0->IsVisible()); - EXPECT_TRUE(dialog1->IsVisible()); - - // Close the background tab. - browser()->tab_strip_model()->CloseWebContentsAt( - 0, TabStripModel::CLOSE_USER_GESTURE); - // Close is asynchronous, so nothing happens until a run loop is spun up. - EXPECT_EQ(0, destroy_count_); - WaitForClose(); - EXPECT_EQ(dialog0, last_destroyed_); - EXPECT_EQ(1, destroy_count_); - - // Close the window. But first close all tabs. Otherwise before-unload - // handlers have an opportunity to run, which is asynchronous. - browser()->tab_strip_model()->CloseAllTabs(); - // Since the parent NSWindow goes away, close happens immediately. - browser()->window()->Close(); - EXPECT_EQ(dialog1, last_destroyed_); - EXPECT_EQ(2, destroy_count_); -} - -// Test showing in a dialog in an inactive tab. For these, the WebContentsView -// will be detached from the view hierarchy. -IN_PROC_BROWSER_TEST_F(WebContentsModalDialogManagerViewsMacTest, - DialogInBackgroundTab) { - // Add a second tab. It should start active. - AddTabAtIndex(1, GURL("about:blank"), ui::PAGE_TRANSITION_LINK); - EXPECT_TRUE(browser()->tab_strip_model()->IsTabSelected(1)); - - // Showing shouldn't change the active tab, and the dialog shouldn't be shown - // at all yet. - Widget* dialog0 = ShowViewsDialogOn(0, false); - EXPECT_TRUE(browser()->tab_strip_model()->IsTabSelected(1)); - EXPECT_FALSE(dialog0->IsVisible()); - - // But switching to the tab should show (and animate) it. - browser()->tab_strip_model()->ActivateTabAt(0, true); - EXPECT_TRUE(browser()->tab_strip_model()->IsTabSelected(0)); - EXPECT_TRUE(dialog0->IsVisible()); - - // Leave the dialog open for a change to ensure shutdown is clean. -}
diff --git a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc index e27284a..aebc2a5 100644 --- a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc +++ b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc
@@ -28,6 +28,8 @@ ui::LinuxInputMethodContextDelegate* delegate, bool is_simple) : delegate_(delegate), + is_simple_(is_simple), + has_focus_(false), gtk_context_(nullptr), gdk_last_set_client_window_(nullptr) { CHECK(delegate_); @@ -103,14 +105,23 @@ void X11InputMethodContextImplGtk::Reset() { gtk_im_context_reset(gtk_context_); + + // Some input methods may not honour the reset call. + // Focusing out/in the to make sure it gets reset correctly. + if (!is_simple_ && has_focus_) { + Blur(); + Focus(); + } } void X11InputMethodContextImplGtk::Focus() { gtk_im_context_focus_in(gtk_context_); + has_focus_ = true; } void X11InputMethodContextImplGtk::Blur() { gtk_im_context_focus_out(gtk_context_); + has_focus_ = false; } void X11InputMethodContextImplGtk::SetCursorLocation(const gfx::Rect& rect) { @@ -127,6 +138,12 @@ } } +void X11InputMethodContextImplGtk::SetSurroundingText( + const base::string16& text, + const gfx::Range& selection_range) { + NOTIMPLEMENTED_LOG_ONCE(); +} + // private: void X11InputMethodContextImplGtk::ResetXModifierKeycodesCache() {
diff --git a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h index 83a530c..5431b643 100644 --- a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h +++ b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h
@@ -35,6 +35,8 @@ void Reset() override; void Focus() override; void Blur() override; + void SetSurroundingText(const base::string16& text, + const gfx::Range& selection_range) override; private: // Resets the cache of X modifier keycodes. @@ -79,6 +81,14 @@ // A set of callback functions. Must not be nullptr. ui::LinuxInputMethodContextDelegate* delegate_; + // Input method context type flag. + // - true if it supports table-based input methods + // - false if it supports multiple, loadable input methods + bool is_simple_; + + // Keeps track of current focus state. + bool has_focus_; + // IME's input GTK context. GtkIMContext* gtk_context_;
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc index 291a4054..072a727 100644 --- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc +++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
@@ -14,10 +14,13 @@ #include "chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h" #include "chrome/common/chrome_features.h" #include "components/omnibox/browser/autocomplete_match.h" +#include "components/ukm/content/source_url_recorder.h" #include "components/url_formatter/idn_spoof_checker.h" #include "components/url_formatter/url_formatter.h" #include "content/public/browser/navigation_handle.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "services/metrics/public/cpp/ukm_builders.h" +#include "services/metrics/public/cpp/ukm_recorder.h" namespace { @@ -80,14 +83,17 @@ return; std::string matched_domain; + MatchType match_type; if (result.matching_top_domain.empty()) { matched_domain = GetMatchingSiteEngagementDomain(service, url); if (matched_domain.empty()) return; RecordEvent(NavigationSuggestionEvent::kMatchSiteEngagement); + match_type = MatchType::kSiteEngagement; } else { matched_domain = result.matching_top_domain; RecordEvent(NavigationSuggestionEvent::kMatchTopSite); + match_type = MatchType::kTopSite; } DCHECK(!matched_domain.empty()); @@ -96,6 +102,14 @@ replace_host.SetHostStr(matched_domain); const GURL suggested_url = url.ReplaceComponents(replace_host); + ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get(); + CHECK(ukm_recorder); + ukm::SourceId source_id = + ukm::GetSourceIdForWebContentsDocument(web_contents()); + ukm::builders::LookalikeUrl_NavigationSuggestion(source_id) + .SetMatchType(static_cast<int>(match_type)) + .Record(ukm_recorder); + if (kMetricsOnly.Get().empty()) { RecordEvent(NavigationSuggestionEvent::kInfobarShown); AlternateNavInfoBarDelegate::CreateForLookalikeUrlNavigation(
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h index 967e0cd3..0b9b12d 100644 --- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h +++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h
@@ -20,7 +20,7 @@ : public content::WebContentsObserver, public content::WebContentsUserData<LookalikeUrlNavigationObserver> { public: - // Used for metrics. + // Used for metrics. Multiple events can occur per navigation. enum class NavigationSuggestionEvent { kNone = 0, kInfobarShown = 1, @@ -33,6 +33,17 @@ kMaxValue = kMatchSiteEngagement, }; + // Used for UKM. There is only a single MatchType per navigation. + enum class MatchType { + kNone = 0, + kTopSite = 1, + kSiteEngagement = 2, + + // Append new items to the end of the list above; do not modify or replace + // existing values. Comment out obsolete items. + kMaxValue = kSiteEngagement, + }; + static const char kHistogramName[]; static void CreateForWebContents(content::WebContents* web_contents);
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc index d02edd3c..699d07f 100644 --- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc +++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
@@ -19,13 +19,18 @@ #include "chrome/test/base/ui_test_utils.h" #include "components/infobars/core/infobar.h" #include "components/infobars/core/infobar_delegate.h" +#include "components/ukm/test_ukm_recorder.h" #include "content/public/browser/web_contents.h" #include "content/public/test/test_navigation_observer.h" #include "net/dns/mock_host_resolver.h" +#include "services/metrics/public/cpp/ukm_builders.h" +#include "services/metrics/public/cpp/ukm_source.h" #include "ui/base/window_open_disposition.h" namespace { +using UkmEntry = ukm::builders::LookalikeUrl_NavigationSuggestion; + enum class FeatureTestState { kDisabled, kEnabledWithoutUI, kEnabledWithUI }; struct SiteEngagementTestCase { @@ -67,6 +72,7 @@ void SetUpOnMainThread() override { host_resolver()->AddRule("*", "127.0.0.1"); ASSERT_TRUE(embedded_test_server()->Start()); + test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); } // Sets the absolute Site Engagement |score| for the testing origin. @@ -86,6 +92,26 @@ ui_test_utils::NavigateToURL(¶ms); } + // Checks that UKM recorded a metric for each URL in |navigated_urls|. + void CheckUkm(const std::vector<GURL>& navigated_urls, + LookalikeUrlNavigationObserver::MatchType match_type) { + auto entries = test_ukm_recorder()->GetEntriesByName(UkmEntry::kEntryName); + ASSERT_EQ(navigated_urls.size(), entries.size()); + int entry_count = 0; + for (const auto* const entry : entries) { + test_ukm_recorder()->ExpectEntrySourceHasUrl(entry, + navigated_urls[entry_count]); + test_ukm_recorder()->ExpectEntryMetric(entry, "MatchType", + static_cast<int>(match_type)); + entry_count++; + } + } + + void CheckNoUkm() { + EXPECT_TRUE( + test_ukm_recorder()->GetEntriesByName(UkmEntry::kEntryName).empty()); + } + void TestInfobarNotShown(const GURL& navigated_url) { content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); @@ -141,8 +167,11 @@ EXPECT_FALSE(base::ContainsValue(enumerator.urls(), navigated_url)); } + ukm::TestUkmRecorder* test_ukm_recorder() { return test_ukm_recorder_.get(); } + private: base::test::ScopedFeatureList feature_list_; + std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_; }; INSTANTIATE_TEST_CASE_P(, @@ -156,6 +185,7 @@ NonIdn_NoInfobar) { TestInfobarNotShown( embedded_test_server()->GetURL("google.com", "/title1.html")); + CheckNoUkm(); } // Navigating to a domain whose visual representation does not look like a @@ -164,6 +194,7 @@ NonTopDomainIdn_NoInfobar) { TestInfobarNotShown( embedded_test_server()->GetURL("éxample.com", "/title1.html")); + CheckNoUkm(); } // Navigating to a domain whose visual representation looks like a top domain @@ -175,8 +206,10 @@ base::HistogramTester histograms; - TestInfobarShown(embedded_test_server()->GetURL( - "googlé.com", "/title1.html") /* navigated */, + const GURL kNavigatedUrl = + embedded_test_server()->GetURL("googlé.com", "/title1.html"); + + TestInfobarShown(kNavigatedUrl, embedded_test_server()->GetURL( "google.com", "/title1.html") /* suggested */); @@ -194,6 +227,8 @@ LookalikeUrlNavigationObserver::kHistogramName, LookalikeUrlNavigationObserver::NavigationSuggestionEvent::kMatchTopSite, 1); + CheckUkm({kNavigatedUrl}, + LookalikeUrlNavigationObserver::MatchType::kTopSite); } // Same as TopDomainIdn_Infobar but the UI is disabled, so only checks for @@ -204,9 +239,10 @@ return; base::HistogramTester histograms; + const GURL kNavigatedUrl = + embedded_test_server()->GetURL("googlé.com", "/title1.html"); - TestInfobarNotShown( - embedded_test_server()->GetURL("googlé.com", "/title1.html")); + TestInfobarNotShown(kNavigatedUrl); histograms.ExpectTotalCount(LookalikeUrlNavigationObserver::kHistogramName, 1); @@ -214,6 +250,8 @@ LookalikeUrlNavigationObserver::kHistogramName, LookalikeUrlNavigationObserver::NavigationSuggestionEvent::kMatchTopSite, 1); + CheckUkm({kNavigatedUrl}, + LookalikeUrlNavigationObserver::MatchType::kTopSite); } // Same as TopDomainIdn_Infobar but the user has engaged with the domain before. @@ -224,6 +262,7 @@ const GURL url = embedded_test_server()->GetURL("googlé.com", "/title1.html"); SetSiteEngagementScore(url, 20); TestInfobarNotShown(url); + CheckNoUkm(); } // Navigating to a domain whose visual representation looks like a domain with a @@ -239,11 +278,15 @@ SetSiteEngagementScore(GURL("http://sité3.test"), 20); SetSiteEngagementScore(GURL("http://www.sité4.test"), 20); + std::vector<GURL> ukm_urls; for (const auto& test_case : kSiteEngagementTestCases) { base::HistogramTester histograms; - TestInfobarShown( - embedded_test_server()->GetURL(test_case.navigated, "/title1.html"), - embedded_test_server()->GetURL(test_case.suggested, "/title1.html")); + const GURL kNavigatedUrl = + embedded_test_server()->GetURL(test_case.navigated, "/title1.html"); + TestInfobarShown(kNavigatedUrl, embedded_test_server()->GetURL( + test_case.suggested, "/title1.html")); + ukm_urls.push_back(kNavigatedUrl); + histograms.ExpectTotalCount(LookalikeUrlNavigationObserver::kHistogramName, 3); histograms.ExpectBucketCount(LookalikeUrlNavigationObserver::kHistogramName, @@ -260,6 +303,8 @@ kMatchSiteEngagement, 1); } + CheckUkm(ukm_urls, + LookalikeUrlNavigationObserver::MatchType::kSiteEngagement); } // Same as SiteEngagement_Infobar but the UI is disabled, so only checks for @@ -274,10 +319,14 @@ SetSiteEngagementScore(GURL("http://sité3.test"), 20); SetSiteEngagementScore(GURL("http://www.sité4.test"), 20); + std::vector<GURL> ukm_urls; for (const auto& test_case : kSiteEngagementTestCases) { base::HistogramTester histograms; - TestInfobarNotShown( - embedded_test_server()->GetURL(test_case.navigated, "/title1.html")); + const GURL kNavigatedUrl = + embedded_test_server()->GetURL(test_case.navigated, "/title1.html"); + TestInfobarNotShown(kNavigatedUrl); + ukm_urls.push_back(kNavigatedUrl); + histograms.ExpectTotalCount(LookalikeUrlNavigationObserver::kHistogramName, 1); histograms.ExpectBucketCount( @@ -286,6 +335,8 @@ kMatchSiteEngagement, 1); } + CheckUkm(ukm_urls, + LookalikeUrlNavigationObserver::MatchType::kSiteEngagement); } // The infobar shouldn't be shown when the feature is disabled. @@ -296,4 +347,5 @@ TestInfobarNotShown( embedded_test_server()->GetURL("googlé.com", "/title1.html")); + CheckNoUkm(); }
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc index f7e93c81..2cd1517 100644 --- a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc +++ b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
@@ -185,7 +185,6 @@ } } -// TODO(crbug/867194): Add metrics for legal message link clicking. void LocalCardMigrationDialogView::StyledLabelLinkClicked( views::StyledLabel* label, const gfx::Range& range, @@ -193,6 +192,9 @@ if (!controller_) return; + controller_->OnLegalMessageLinkClicked(); + // TODO(crbug.com/867194): Should be controller's responsibility to open + // links. legal_message_container_->OnLinkClicked(label, range, web_contents_); }
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc index 65499f68..98f7628 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
@@ -76,13 +76,9 @@ class DialogWaiter : public aura::EnvObserver, public views::WidgetObserver { public: - DialogWaiter() - : dialog_created_(false), - dialog_(NULL) { - aura::Env::GetInstance()->AddObserver(this); - } + explicit DialogWaiter(aura::Env* env) : env_(env) { env_->AddObserver(this); } - ~DialogWaiter() override { aura::Env::GetInstance()->RemoveObserver(this); } + ~DialogWaiter() override { env_->RemoveObserver(this); } views::Widget* WaitForDialog() { if (dialog_created_) @@ -116,8 +112,9 @@ } } - bool dialog_created_; - views::Widget* dialog_; + aura::Env* env_; + bool dialog_created_ = false; + views::Widget* dialog_ = nullptr; base::Closure quit_closure_; DISALLOW_COPY_AND_ASSIGN(DialogWaiter); @@ -1340,7 +1337,8 @@ ASSERT_TRUE(child_menu != NULL); // Click and wait until the dialog box appears. - std::unique_ptr<DialogWaiter> dialog_waiter(new DialogWaiter()); + auto dialog_waiter = std::make_unique<DialogWaiter>( + bb_view_->GetWidget()->GetNativeWindow()->env()); ui_test_utils::MoveMouseToCenterAndPress( child_menu, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP, base::Bind(&BookmarkBarViewTest12::Step4, base::Unretained(this),
diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc index 476e0e66d..263ba71e 100644 --- a/chrome/browser/ui/views/chrome_views_delegate.cc +++ b/chrome/browser/ui/views/chrome_views_delegate.cc
@@ -128,8 +128,7 @@ views::View* view, ax::mojom::Event event_type) { #if defined(USE_AURA) - AutomationManagerAura::GetInstance()->HandleEvent( - GetProfileForWindow(view->GetWidget()), view, event_type); + AutomationManagerAura::GetInstance()->HandleEvent(view, event_type); #endif }
diff --git a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc index 1d006ce..1e1bf5f 100644 --- a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc +++ b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
@@ -81,12 +81,14 @@ // well to catch 'em all. void OnMouseMoved(const ui::MouseEvent& event) override { auto pair = GetParentWidgetAndEvent(this, &event); - pair.widget->OnMouseEvent(&pair.event); + if (pair.widget) + pair.widget->OnMouseEvent(&pair.event); } void OnMouseEvent(ui::MouseEvent* event) override { auto pair = GetParentWidgetAndEvent(this, event); - pair.widget->OnMouseEvent(&pair.event); + if (pair.widget) + pair.widget->OnMouseEvent(&pair.event); // If the original event isn't marked as "handled" then it will propagate up // the view hierarchy and might be double-handled. https://crbug.com/870341 @@ -95,10 +97,14 @@ gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override { auto pair = GetParentWidgetAndEvent(this, &event); - views::View* omnibox_view = - pair.widget->GetRootView()->GetEventHandlerForPoint( - pair.event.location()); - return omnibox_view->GetCursor(pair.event); + if (pair.widget) { + views::View* omnibox_view = + pair.widget->GetRootView()->GetEventHandlerForPoint( + pair.event.location()); + return omnibox_view->GetCursor(pair.event); + } + + return nullptr; } #endif // !USE_AURA };
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc index 1188e96..e6b929d5 100644 --- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc +++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
@@ -83,8 +83,8 @@ CvcUnmaskViewController::~CvcUnmaskViewController() {} void CvcUnmaskViewController::LoadRiskData( - const base::Callback<void(const std::string&)>& callback) { - autofill::LoadRiskData(0, web_contents_, callback); + base::OnceCallback<void(const std::string&)> callback) { + autofill::LoadRiskData(0, web_contents_, std::move(callback)); } void CvcUnmaskViewController::ShowUnmaskPrompt(
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h index 41e8c78f..77f418dd 100644 --- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h +++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
@@ -55,7 +55,7 @@ // autofill::RiskDataLoader: void LoadRiskData( - const base::Callback<void(const std::string&)>& callback) override; + base::OnceCallback<void(const std::string&)> callback) override; // autofill::payments::FullCardRequest::UIDelegate: void ShowUnmaskPrompt(
diff --git a/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.h b/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.h deleted file mode 100644 index 0811df2..0000000 --- a/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_GET_APP_MENU_ANCHOR_POINT_H_ -#define CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_GET_APP_MENU_ANCHOR_POINT_H_ - -#include "ui/gfx/geometry/point.h" - -class Browser; - -// Returns the point to which bubbles should be anchored for the app menu of -// |browser|. -gfx::Point GetAppMenuAnchorPoint(Browser* browser); - -#endif // CHROME_BROWSER_UI_VIEWS_RELAUNCH_NOTIFICATION_GET_APP_MENU_ANCHOR_POINT_H_
diff --git a/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.mm b/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.mm deleted file mode 100644 index 261ccda..0000000 --- a/chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.mm +++ /dev/null
@@ -1,22 +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. - -#import "chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.h" - -#import "chrome/browser/ui/browser.h" -#import "chrome/browser/ui/browser_window.h" -#import "chrome/browser/ui/cocoa/browser_window_controller.h" -#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" -#include "ui/base/cocoa/cocoa_base_utils.h" -#import "ui/gfx/mac/coordinate_conversion.h" - -gfx::Point GetAppMenuAnchorPoint(Browser* browser) { - NSWindow* parent_window = browser->window()->GetNativeWindow(); - BrowserWindowController* bwc = - [BrowserWindowController browserWindowControllerForWindow:parent_window]; - ToolbarController* tbc = [bwc toolbarController]; - NSPoint ns_point = [tbc appMenuBubblePoint]; - return gfx::ScreenPointFromNSPoint( - ui::ConvertPointFromWindowToScreen(parent_window, ns_point)); -}
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc index 8c7f2bf..32e36f1 100644 --- a/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc +++ b/chrome/browser/ui/views/relaunch_notification/relaunch_recommended_bubble_view.cc
@@ -36,35 +36,8 @@ #if defined(OS_MACOSX) #include "chrome/browser/platform_util.h" -#if BUILDFLAG(MAC_VIEWS_BROWSER) -#include "chrome/browser/ui/views_mode_controller.h" -#endif // BUILDFLAG(MAC_VIEWS_BROWSER) -#include "chrome/browser/ui/views/relaunch_notification/get_app_menu_anchor_point.h" #endif // defined(OS_MACOSX) -namespace { - -// Returns the anchor for |browser|'s app menu, accounting for macOS running -// with views or Cocoa. -std::pair<views::Button*, gfx::Point> GetAnchor(Browser* browser) { -#if defined(OS_MACOSX) -#if BUILDFLAG(MAC_VIEWS_BROWSER) - if (views_mode_controller::IsViewsBrowserCocoa()) - return std::make_pair(nullptr, GetAppMenuAnchorPoint(browser)); -#else // BUILDFLAG(MAC_VIEWS_BROWSER) - return std::make_pair(nullptr, GetAppMenuAnchorPoint(browser)); -#endif // BUILDFLAG(MAC_VIEWS_BROWSER) -#endif // defined(OS_MACOSX) -#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER) - return std::make_pair(BrowserView::GetBrowserViewForBrowser(browser) - ->toolbar() - ->app_menu_button(), - gfx::Point()); -#endif // !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER) -} - -} // namespace - // static views::Widget* RelaunchRecommendedBubbleView::ShowBubble( Browser* browser, @@ -72,13 +45,12 @@ base::RepeatingClosure on_accept) { DCHECK(browser); - views::Button* anchor_button; - gfx::Point anchor_point; - // Anchor the popup to the browser's app menu. - std::tie(anchor_button, anchor_point) = GetAnchor(browser); + auto* anchor_button = BrowserView::GetBrowserViewForBrowser(browser) + ->toolbar() + ->app_menu_button(); auto* bubble_view = new RelaunchRecommendedBubbleView( - anchor_button, anchor_point, detection_time, std::move(on_accept)); + anchor_button, gfx::Point(), detection_time, std::move(on_accept)); bubble_view->SetArrow(views::BubbleBorder::TOP_RIGHT); #if defined(OS_MACOSX)
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc index eb08cdc..01d482a0 100644 --- a/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc +++ b/chrome/browser/ui/webui/chromeos/login/oobe_display_chooser_unittest.cc
@@ -121,7 +121,7 @@ // Setup corresponding TouchscreenDevice object ui::TouchscreenDevice touchscreen = - ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "Touchscreen", gfx::Size(800, 600), 1); touchscreen.vendor_id = kWhitelistedId; ws::InputDeviceClientTestApi().SetTouchscreenDevices({touchscreen}); @@ -164,7 +164,7 @@ // Setup corresponding TouchscreenDevice object ui::TouchscreenDevice touchscreen = - ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_USB, "Touchscreen", gfx::Size(800, 600), 1); touchscreen.vendor_id = kWhitelistedId; ws::InputDeviceClientTestApi().SetTouchscreenDevices({touchscreen});
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc index 7fd0854..9cf3cf6 100644 --- a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc
@@ -185,7 +185,7 @@ // Simulate an external keyboard being connected. We should assume there's a // Caps Lock and Meta keys now. input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{ - {2, ui::INPUT_DEVICE_EXTERNAL, "external keyboard"}}); + {2, ui::INPUT_DEVICE_USB, "external keyboard"}}); EXPECT_TRUE(HasCapsLock()); EXPECT_FALSE(HasDiamondKey()); EXPECT_TRUE(HasExternalMetaKey()); @@ -194,7 +194,7 @@ // Simulate an external Apple keyboard being connected. Now users can remap // the command key. input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{ - {3, ui::INPUT_DEVICE_EXTERNAL, "Apple Inc. Apple Keyboard"}}); + {3, ui::INPUT_DEVICE_USB, "Apple Inc. Apple Keyboard"}}); EXPECT_TRUE(HasCapsLock()); EXPECT_FALSE(HasDiamondKey()); EXPECT_FALSE(HasExternalMetaKey()); @@ -203,8 +203,8 @@ // Simulate two external keyboards (Apple and non-Apple) are connected at the // same time. input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{ - {2, ui::INPUT_DEVICE_EXTERNAL, "external keyboard"}, - {3, ui::INPUT_DEVICE_EXTERNAL, "Apple Inc. Apple Keyboard"}}); + {2, ui::INPUT_DEVICE_USB, "external keyboard"}, + {3, ui::INPUT_DEVICE_USB, "Apple Inc. Apple Keyboard"}}); EXPECT_TRUE(HasCapsLock()); EXPECT_FALSE(HasDiamondKey()); EXPECT_TRUE(HasExternalMetaKey()); @@ -215,7 +215,7 @@ // should show the capslock and external meta remapping. // https://crbug.com/834594. input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{ - {4, ui::INPUT_DEVICE_EXTERNAL, "Topre Corporation Realforce 87"}}); + {4, ui::INPUT_DEVICE_USB, "Topre Corporation Realforce 87"}}); EXPECT_TRUE(HasCapsLock()); EXPECT_FALSE(HasDiamondKey()); EXPECT_TRUE(HasExternalMetaKey());
diff --git a/chrome/browser/vr/test/gl_test_environment_unittest.cc b/chrome/browser/vr/test/gl_test_environment_unittest.cc index ee62da2..d66e7e451 100644 --- a/chrome/browser/vr/test/gl_test_environment_unittest.cc +++ b/chrome/browser/vr/test/gl_test_environment_unittest.cc
@@ -9,7 +9,13 @@ namespace vr { -TEST(GlTestEnvironmentTest, InitializeAndCleanup) { +#if defined(MEMORY_SANITIZER) +#define MAYBE_InitializeAndCleanup DISABLED_InitializeAndCleanup +#else +#define MAYBE_InitializeAndCleanup InitializeAndCleanup +#endif + +TEST(GlTestEnvironmentTest, MAYBE_InitializeAndCleanup) { GlTestEnvironment gl_test_environment(gfx::Size(100, 100)); EXPECT_NE(gl_test_environment.GetFrameBufferForTesting(), 0u); EXPECT_EQ(glGetError(), (GLenum)GL_NO_ERROR);
diff --git a/chrome/browser/vr/ui_pixeltest.cc b/chrome/browser/vr/ui_pixeltest.cc index 64c15d3..1d4c3351 100644 --- a/chrome/browser/vr/ui_pixeltest.cc +++ b/chrome/browser/vr/ui_pixeltest.cc
@@ -18,7 +18,13 @@ } // namespace -TEST_F(UiPixelTest, DrawVrBrowsingMode) { +#if defined(MEMORY_SANITIZER) +#define MAYBE_DrawVrBrowsingMode DISABLED_DrawVrBrowsingMode +#else +#define MAYBE_DrawVrBrowsingMode DrawVrBrowsingMode +#endif + +TEST_F(UiPixelTest, MAYBE_DrawVrBrowsingMode) { // Set up scene. UiInitialState ui_initial_state; ui_initial_state.in_web_vr = false;
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index e5d09bd..821f504f 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -559,7 +559,7 @@ // Enables or disables sliding (showing or hiding) the top-chrome UIs with page // scrolls in tablet mode. const base::Feature kSlideTopChromeWithPageScrolls{ - "SlideTopChromeWithPageScrolls", base::FEATURE_DISABLED_BY_DEFAULT}; + "SlideTopChromeWithPageScrolls", base::FEATURE_ENABLED_BY_DEFAULT}; // Enables or disables chrome://sys-internals. const base::Feature kSysInternals{"SysInternals", @@ -587,12 +587,6 @@ // Chrome OS. const base::Feature kUserActivityEventLogging{"UserActivityEventLogging", base::FEATURE_ENABLED_BY_DEFAULT}; - -// Enables or disables user activity prediction for power management on -// Chrome OS. -const base::Feature kUserActivityPrediction{"UserActivityPrediction", - base::FEATURE_DISABLED_BY_DEFAULT}; - #endif // Enables using the main HTTP cache for media files as well.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 2d0eb8ca..f137fb4 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -393,8 +393,6 @@ COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kUserActivityEventLogging; -COMPONENT_EXPORT(CHROME_FEATURES) -extern const base::Feature kUserActivityPrediction; #endif COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc index 78264954..27c8c9357 100644 --- a/chrome/renderer/media/chrome_key_systems.cc +++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -152,11 +152,11 @@ // TODO(sandersd): Distinguish these from those that are directly supported, // as those may offer a higher level of protection. if (!supported_video_codecs.empty() || !is_secure) { - supported_codecs |= media::EME_CODEC_WEBM_OPUS; - supported_codecs |= media::EME_CODEC_WEBM_VORBIS; - supported_codecs |= media::EME_CODEC_MP4_FLAC; + supported_codecs |= media::EME_CODEC_OPUS; + supported_codecs |= media::EME_CODEC_VORBIS; + supported_codecs |= media::EME_CODEC_FLAC; #if BUILDFLAG(USE_PROPRIETARY_CODECS) - supported_codecs |= media::EME_CODEC_MP4_AAC; + supported_codecs |= media::EME_CODEC_AAC; #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) } @@ -164,15 +164,15 @@ for (const auto& codec : supported_video_codecs) { switch (codec) { case media::VideoCodec::kCodecVP8: - supported_codecs |= media::EME_CODEC_WEBM_VP8; + supported_codecs |= media::EME_CODEC_VP8; break; case media::VideoCodec::kCodecVP9: - supported_codecs |= media::EME_CODEC_WEBM_VP9; - supported_codecs |= media::EME_CODEC_COMMON_VP9; + supported_codecs |= media::EME_CODEC_LEGACY_VP9; + supported_codecs |= media::EME_CODEC_VP9; break; #if BUILDFLAG(USE_PROPRIETARY_CODECS) case media::VideoCodec::kCodecH264: - supported_codecs |= media::EME_CODEC_MP4_AVC1; + supported_codecs |= media::EME_CODEC_AVC1; break; #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) default:
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index d11517d..ddc0d48 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1972,7 +1972,6 @@ "../browser/ui/cocoa/touchbar/browser_window_touch_bar_controller_browsertest.mm", "../browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm", "../browser/ui/cocoa/view_id_util_browsertest.mm", - "../browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac_browsertest.mm", ## TODO(crbug/845389): Re-Enable the following, which were temporarily ## omitted from the build, but still in use by the Cocoa browser. @@ -4128,11 +4127,8 @@ "../browser/ui/cocoa/browser_window_layout_unittest.mm", "../browser/ui/cocoa/browser_window_utils_unittest.mm", "../browser/ui/cocoa/chrome_browser_window_unittest.mm", - "../browser/ui/cocoa/clickhold_button_cell_unittest.mm", "../browser/ui/cocoa/color_panel_cocoa_unittest.mm", "../browser/ui/cocoa/confirm_quit_panel_controller_unittest.mm", - "../browser/ui/cocoa/constrained_window/constrained_window_alert_unittest.mm", - "../browser/ui/cocoa/constrained_window/constrained_window_button_unittest.mm", "../browser/ui/cocoa/constrained_window/constrained_window_custom_window_unittest.mm", "../browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm", "../browser/ui/cocoa/find_pasteboard_unittest.mm", @@ -4145,10 +4141,8 @@ "../browser/ui/cocoa/history_menu_cocoa_controller_unittest.mm", "../browser/ui/cocoa/history_overlay_controller_unittest.mm", "../browser/ui/cocoa/hover_close_button_unittest.mm", - "../browser/ui/cocoa/image_button_cell_unittest.mm", "../browser/ui/cocoa/main_menu_builder_unittest.mm", "../browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm", - "../browser/ui/cocoa/menu_button_unittest.mm", "../browser/ui/cocoa/notifications/notification_builder_mac_unittest.mm", "../browser/ui/cocoa/notifications/notification_response_builder_mac_unittest.mm", "../browser/ui/cocoa/nsmenuitem_additions_unittest.mm", @@ -4170,11 +4164,6 @@ "../browser/ui/cocoa/test/run_loop_testing_unittest.mm", "../browser/ui/cocoa/test/styled_text_field_test_helper.h", "../browser/ui/cocoa/test/styled_text_field_test_helper.mm", - "../browser/ui/cocoa/toolbar/app_toolbar_button_cell_unittest.mm", - "../browser/ui/cocoa/toolbar/app_toolbar_button_unittest.mm", - "../browser/ui/cocoa/toolbar/reload_button_unittest_cocoa.mm", - "../browser/ui/cocoa/toolbar/toolbar_button_unittest.mm", - "../browser/ui/cocoa/toolbar/toolbar_view_unittest.mm", "../browser/ui/cocoa/touchbar/browser_window_default_touch_bar_unittest.mm", "../browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm", "../browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm",
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc index c4e50e8..bb93d11f 100644 --- a/chrome/test/chromedriver/capabilities.cc +++ b/chrome/test/chromedriver/capabilities.cc
@@ -219,6 +219,30 @@ return Status(kInvalidArgument, "invalid 'unhandledPromptBehavior'"); } +Status ParseTimeouts(const base::Value& option, Capabilities* capabilities) { + const base::DictionaryValue* timeouts; + if (!option.GetAsDictionary(&timeouts)) + return Status(kInvalidArgument, "'timeouts' must be a JSON object"); + + std::map<std::string, Parser> parser_map; + parser_map["script"] = + base::BindRepeating(&ParseTimeDelta, &capabilities->script_timeout); + parser_map["pageLoad"] = + base::BindRepeating(&ParseTimeDelta, &capabilities->page_load_timeout); + parser_map["implicit"] = base::BindRepeating( + &ParseTimeDelta, &capabilities->implicit_wait_timeout); + + for (const auto& it : timeouts->DictItems()) { + if (parser_map.find(it.first) == parser_map.end()) + return Status(kInvalidArgument, + "unrecognized 'timeouts' option: " + it.first); + Status status = parser_map[it.first].Run(it.second, capabilities); + if (status.IsError()) + return Status(kInvalidArgument, "cannot parse " + it.first, status); + } + return Status(kOk); +} + Status ParseSwitches(const base::Value& option, Capabilities* capabilities) { const base::ListValue* switches_list = NULL; @@ -705,7 +729,7 @@ base::BindRepeating(&ParseString, &platform_name); parser_map["pageLoadStrategy"] = base::BindRepeating(&ParsePageLoadStrategy); parser_map["proxy"] = base::BindRepeating(&ParseProxy); - // TODO(https://crbug.com/chromedriver/1997): Parse "timeouts". + parser_map["timeouts"] = base::BindRepeating(&ParseTimeouts); // TODO(https://crbug.com/chromedriver/2596): "unexpectedAlertBehaviour" is // legacy name of "unhandledPromptBehavior", remove when we stop supporting // legacy mode.
diff --git a/chrome/test/chromedriver/capabilities.h b/chrome/test/chromedriver/capabilities.h index 425eeef1..ee890e27 100644 --- a/chrome/test/chromedriver/capabilities.h +++ b/chrome/test/chromedriver/capabilities.h
@@ -20,6 +20,7 @@ #include "chrome/test/chromedriver/chrome/devtools_http_client.h" #include "chrome/test/chromedriver/chrome/log.h" #include "chrome/test/chromedriver/net/net_util.h" +#include "chrome/test/chromedriver/session.h" namespace base { class CommandLine; @@ -119,10 +120,9 @@ // Data from "proxy" capability are stored in "switches" field. - // The default values for the timeout fields came from W3C spec. - base::TimeDelta script_timeout = base::TimeDelta::FromSeconds(30); - base::TimeDelta page_load_timeout = base::TimeDelta::FromSeconds(300); - base::TimeDelta implicit_wait_timeout = base::TimeDelta::FromSeconds(0); + base::TimeDelta script_timeout = Session::kDefaultScriptTimeout; + base::TimeDelta page_load_timeout = Session::kDefaultPageLoadTimeout; + base::TimeDelta implicit_wait_timeout = Session::kDefaultImplicitWaitTimeout; std::string unhandled_prompt_behavior;
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py index 5afa1605..f1d3074 100644 --- a/chrome/test/chromedriver/client/chromedriver.py +++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -132,7 +132,7 @@ send_w3c_capability=None, send_w3c_request=None, page_load_strategy=None, unexpected_alert_behaviour=None, devtools_events_to_log=None, accept_insecure_certs=None, - test_name=None): + timeouts=None, test_name=None): self._executor = command_executor.CommandExecutor(server_url) self.w3c_compliant = False @@ -230,6 +230,9 @@ if accept_insecure_certs is not None: params['acceptInsecureCerts'] = accept_insecure_certs + if timeouts is not None: + params['timeouts'] = timeouts + if test_name is not None: params['goog:testName'] = test_name @@ -360,6 +363,9 @@ return self.ExecuteCommand( Command.FIND_ELEMENTS, {'using': strategy, 'value': target}) + def GetTimeouts(self): + return self.ExecuteCommand(Command.GET_TIMEOUTS) + def SetTimeouts(self, params): return self.ExecuteCommand(Command.SET_TIMEOUTS, params)
diff --git a/chrome/test/chromedriver/session.cc b/chrome/test/chromedriver/session.cc index ab9eb29..30d0674c 100644 --- a/chrome/test/chromedriver/session.cc +++ b/chrome/test/chromedriver/session.cc
@@ -29,10 +29,13 @@ frame_id(frame_id), chromedriver_frame_id(chromedriver_frame_id) {} +// The default timeout values came from W3C spec. +const base::TimeDelta Session::kDefaultImplicitWaitTimeout = + base::TimeDelta::FromSeconds(0); const base::TimeDelta Session::kDefaultPageLoadTimeout = - base::TimeDelta::FromMinutes(5); + base::TimeDelta::FromSeconds(300); const base::TimeDelta Session::kDefaultScriptTimeout = - base::TimeDelta::FromMilliseconds(30000); + base::TimeDelta::FromSeconds(30); Session::Session(const std::string& id) : id(id), @@ -43,6 +46,7 @@ sticky_modifiers(0), mouse_position(0, 0), pressed_mouse_button(kNoneMouseButton), + implicit_wait(kDefaultImplicitWaitTimeout), page_load_timeout(kDefaultPageLoadTimeout), script_timeout(kDefaultScriptTimeout), auto_reporting_enabled(false) {} @@ -57,6 +61,7 @@ sticky_modifiers(0), mouse_position(0, 0), pressed_mouse_button(kNoneMouseButton), + implicit_wait(kDefaultImplicitWaitTimeout), page_load_timeout(kDefaultPageLoadTimeout), script_timeout(kDefaultScriptTimeout), auto_reporting_enabled(false) {}
diff --git a/chrome/test/chromedriver/session.h b/chrome/test/chromedriver/session.h index 24ca85d..2a26abc1 100644 --- a/chrome/test/chromedriver/session.h +++ b/chrome/test/chromedriver/session.h
@@ -50,6 +50,7 @@ }; struct Session { + static const base::TimeDelta kDefaultImplicitWaitTimeout; static const base::TimeDelta kDefaultPageLoadTimeout; static const base::TimeDelta kDefaultScriptTimeout;
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc index 3664417..ae63c03 100644 --- a/chrome/test/chromedriver/session_commands.cc +++ b/chrome/test/chromedriver/session_commands.cc
@@ -269,6 +269,10 @@ session->unhandled_prompt_behavior = capabilities.unhandled_prompt_behavior; + session->implicit_wait = capabilities.implicit_wait_timeout; + session->page_load_timeout = capabilities.page_load_timeout; + session->script_timeout = capabilities.script_timeout; + Log::Level driver_level = Log::kWarning; if (capabilities.logging_prefs.count(WebDriverLog::kDriverType)) driver_level = capabilities.logging_prefs[WebDriverLog::kDriverType];
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index 2a9245a..8a68c711 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -2159,6 +2159,25 @@ class ChromeDesiredCapabilityTest(ChromeDriverBaseTest): """Tests that chromedriver properly processes desired capabilities.""" + def testDefaultTimeouts(self): + driver = self.CreateDriver() + timeouts = driver.GetTimeouts() + # Compare against defaults in W3C spec + self.assertEquals(timeouts['implicit'], 0) + self.assertEquals(timeouts['pageLoad'], 300000) + self.assertEquals(timeouts['script'], 30000) + + def testTimeouts(self): + driver = self.CreateDriver(timeouts = { + 'implicit': 123, + 'pageLoad': 456, + 'script': 789 + }) + timeouts = driver.GetTimeouts() + self.assertEquals(timeouts['implicit'], 123) + self.assertEquals(timeouts['pageLoad'], 456) + self.assertEquals(timeouts['script'], 789) + def testUnexpectedAlertBehaviour(self): driver = self.CreateDriver(unexpected_alert_behaviour="accept") self.assertEquals("accept",
diff --git a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js index 26c4850..202ac10 100644 --- a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js +++ b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
@@ -166,6 +166,39 @@ settings_sections_tests.TestNames.DisableMarginsByPagesPerSheet); }); +PrintPreviewPagesSettingsTest = class extends NewPrintPreviewTest { + /** @override */ + get browsePreload() { + return 'chrome://print/new/pages_settings.html'; + } + + /** @override */ + get extraLibraries() { + return super.extraLibraries.concat([ + '../settings/test_util.js', + 'print_preview_test_utils.js', + 'pages_settings_test.js', + ]); + } + + /** @override */ + get suiteName() { + return pages_settings_test.suiteName; + } +}; + +TEST_F('PrintPreviewPagesSettingsTest', 'ValidPageRanges', function() { + this.runMochaTest(pages_settings_test.TestNames.ValidPageRanges); +}); + +TEST_F('PrintPreviewPagesSettingsTest', 'InvalidPageRanges', function() { + this.runMochaTest(pages_settings_test.TestNames.InvalidPageRanges); +}); + +TEST_F('PrintPreviewPagesSettingsTest', 'NupChangesPages', function() { + this.runMochaTest(pages_settings_test.TestNames.NupChangesPages); +}); + PrintPreviewPolicyTest = class extends NewPrintPreviewTest { /** @override */ get browsePreload() {
diff --git a/chrome/test/data/webui/print_preview/pages_settings_test.js b/chrome/test/data/webui/print_preview/pages_settings_test.js index 954fdc7..97f6cab7 100644 --- a/chrome/test/data/webui/print_preview/pages_settings_test.js +++ b/chrome/test/data/webui/print_preview/pages_settings_test.js
@@ -68,12 +68,15 @@ Polymer.dom.flush(); const input = pagesSection.$.pageSettingsCustomInput.inputElement; - const readyForInput = pagesSection.$$('#custom-radio-button').checked ? + const pagesSelect = pagesSection.$$('select'); + const readyForInput = + pagesSelect.value === pagesSection.pagesValueEnum_.CUSTOM.toString() ? Promise.resolve() : - test_util.eventToPromise('focus', input); + test_util.eventToPromise('process-select-change', pagesSection); // Select custom - pagesSection.$$('#custom-radio-button').click(); + pagesSelect.value = pagesSection.pagesValueEnum_.CUSTOM.toString(); + pagesSelect.dispatchEvent(new CustomEvent('change')); return readyForInput.then(() => { // Set input string input.value = inputString;
diff --git a/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js b/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js index e82fee6..c7a351f7 100644 --- a/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js +++ b/chrome/test/data/webui/print_preview/print_preview_interactive_ui_tests.js
@@ -99,36 +99,3 @@ this.runMochaTest( destination_dialog_interactive_test.TestNames.FocusSearchBox); }); - -PrintPreviewPagesSettingsTest = class extends PrintPreviewInteractiveUITest { - /** @override */ - get browsePreload() { - return 'chrome://print/new/pages_settings.html'; - } - - /** @override */ - get extraLibraries() { - return super.extraLibraries.concat([ - '../settings/test_util.js', - 'print_preview_test_utils.js', - 'pages_settings_test.js', - ]); - } - - /** @override */ - get suiteName() { - return pages_settings_test.suiteName; - } -}; - -TEST_F('PrintPreviewPagesSettingsTest', 'ValidPageRanges', function() { - this.runMochaTest(pages_settings_test.TestNames.ValidPageRanges); -}); - -TEST_F('PrintPreviewPagesSettingsTest', 'InvalidPageRanges', function() { - this.runMochaTest(pages_settings_test.TestNames.InvalidPageRanges); -}); - -TEST_F('PrintPreviewPagesSettingsTest', 'NupChangesPages', function() { - this.runMochaTest(pages_settings_test.TestNames.NupChangesPages); -});
diff --git a/chrome/test/data/webui/print_preview/settings_section_test.js b/chrome/test/data/webui/print_preview/settings_section_test.js index 99d676d..7941e30 100644 --- a/chrome/test/data/webui/print_preview/settings_section_test.js +++ b/chrome/test/data/webui/print_preview/settings_section_test.js
@@ -557,20 +557,21 @@ assertFalse(pagesElement.hidden); // Default value is all pages. Print ticket expects this to be empty. - const allRadio = pagesElement.$$('#all-radio-button'); - const customRadio = pagesElement.$$('#custom-radio-button'); + const pagesSelect = pagesElement.$$('select'); + const customInputCollapse = pagesElement.$$('iron-collapse'); const pagesCrInput = pagesElement.$.pageSettingsCustomInput; const pagesInput = pagesCrInput.inputElement; /** - * @param {boolean} allChecked Whether the all pages radio button is - * selected. + * @param {boolean} allSelected Whether the all pages option is selected. * @param {string} inputString The expected string in the pages input. * @param {boolean} valid Whether the input string is valid. */ - const validateInputState = function(allChecked, inputString, valid) { - assertEquals(allChecked, allRadio.checked); - assertEquals(!allChecked, customRadio.checked); + const validateInputState = function(allSelected, inputString, valid) { + assertEquals(allSelected, !customInputCollapse.opened); + assertEquals( + allSelected, + pagesSelect.value === pagesElement.pagesValueEnum_.ALL.toString()); assertEquals(inputString, pagesInput.value); assertEquals(valid, !pagesCrInput.invalid); }; @@ -580,15 +581,14 @@ assertTrue(page.settings.pages.valid); // Set selection of pages 1 and 2. - customRadio.click(); + pagesSelect.value = pagesElement.pagesValueEnum_.CUSTOM.toString(); + pagesSelect.dispatchEvent(new CustomEvent('change')); - // Manually set |customSelected_| since focus may not work correctly on - // MacOS. The PageSettingsTests verify this behavior is correct on all - // platforms. - pagesElement.set('customSelected_', true); - - triggerInputEvent(pagesInput, '1-2'); - return test_util.eventToPromise('input-change', pagesElement) + return test_util.eventToPromise('process-select-change', pagesElement) + .then(function() { + triggerInputEvent(pagesInput, '1-2'); + return test_util.eventToPromise('input-change', pagesElement); + }) .then(function() { validateInputState(false, '1-2', true); assertEquals(1, page.settings.ranges.value.length);
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn index 0432ad1..94d7255 100644 --- a/chromecast/base/BUILD.gn +++ b/chromecast/base/BUILD.gn
@@ -313,7 +313,6 @@ "$java_src_dir/org/chromium/chromecast/base/BiFunction.java", "$java_src_dir/org/chromium/chromecast/base/BiPredicate.java", "$java_src_dir/org/chromium/chromecast/base/Both.java", - "$java_src_dir/org/chromium/chromecast/base/CircularBuffer.java", "$java_src_dir/org/chromium/chromecast/base/Controller.java", "$java_src_dir/org/chromium/chromecast/base/Consumer.java", "$java_src_dir/org/chromium/chromecast/base/Function.java", @@ -359,7 +358,6 @@ java_files = [ "$java_test_dir/org/chromium/chromecast/base/BothTest.java", "$java_test_dir/org/chromium/chromecast/base/ControllerTest.java", - "$java_test_dir/org/chromium/chromecast/base/CircularBufferTest.java", "$java_test_dir/org/chromium/chromecast/base/ItertoolsTest.java", "$java_test_dir/org/chromium/chromecast/base/ObservableAndTest.java", "$java_test_dir/org/chromium/chromecast/base/ObservableAndThenTest.java",
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/CircularBuffer.java b/chromecast/base/java/src/org/chromium/chromecast/base/CircularBuffer.java deleted file mode 100644 index 8e0c33d..0000000 --- a/chromecast/base/java/src/org/chromium/chromecast/base/CircularBuffer.java +++ /dev/null
@@ -1,78 +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. - -package org.chromium.chromecast.base; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * An Iterable object that stores up to a fixed amount of objects, and overwrites the least-recently - * inserted object if it exceeds its capacity. Appending, removing, and iterating are all constant - * time. - * - * This class is intended as a fast Iterable Deque with a fixed capacity. LinkedList generates lint - * warnings because every item requires a heap allocation for the Node, ArrayList requires rewriting - * the list when the head is removed, and ArrayDeque is not fixed-size. - * - * Currently, the only supported use case is appending items to the buffer, and then iterating the - * buffer. Concurrent modification while iterating, or appending items after iterating, is - * undefined behavior as of now. - * - * @param <T> The type that elements of the buffer should be instances of. - */ -public class CircularBuffer<T> implements Iterable<T> { - private final List<T> mData; - private final int mSize; - private boolean mAtCapacity; - private int mHeadPosition; - private int mTailPosition; - - public CircularBuffer(int size) { - mData = new ArrayList<T>(size); - mSize = size; - mAtCapacity = false; - mHeadPosition = 0; - mTailPosition = 0; - } - - public void add(T item) { - if (mSize == 0) { - return; - } - if (mAtCapacity) { - mData.set(mHeadPosition, item); - mHeadPosition = increment(mHeadPosition); - } else { - mData.add(item); - } - mTailPosition = increment(mTailPosition); - if (mTailPosition == mHeadPosition) { - mAtCapacity = true; - } - } - - @Override - public Iterator<T> iterator() { - return new Iterator<T>() { - @Override - public boolean hasNext() { - return mAtCapacity || mHeadPosition != mTailPosition; - } - - @Override - public T next() { - T result = mData.get(mHeadPosition); - mHeadPosition = increment(mHeadPosition); - mAtCapacity = false; - return result; - } - }; - } - - private int increment(int position) { - return (position + 1) % mSize; - } -}
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/CircularBufferTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/CircularBufferTest.java deleted file mode 100644 index ec52b9b..0000000 --- a/chromecast/base/java/test/org/chromium/chromecast/base/CircularBufferTest.java +++ /dev/null
@@ -1,73 +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. - -package org.chromium.chromecast.base; - -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.emptyIterable; -import static org.junit.Assert.assertThat; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.BlockJUnit4ClassRunner; - -/** - * Tests for CircularBuffer. - * - * Currently, the only supported use case is appending items to the buffer, and then iterating the - * buffer. Concurrent modification while iterating, or appending items after iterating, is - * undefined behavior as of now. - */ -@RunWith(BlockJUnit4ClassRunner.class) -public class CircularBufferTest { - @Test - public void testBufferWithNoCapacity() { - CircularBuffer<String> buffer = new CircularBuffer<>(0); - buffer.add("a"); - assertThat(buffer, emptyIterable()); - } - - @Test - public void testBufferWithPartialCapacity() { - CircularBuffer<String> buffer = new CircularBuffer<>(4); - buffer.add("a"); - buffer.add("b"); - buffer.add("c"); - assertThat(buffer, contains("a", "b", "c")); - } - - @Test - public void testBufferWithFullCapacity() { - CircularBuffer<String> buffer = new CircularBuffer<>(4); - buffer.add("zero"); - buffer.add("one"); - buffer.add("two"); - buffer.add("three"); - assertThat(buffer, contains("zero", "one", "two", "three")); - } - - @Test - public void testBufferThatOverflowsCapacityWrapsAroundAndErasesOldestElements() { - CircularBuffer<String> buffer = new CircularBuffer<>(4); - buffer.add("1"); - buffer.add("2"); - buffer.add("3"); - buffer.add("4"); // Hits capacity; subsequent additions overwrite oldest elements. - buffer.add("5"); // erases "1" - buffer.add("6"); // erases "2" - assertThat(buffer, contains("3", "4", "5", "6")); - } - - @Test - public void testBufferThatOverflowsTwice() { - CircularBuffer<String> buffer = new CircularBuffer<>(2); - buffer.add("a"); - buffer.add("b"); - buffer.add("c"); - buffer.add("d"); - buffer.add("e"); - // Since the capacity is 2, return the 2 most-recently added items. - assertThat(buffer, contains("d", "e")); - } -}
diff --git a/chromecast/media/cma/backend/filter_group.cc b/chromecast/media/cma/backend/filter_group.cc index 2e5d9934..a4be583a 100644 --- a/chromecast/media/cma/backend/filter_group.cc +++ b/chromecast/media/cma/backend/filter_group.cc
@@ -198,6 +198,9 @@ } int64_t FilterGroup::GetRenderingDelayMicroseconds() { + if (output_samples_per_second_ == 0) { + return 0; + } return delay_frames_ * base::Time::kMicrosecondsPerSecond / output_samples_per_second_; }
diff --git a/chromecast/renderer/media/key_systems_cast.cc b/chromecast/renderer/media/key_systems_cast.cc index 73491048..da2796b 100644 --- a/chromecast/renderer/media/key_systems_cast.cc +++ b/chromecast/renderer/media/key_systems_cast.cc
@@ -110,32 +110,31 @@ #if BUILDFLAG(IS_CAST_USING_CMA_BACKEND) SupportedCodecs GetCastEmeSupportedCodecs() { - SupportedCodecs codecs = - ::media::EME_CODEC_MP4_AAC | ::media::EME_CODEC_MP4_AVC1 | - ::media::EME_CODEC_COMMON_VP9 | ::media::EME_CODEC_WEBM_VP8 | - ::media::EME_CODEC_WEBM_VP9; + SupportedCodecs codecs = ::media::EME_CODEC_AAC | ::media::EME_CODEC_AVC1 | + ::media::EME_CODEC_VP9 | ::media::EME_CODEC_VP8 | + ::media::EME_CODEC_LEGACY_VP9; #if !BUILDFLAG(DISABLE_SECURE_FLAC_OPUS_DECODING) - codecs |= ::media::EME_CODEC_MP4_FLAC | ::media::EME_CODEC_WEBM_OPUS; + codecs |= ::media::EME_CODEC_FLAC | ::media::EME_CODEC_OPUS; #endif // BUILDFLAG(DISABLE_SECURE_FLAC_OPUS_DECODING) #if BUILDFLAG(ENABLE_HEVC_DEMUXING) - codecs |= ::media::EME_CODEC_MP4_HEVC; + codecs |= ::media::EME_CODEC_HEVC; #endif // BUILDFLAG(ENABLE_HEVC_DEMUXING) #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) - codecs |= ::media::EME_CODEC_MP4_DV_AVC; + codecs |= ::media::EME_CODEC_DOLBY_VISION_AVC; #if BUILDFLAG(ENABLE_HEVC_DEMUXING) - codecs |= ::media::EME_CODEC_MP4_DV_HEVC; + codecs |= ::media::EME_CODEC_DOLBY_VISION_HEVC; #endif // BUILDFLAG(ENABLE_HEVC_DEMUXING) #endif // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) - codecs |= ::media::EME_CODEC_MP4_AC3 | ::media::EME_CODEC_MP4_EAC3; + codecs |= ::media::EME_CODEC_AC3 | ::media::EME_CODEC_EAC3; #endif // BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) #if BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING) - codecs |= ::media::EME_CODEC_MP4_MPEG_H_AUDIO; + codecs |= ::media::EME_CODEC_MPEG_H_AUDIO; #endif // BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING) return codecs;
diff --git a/chromeos/chromeos_features.cc b/chromeos/chromeos_features.cc index 2b8e7784..e6c444d3 100644 --- a/chromeos/chromeos_features.cc +++ b/chromeos/chromeos_features.cc
@@ -45,6 +45,13 @@ const base::Feature kMultiDeviceApi{"MultiDeviceApi", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables or disables user activity prediction for power management on +// Chrome OS. +// Defined here rather than in //chrome alongside other related features so that +// PowerPolicyController can check it. +const base::Feature kUserActivityPrediction{"UserActivityPrediction", + base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace chromeos
diff --git a/chromeos/chromeos_features.h b/chromeos/chromeos_features.h index 9fcdab82..3b4d0f4 100644 --- a/chromeos/chromeos_features.h +++ b/chromeos/chromeos_features.h
@@ -23,8 +23,8 @@ CHROMEOS_EXPORT extern const base::Feature kEnableUnifiedMultiDeviceSetup; CHROMEOS_EXPORT extern const base::Feature kImeServiceConnectable; CHROMEOS_EXPORT extern const base::Feature kInstantTethering; - CHROMEOS_EXPORT extern const base::Feature kMultiDeviceApi; +CHROMEOS_EXPORT extern const base::Feature kUserActivityPrediction; } // namespace features
diff --git a/chromeos/components/tether/host_scan_scheduler_impl.cc b/chromeos/components/tether/host_scan_scheduler_impl.cc index 8fac55f..e790ab63b 100644 --- a/chromeos/components/tether/host_scan_scheduler_impl.cc +++ b/chromeos/components/tether/host_scan_scheduler_impl.cc
@@ -138,11 +138,7 @@ is_screen_locked_ = session_manager_->IsScreenLocked(); if (is_screen_locked_) { - // If the screen is now locked, stop any ongoing scan. A scan during the - // lock screen could cause bad interactions with EasyUnlock. See - // https://crbug.com/763604. - // Note: Once the SecureChannel API is in use, the scan will no longer have - // to stop. + // If the screen is now locked, stop any ongoing scan. host_scanner_->StopScan(); if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) delay_scan_after_unlock_timer_->Stop(); @@ -182,11 +178,9 @@ if (host_scanner_->IsScanActive()) return; - // If the SecureChannel API is not present, and the screen is locked, a host - // scan should not occur. A scan during the lock screen could cause bad - // interactions with EasyUnlock. See https://crbug.com/763604. - if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi) && - session_manager_->IsScreenLocked()) { + // If the screen is locked, a host scan should not occur. + if (session_manager_->IsScreenLocked()) { + PA_LOG(INFO) << "Skipping scan attempt because the screen is locked."; return; }
diff --git a/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc b/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc index b96601b9..52e8e49 100644 --- a/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc +++ b/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc
@@ -192,23 +192,21 @@ SetMultiDeviceApiEnabled(); - // Lock the screen. This should not trigger a scan. + // Lock the screen. This should never trigger a scan. SetScreenLockedState(true /* is_locked */); EXPECT_EQ(0u, fake_host_scanner_->num_scans_started()); EXPECT_FALSE(mock_delay_scan_after_unlock_timer_->IsRunning()); - // Try to start a scan. Regardless of screen lock state, this should cause a - // scan if the device is offline. The timer should not have been started. + // Try to start a scan. Because the screen is locked, this should not + // cause a scan to be started. host_scan_scheduler_->AttemptScanIfOffline(); - EXPECT_EQ(is_online ? 0u : 1u, fake_host_scanner_->num_scans_started()); + EXPECT_EQ(0u, fake_host_scanner_->num_scans_started()); EXPECT_FALSE(mock_delay_scan_after_unlock_timer_->IsRunning()); - fake_host_scanner_->StopScan(); - // Unlock the screen. If the device is offline, a new scan should have // started. The timer should be untouched. SetScreenLockedState(false /* is_locked */); - EXPECT_EQ(is_online ? 0u : 2u, fake_host_scanner_->num_scans_started()); + EXPECT_EQ(is_online ? 0u : 1u, fake_host_scanner_->num_scans_started()); EXPECT_FALSE(mock_delay_scan_after_unlock_timer_->IsRunning()); }
diff --git a/chromeos/dbus/DEPS b/chromeos/dbus/DEPS index 1d90fba1..840af75 100644 --- a/chromeos/dbus/DEPS +++ b/chromeos/dbus/DEPS
@@ -3,6 +3,7 @@ include_rules = [ "+base", "+chromeos/chromeos_export.h", + "+chromeos/chromeos_features.h", "+components/account_id/account_id.h", "+components/device_event_log", "+components/policy/proto",
diff --git a/chromeos/dbus/power_policy_controller.cc b/chromeos/dbus/power_policy_controller.cc index bc39c41..634be59 100644 --- a/chromeos/dbus/power_policy_controller.cc +++ b/chromeos/dbus/power_policy_controller.cc
@@ -8,10 +8,12 @@ #include <utility> +#include "base/feature_list.h" #include "base/format_macros.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "chromeos/chromeos_features.h" // Avoid some ugly line-wrapping later. using base::StringAppendF; @@ -111,7 +113,8 @@ presentation_screen_dim_delay_factor(1.0), user_activity_screen_dim_delay_factor(1.0), wait_for_initial_user_activity(false), - force_nonzero_brightness_for_user_activity(true) {} + force_nonzero_brightness_for_user_activity(true), + smart_dim_enabled(true) {} // static std::string PowerPolicyController::GetPolicyDebugString( @@ -236,10 +239,22 @@ prefs_policy_.set_battery_brightness_percent( values.battery_brightness_percent); } - prefs_policy_.set_presentation_screen_dim_delay_factor( - values.presentation_screen_dim_delay_factor); - prefs_policy_.set_user_activity_screen_dim_delay_factor( - values.user_activity_screen_dim_delay_factor); + + // Screen-dim deferral in response to user activity predictions can + // interact poorly with delay scaling, resulting in the system staying + // awake for a long time if a prediction is wrong. See + // https://crbug.com/888392. + if (values.smart_dim_enabled && + base::FeatureList::IsEnabled(features::kUserActivityPrediction)) { + prefs_policy_.set_presentation_screen_dim_delay_factor(1.0); + prefs_policy_.set_user_activity_screen_dim_delay_factor(1.0); + } else { + prefs_policy_.set_presentation_screen_dim_delay_factor( + values.presentation_screen_dim_delay_factor); + prefs_policy_.set_user_activity_screen_dim_delay_factor( + values.user_activity_screen_dim_delay_factor); + } + prefs_policy_.set_wait_for_initial_user_activity( values.wait_for_initial_user_activity); prefs_policy_.set_force_nonzero_brightness_for_user_activity(
diff --git a/chromeos/dbus/power_policy_controller.h b/chromeos/dbus/power_policy_controller.h index 38a4b572..1c55d65 100644 --- a/chromeos/dbus/power_policy_controller.h +++ b/chromeos/dbus/power_policy_controller.h
@@ -77,6 +77,7 @@ double user_activity_screen_dim_delay_factor; bool wait_for_initial_user_activity; bool force_nonzero_brightness_for_user_activity; + bool smart_dim_enabled; }; // Returns a string describing |policy|. Useful for tests.
diff --git a/chromeos/dbus/power_policy_controller_unittest.cc b/chromeos/dbus/power_policy_controller_unittest.cc index f9a7c09..547035f2 100644 --- a/chromeos/dbus/power_policy_controller_unittest.cc +++ b/chromeos/dbus/power_policy_controller_unittest.cc
@@ -7,6 +7,8 @@ #include <memory> #include "base/message_loop/message_loop.h" +#include "base/test/scoped_feature_list.h" +#include "chromeos/chromeos_features.h" #include "chromeos/dbus/fake_power_manager_client.h" #include "testing/gtest/include/gtest/gtest.h" @@ -325,4 +327,40 @@ fake_power_client_->policy())); } +TEST_F(PowerPolicyControllerTest, SmartDimEnabledExperimentEnabled) { + const std::map<std::string, std::string> params = { + {"dim_threshold", "0.651"}}; + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + chromeos::features::kUserActivityPrediction, params); + + PowerPolicyController::PrefValues prefs; + policy_controller_->ApplyPrefs(prefs); + const power_manager::PowerManagementPolicy kDefaultPolicy = + fake_power_client_->policy(); + + // First disable smart dim model. + prefs.smart_dim_enabled = false; + prefs.presentation_screen_dim_delay_factor = 3.0; + prefs.user_activity_screen_dim_delay_factor = 2.0; + policy_controller_->ApplyPrefs(prefs); + + power_manager::PowerManagementPolicy expected_policy = kDefaultPolicy; + expected_policy.set_presentation_screen_dim_delay_factor(3.0); + expected_policy.set_user_activity_screen_dim_delay_factor(2.0); + EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy), + PowerPolicyController::GetPolicyDebugString( + fake_power_client_->policy())); + + // Then enable smart dim model. + prefs.smart_dim_enabled = true; + policy_controller_->ApplyPrefs(prefs); + + expected_policy.set_presentation_screen_dim_delay_factor(1.0); + expected_policy.set_user_activity_screen_dim_delay_factor(1.0); + EXPECT_EQ(PowerPolicyController::GetPolicyDebugString(expected_policy), + PowerPolicyController::GetPolicyDebugString( + fake_power_client_->policy())); +} + } // namespace chromeos
diff --git a/components/autofill/content/browser/risk/fingerprint.cc b/components/autofill/content/browser/risk/fingerprint.cc index e6fd910..f12c1b09 100644 --- a/components/autofill/content/browser/risk/fingerprint.cc +++ b/components/autofill/content/browser/risk/fingerprint.cc
@@ -194,7 +194,7 @@ const std::string& app_locale, const std::string& user_agent, const base::TimeDelta& timeout, - const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback, + base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback, service_manager::Connector* connector); private: @@ -249,7 +249,7 @@ base::OneShotTimer timeout_timer_; // The callback that will be called once all the data is available. - base::Callback<void(std::unique_ptr<Fingerprint>)> callback_; + base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback_; // For invalidating asynchronous callbacks that might arrive after |this| // instance is destroyed. @@ -270,7 +270,7 @@ const std::string& app_locale, const std::string& user_agent, const base::TimeDelta& timeout, - const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback, + base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback, service_manager::Connector* connector) : gpu_data_manager_(content::GpuDataManager::GetInstance()), gpu_observer_(this), @@ -285,7 +285,7 @@ user_agent_(user_agent), install_time_(install_time), waiting_on_plugins_(true), - callback_(callback), + callback_(std::move(callback)), weak_ptr_factory_(this) { DCHECK(!install_time_.is_null()); @@ -437,7 +437,7 @@ metadata->set_obfuscated_gaia_id(obfuscated_gaia_id_); metadata->set_fingerprinter_version(kFingerprinterVersion); - callback_.Run(std::move(fingerprint)); + std::move(callback_).Run(std::move(fingerprint)); } } // namespace @@ -456,14 +456,14 @@ const std::string& app_locale, const std::string& user_agent, const base::TimeDelta& timeout, - const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback, + base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback, service_manager::Connector* connector) { // Begin loading all of the data that we need to load asynchronously. // This class is responsible for freeing its own memory. new FingerprintDataLoader(obfuscated_gaia_id, window_bounds, content_bounds, screen_info, version, charset, accept_languages, install_time, app_locale, user_agent, timeout, - callback, connector); + std::move(callback), connector); } } // namespace internal @@ -478,7 +478,7 @@ const base::Time& install_time, const std::string& app_locale, const std::string& user_agent, - const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback, + base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback, service_manager::Connector* connector) { gfx::Rect content_bounds = web_contents->GetContainerBounds(); @@ -491,7 +491,8 @@ internal::GetFingerprintInternal( obfuscated_gaia_id, window_bounds, content_bounds, screen_info, version, charset, accept_languages, install_time, app_locale, user_agent, - base::TimeDelta::FromSeconds(kTimeoutSeconds), callback, connector); + base::TimeDelta::FromSeconds(kTimeoutSeconds), std::move(callback), + connector); } } // namespace risk
diff --git a/components/autofill/content/browser/risk/fingerprint.h b/components/autofill/content/browser/risk/fingerprint.h index 7b45019d..235cca8 100644 --- a/components/autofill/content/browser/risk/fingerprint.h +++ b/components/autofill/content/browser/risk/fingerprint.h
@@ -59,7 +59,7 @@ const base::Time& install_time, const std::string& app_locale, const std::string& user_agent, - const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback, + const base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback, service_manager::Connector* connector); } // namespace risk
diff --git a/components/autofill/content/browser/risk/fingerprint_browsertest.cc b/components/autofill/content/browser/risk/fingerprint_browsertest.cc index 24ddc8af..3c461f2b 100644 --- a/components/autofill/content/browser/risk/fingerprint_browsertest.cc +++ b/components/autofill/content/browser/risk/fingerprint_browsertest.cc
@@ -46,7 +46,7 @@ const std::string& app_locale, const std::string& user_agent, const base::TimeDelta& timeout, - const base::Callback<void(std::unique_ptr<Fingerprint>)>& callback, + base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback, service_manager::Connector* connector); } // namespace internal
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h index 50d1e2b..a981f74 100644 --- a/components/autofill/core/browser/autofill_client.h +++ b/components/autofill/core/browser/autofill_client.h
@@ -157,7 +157,7 @@ // Runs |callback| if the |card| should be imported as personal data. // |metric_logger| can be used to log user actions. virtual void ConfirmSaveCreditCardLocally(const CreditCard& card, - const base::Closure& callback) = 0; + base::OnceClosure callback) = 0; // Runs |callback| if the |card| should be uploaded to Payments. Displays the // contents of |legal_message| to the user. Displays a cardholder name
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc index 7094f20..86b8544 100644 --- a/components/autofill/core/browser/autofill_metrics.cc +++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -851,6 +851,45 @@ } // static +void AutofillMetrics::LogLocalCardMigrationDialogOfferMetric( + LocalCardMigrationDialogOfferMetric metric) { + DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS); + std::string histogram_name = "Autofill.LocalCardMigrationDialogOffer"; + base::UmaHistogramEnumeration(histogram_name, metric, + NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS); +} + +// static +void AutofillMetrics::LogLocalCardMigrationDialogUserInteractionMetric( + const base::TimeDelta& duration, + const int selected, + const int total, + LocalCardMigrationDialogUserInteractionMetric metric) { + DCHECK_LT(metric, NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS); + base::UmaHistogramEnumeration( + "Autofill.LocalCardMigrationDialogUserInteraction", metric, + NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS); + std::string suffix; + switch (metric) { + case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED: + suffix = "Accepted"; + break; + case LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED: + suffix = "Denied"; + break; + default: + return; + } + base::UmaHistogramLongTimes("Autofill.LocalCardMigrationDialogActiveDuration", + duration); + base::UmaHistogramLongTimes( + "Autofill.LocalCardMigrationDialogActiveDuration." + suffix, duration); + UMA_HISTOGRAM_PERCENTAGE( + "Autofill.LocalCardMigrationDialogUserSelectionPercentage", + 100 * selected / total); +} + +// static void AutofillMetrics::LogLocalCardMigrationPromptMetric( LocalCardMigrationOrigin local_card_migration_origin, LocalCardMigrationPromptMetric metric) {
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h index 4ed3244..20eb82a8 100644 --- a/components/autofill/core/browser/autofill_metrics.h +++ b/components/autofill/core/browser/autofill_metrics.h
@@ -443,6 +443,26 @@ NUM_LOCAL_CARD_MIGRATION_BUBBLE_USER_INTERACTION_METRICS, }; + // Metrics to track events when local card migration dialog is offered. + enum LocalCardMigrationDialogOfferMetric { + // The dialog is shown to the user. + LOCAL_CARD_MIGRATION_DIALOG_SHOWN = 0, + // The dialog is not shown due to legal message being invalid. + LOCAL_CARD_MIGRATION_DIALOG_NOT_SHOWN_INVALID_LEGAL_MESSAGE = 1, + NUM_LOCAL_CARD_MIGRATION_DIALOG_OFFER_METRICS, + }; + + // Metrics to track user interactions with the dialog. + enum LocalCardMigrationDialogUserInteractionMetric { + // The user explicitly accepts the offer by clicking the save button. + LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED = 0, + // The user explicitly denies the offer by clicking the cancel button. + LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED = 1, + // The user clicks the legal message. + LOCAL_CARD_MIGRATION_DIALOG_LEGAL_MESSAGE_CLICKED = 2, + NUM_LOCAL_CARD_MIGRATION_DIALOG_USER_INTERACTION_METRICS, + }; + // These metrics are logged for each local card migration origin. These are // used to derive the conversion rate for each triggering source. enum LocalCardMigrationPromptMetric { @@ -886,6 +906,13 @@ static void LogLocalCardMigrationBubbleUserInteractionMetric( LocalCardMigrationBubbleUserInteractionMetric metric, bool is_reshow); + static void LogLocalCardMigrationDialogOfferMetric( + LocalCardMigrationDialogOfferMetric metric); + static void LogLocalCardMigrationDialogUserInteractionMetric( + const base::TimeDelta& duration, + const int selected, + const int total, + LocalCardMigrationDialogUserInteractionMetric metric); static void LogLocalCardMigrationPromptMetric( LocalCardMigrationOrigin local_card_migration_origin, LocalCardMigrationPromptMetric metric);
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc index 098480b..0ab21701 100644 --- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc +++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -31,12 +31,12 @@ const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, base::OnceCallback<void(const base::string16&)> upload_save_card_callback, - base::Closure local_save_card_callback, + base::OnceClosure local_save_card_callback, PrefService* pref_service) : ConfirmInfoBarDelegate(), upload_(upload), upload_save_card_callback_(std::move(upload_save_card_callback)), - local_save_card_callback_(local_save_card_callback), + local_save_card_callback_(std::move(local_save_card_callback)), pref_service_(pref_service), had_user_interaction_(false), issuer_icon_id_(CreditCard::IconResourceId(card.network())), @@ -155,12 +155,10 @@ } bool AutofillSaveCardInfoBarDelegateMobile::Accept() { - if (upload_) { + if (upload_) std::move(upload_save_card_callback_).Run(base::string16()); - } else { - local_save_card_callback_.Run(); - local_save_card_callback_.Reset(); - } + else + std::move(local_save_card_callback_).Run(); LogUserAction(AutofillMetrics::INFOBAR_ACCEPTED); return true; }
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h index 8295b749..0b61d2df 100644 --- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h +++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
@@ -33,7 +33,7 @@ const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, base::OnceCallback<void(const base::string16&)> upload_save_card_callback, - base::Closure local_save_card_callback, + base::OnceClosure local_save_card_callback, PrefService* pref_service); ~AutofillSaveCardInfoBarDelegateMobile() override; @@ -80,7 +80,7 @@ // The callback to save the credit card locally to the device if |upload_| is // false and the user accepts the infobar. - base::Closure local_save_card_callback_; + base::OnceClosure local_save_card_callback_; // Weak reference to read & write |kAutofillAcceptSaveCreditCardPromptState|, PrefService* pref_service_;
diff --git a/components/autofill/core/browser/credit_card_save_manager.cc b/components/autofill/core/browser/credit_card_save_manager.cc index 78bb7095..f9ffa7df 100644 --- a/components/autofill/core/browser/credit_card_save_manager.cc +++ b/components/autofill/core/browser/credit_card_save_manager.cc
@@ -88,9 +88,10 @@ if (observer_for_testing_) observer_for_testing_->OnOfferLocalSave(); client_->ConfirmSaveCreditCardLocally( - card, base::Bind(base::IgnoreResult( - &PersonalDataManager::OnAcceptedLocalCreditCardSave), - base::Unretained(personal_data_manager_), card)); + card, + base::BindOnce(base::IgnoreResult( + &PersonalDataManager::OnAcceptedLocalCreditCardSave), + base::Unretained(personal_data_manager_), card)); } void CreditCardSaveManager::AttemptToOfferCardUploadSave( @@ -263,8 +264,8 @@ base::BindOnce(&CreditCardSaveManager::OnUserDidAcceptUpload, weak_ptr_factory_.GetWeakPtr())); client_->LoadRiskData( - base::Bind(&CreditCardSaveManager::OnDidGetUploadRiskData, - weak_ptr_factory_.GetWeakPtr())); + base::BindOnce(&CreditCardSaveManager::OnDidGetUploadRiskData, + weak_ptr_factory_.GetWeakPtr())); upload_decision_metrics_ |= AutofillMetrics::UPLOAD_OFFERED; AutofillMetrics::LogUploadOfferedCardOriginMetric( uploading_local_card_ ? AutofillMetrics::OFFERING_UPLOAD_OF_LOCAL_CARD
diff --git a/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/credit_card_save_manager_unittest.cc index cb73604..308acee 100644 --- a/components/autofill/core/browser/credit_card_save_manager_unittest.cc +++ b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
@@ -92,7 +92,7 @@ ~MockAutofillClient() override {} MOCK_METHOD2(ConfirmSaveCreditCardLocally, - void(const CreditCard& card, const base::Closure& callback)); + void(const CreditCard& card, base::OnceClosure callback)); private: DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
diff --git a/components/autofill/core/browser/proto/server.proto b/components/autofill/core/browser/proto/server.proto index 39cb0de..9389048 100644 --- a/components/autofill/core/browser/proto/server.proto +++ b/components/autofill/core/browser/proto/server.proto
@@ -179,11 +179,16 @@ // 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: 34 +// Next available id: 35 message AutofillUploadContents { required string client_version = 1; required fixed64 form_signature = 2; + // The secondary form signature is calculated based on field types instead of + // names and is used if the primary one is unstable, i.e. the field names + // change on every page load. + optional fixed64 secondary_form_signature = 34; + // True if the autofill feature was used to fill this form, false otherwise. required bool autofill_used = 3;
diff --git a/components/autofill/core/browser/risk_data_loader.h b/components/autofill/core/browser/risk_data_loader.h index be3def3..2b8468bb 100644 --- a/components/autofill/core/browser/risk_data_loader.h +++ b/components/autofill/core/browser/risk_data_loader.h
@@ -15,7 +15,7 @@ public: // Gathers risk data and provides it to |callback|. virtual void LoadRiskData( - const base::Callback<void(const std::string&)>& callback) = 0; + base::OnceCallback<void(const std::string&)> callback) = 0; protected: virtual ~RiskDataLoader() {}
diff --git a/components/autofill/core/browser/test_autofill_client.cc b/components/autofill/core/browser/test_autofill_client.cc index 6512f11..ff83670 100644 --- a/components/autofill/core/browser/test_autofill_client.cc +++ b/components/autofill/core/browser/test_autofill_client.cc
@@ -100,8 +100,7 @@ void TestAutofillClient::ConfirmSaveCreditCardLocally( const CreditCard& card, - const base::Closure& callback) { -} + base::OnceClosure callback) {} void TestAutofillClient::ConfirmSaveCreditCardToCloud( const CreditCard& card, @@ -118,8 +117,8 @@ } void TestAutofillClient::LoadRiskData( - const base::Callback<void(const std::string&)>& callback) { - callback.Run("some risk data"); + base::OnceCallback<void(const std::string&)> callback) { + std::move(callback).Run("some risk data"); } bool TestAutofillClient::HasCreditCardScanFeature() {
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h index 19c8b3a..fccf5e3 100644 --- a/components/autofill/core/browser/test_autofill_client.h +++ b/components/autofill/core/browser/test_autofill_client.h
@@ -51,7 +51,7 @@ void ConfirmSaveAutofillProfile(const AutofillProfile& profile, base::OnceClosure callback) override; void ConfirmSaveCreditCardLocally(const CreditCard& card, - const base::Closure& callback) override; + base::OnceClosure callback) override; void ConfirmSaveCreditCardToCloud( const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, @@ -60,7 +60,7 @@ void ConfirmCreditCardFillAssist(const CreditCard& card, const base::Closure& callback) override; void LoadRiskData( - const base::Callback<void(const std::string&)>& callback) override; + base::OnceCallback<void(const std::string&)> callback) override; bool HasCreditCardScanFeature() override; void ScanCreditCard(const CreditCardScanCallback& callback) override; void ShowAutofillPopup(
diff --git a/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h b/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h index 75d014d..4696d2606 100644 --- a/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h +++ b/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h
@@ -31,6 +31,7 @@ const std::vector<std::string>& selected_cards_guids) = 0; virtual void OnCancelButtonClicked() = 0; virtual void OnViewCardsButtonClicked() = 0; + virtual void OnLegalMessageLinkClicked() = 0; virtual void OnDialogClosed() = 0; private:
diff --git a/components/blacklist/README.md b/components/blacklist/README.md index f83cc36..d08198a 100644 --- a/components/blacklist/README.md +++ b/components/blacklist/README.md
@@ -1,36 +1,8 @@ # Blacklist component # The goal of the blacklist component is to provide various blacklists that allow -different policies for features to consume. Below are various types of blacklist -included within the component. - -## Bloom filter blacklist ## -The Bloom filter blacklist allows blocking specific strings (hosts) based on a -probabilistic data structure that represents a host as a hashed value. -Collisions are possible (false positive matches), and the consumer is -responsible for determining what action to take when a match occurs. The -implementation uses MurmurHash3 in coordination with wherever (i.e., the server -that ships it) the bloom filter is generated. - -### Expected behavior ### -The consumer needs to supply a Bloom filter, the number of times to hash the -string, and the number of bits that the Bloom filter occupies. Calling Contains, -will inform the consumer whether the string is included in the Bloom filter, and -these should be considered strings that are not allowed to be used for the -consumer feature. - -### Host filter ### -HostFilter uses an internal Bloom filter to blacklist host names. It uses the -Bloom filter to store blacklisted host name suffixes. Given a URL, HostFilter -will check the URL's host name for any blacklisted host suffixes. The host -filter will look for matching sub-domains and the full domain in the Bloom -filter, and will treat any match as a blacklisted host. For instance, a host -like a.b.c.d.e.chromium.org would match any of the following if they appeared in -the Bloom filter: a.b.c.d.e.chromium.org, chromium.org, e.chromium.org, -d.e.chromium.org, c.d.e.chromium.org. Note that b.c.d.e.chromium.org is not -included, as the default implementation checks the full host, and four other -sub-domains, looking at the most granular to least granular. Hosts with top -level domains of more than 6 characters are not supported. +different policies for features to consume. Currently, the only implemented +blacklist is the opt out blacklist. ## Opt out blacklist ## The opt out blacklist makes decisions based on user history actions. Each user
diff --git a/components/cdm/browser/cdm_message_filter_android.cc b/components/cdm/browser/cdm_message_filter_android.cc index d43d766..7a986ed8 100644 --- a/components/cdm/browser/cdm_message_filter_android.cc +++ b/components/cdm/browser/cdm_message_filter_android.cc
@@ -37,19 +37,19 @@ }; const CodecInfo<media::VideoCodec> kVideoCodecsToQuery[] = { - {media::EME_CODEC_WEBM_VP8, media::kCodecVP8, "video/webm"}, - {media::EME_CODEC_WEBM_VP9, media::kCodecVP9, "video/webm"}, - {media::EME_CODEC_COMMON_VP9, media::kCodecVP9, "video/webm"}, - {media::EME_CODEC_COMMON_VP9, media::kCodecVP9, "video/mp4"}, + {media::EME_CODEC_VP8, media::kCodecVP8, "video/webm"}, + {media::EME_CODEC_LEGACY_VP9, media::kCodecVP9, "video/webm"}, + {media::EME_CODEC_VP9, media::kCodecVP9, "video/webm"}, + {media::EME_CODEC_VP9, media::kCodecVP9, "video/mp4"}, #if BUILDFLAG(USE_PROPRIETARY_CODECS) - {media::EME_CODEC_MP4_AVC1, media::kCodecH264, "video/mp4"}, + {media::EME_CODEC_AVC1, media::kCodecH264, "video/mp4"}, #if BUILDFLAG(ENABLE_HEVC_DEMUXING) - {media::EME_CODEC_MP4_HEVC, media::kCodecHEVC, "video/mp4"}, + {media::EME_CODEC_HEVC, media::kCodecHEVC, "video/mp4"}, #endif #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) - {media::EME_CODEC_MP4_DV_AVC, media::kCodecDolbyVision, "video/mp4"}, + {media::EME_CODEC_DOLBY_VISION_AVC, media::kCodecDolbyVision, "video/mp4"}, #if BUILDFLAG(ENABLE_HEVC_DEMUXING) - {media::EME_CODEC_MP4_DV_HEVC, media::kCodecDolbyVision, "video/mp4"}, + {media::EME_CODEC_DOLBY_VISION_HEVC, media::kCodecDolbyVision, "video/mp4"}, #endif #endif #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) @@ -58,12 +58,12 @@ const CodecInfo<media::AudioCodec> kAudioCodecsToQuery[] = { // FLAC is not supported. See https://crbug.com/747050 for details. // Vorbis is not supported. See http://crbug.com/710924 for details. - {media::EME_CODEC_WEBM_OPUS, media::kCodecOpus, "video/webm"}, + {media::EME_CODEC_OPUS, media::kCodecOpus, "video/webm"}, #if BUILDFLAG(USE_PROPRIETARY_CODECS) - {media::EME_CODEC_MP4_AAC, media::kCodecAAC, "video/mp4"}, + {media::EME_CODEC_AAC, media::kCodecAAC, "video/mp4"}, #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) - {media::EME_CODEC_MP4_AC3, media::kCodecAC3, "video/mp4"}, - {media::EME_CODEC_MP4_EAC3, media::kCodecEAC3, "video/mp4"}, + {media::EME_CODEC_AC3, media::kCodecAC3, "video/mp4"}, + {media::EME_CODEC_EAC3, media::kCodecEAC3, "video/mp4"}, #endif #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) };
diff --git a/components/constrained_window/BUILD.gn b/components/constrained_window/BUILD.gn index de9893a..33ae96c 100644 --- a/components/constrained_window/BUILD.gn +++ b/components/constrained_window/BUILD.gn
@@ -14,17 +14,9 @@ "native_web_contents_modal_dialog_manager_views.h", "native_web_contents_modal_dialog_manager_views_mac.h", "native_web_contents_modal_dialog_manager_views_mac.mm", + "show_modal_dialog_views.cc", ] - if (is_mac) { - sources += [ "show_modal_dialog_cocoa.cc" ] - if (mac_views_browser) { - sources += [ "show_modal_dialog_views.cc" ] - } - } else { - sources += [ "show_modal_dialog_views.cc" ] - } - deps = [ "//components/guest_view/browser", "//components/web_modal", @@ -52,10 +44,6 @@ "constrained_window_views_unittest.cc", ] - if (is_mac) { - sources += [ "test_create_native_web_modal_manager_cocoa.cc" ] - } - deps = [ ":constrained_window", "//components/web_modal:test_support",
diff --git a/components/constrained_window/show_modal_dialog_cocoa.cc b/components/constrained_window/show_modal_dialog_cocoa.cc deleted file mode 100644 index 33b3da1..0000000 --- a/components/constrained_window/show_modal_dialog_cocoa.cc +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <memory> - -#include "components/constrained_window/constrained_window_views.h" -#include "components/web_modal/single_web_contents_dialog_manager.h" -#include "components/web_modal/web_contents_modal_dialog_manager.h" -#include "content/public/browser/web_contents.h" -#include "ui/base/ui_features.h" -#include "ui/gfx/native_widget_types.h" - -// TODO(patricialor): This is a layering violation and should be deleted. -// Currently it's needed because on Cocoa, the dialog needs to be shown with a -// SingleWebContentsDialogManagerViewsMac, which depends on things inside -// chrome/browser/ui/cocoa/constrained_window/* and thus can't be moved out into -// components/constrained_window/*. Instead, to get this to work, the -// CreateNativeWebModalManager() method is declared in the web_modal component, -// but defined outside of that in c/b/u/cocoa/. - -namespace constrained_window { - -void ShowModalDialogCocoa(gfx::NativeWindow dialog, - content::WebContents* initiator_web_contents) { - web_modal::WebContentsModalDialogManager* manager = - web_modal::WebContentsModalDialogManager::FromWebContents( - initiator_web_contents); - std::unique_ptr<web_modal::SingleWebContentsDialogManager> dialog_manager( - web_modal::WebContentsModalDialogManager::CreateNativeWebModalManager( - dialog, manager)); - manager->ShowDialogWithManager(dialog, std::move(dialog_manager)); -} - -#if !BUILDFLAG(MAC_VIEWS_BROWSER) -void ShowModalDialog(gfx::NativeWindow dialog, - content::WebContents* initiator_web_contents) { - ShowModalDialogCocoa(dialog, initiator_web_contents); -} -#endif - -} // namespace constrained_window
diff --git a/components/constrained_window/show_modal_dialog_views.cc b/components/constrained_window/show_modal_dialog_views.cc index 5f7e2c8..e1f3819 100644 --- a/components/constrained_window/show_modal_dialog_views.cc +++ b/components/constrained_window/show_modal_dialog_views.cc
@@ -10,17 +10,12 @@ #include "components/web_modal/single_web_contents_dialog_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "content/public/browser/web_contents.h" -#include "ui/base/ui_base_features.h" #include "ui/gfx/native_widget_types.h" namespace constrained_window { void ShowModalDialog(gfx::NativeWindow dialog, content::WebContents* web_contents) { -#if defined(OS_MACOSX) - if (features::IsViewsBrowserCocoa()) - return ShowModalDialogCocoa(dialog, web_contents); -#endif web_modal::WebContentsModalDialogManager* manager = web_modal::WebContentsModalDialogManager::FromWebContents(web_contents); DCHECK(manager);
diff --git a/components/constrained_window/test_create_native_web_modal_manager_cocoa.cc b/components/constrained_window/test_create_native_web_modal_manager_cocoa.cc deleted file mode 100644 index 931dfe45..0000000 --- a/components/constrained_window/test_create_native_web_modal_manager_cocoa.cc +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/web_modal/web_contents_modal_dialog_manager.h" - -namespace web_modal { - -SingleWebContentsDialogManager* -WebContentsModalDialogManager::CreateNativeWebModalManager( - gfx::NativeWindow dialog, - web_modal::SingleWebContentsDialogManagerDelegate* delegate) { - return nullptr; -} - -} // namespace web_modal
diff --git a/components/exo/gaming_seat_unittest.cc b/components/exo/gaming_seat_unittest.cc index 4411b68..922adcb3 100644 --- a/components/exo/gaming_seat_unittest.cc +++ b/components/exo/gaming_seat_unittest.cc
@@ -58,7 +58,7 @@ std::vector<ui::InputDevice> gamepad_devices; for (auto& id : gamepad_device_ids) { gamepad_devices.push_back(ui::InputDevice( - id, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "gamepad")); + id, ui::InputDeviceType::INPUT_DEVICE_USB, "gamepad")); } ui::GamepadProviderOzone::GetInstance()->DispatchGamepadDevicesUpdated( gamepad_devices);
diff --git a/components/exo/keyboard_unittest.cc b/components/exo/keyboard_unittest.cc index 8b216339..13627079 100644 --- a/components/exo/keyboard_unittest.cc +++ b/components/exo/keyboard_unittest.cc
@@ -306,8 +306,8 @@ ui::DeviceDataManager::GetInstance(); ASSERT_TRUE(device_data_manager != nullptr); // Make sure that DeviceDataManager has one external keyboard. - const std::vector<ui::InputDevice> keyboards{ui::InputDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard")}; + const std::vector<ui::InputDevice> keyboards{ + ui::InputDevice(2, ui::InputDeviceType::INPUT_DEVICE_USB, "keyboard")}; device_data_manager->OnKeyboardDevicesUpdated(keyboards); ash::TabletModeController* tablet_mode_controller =
diff --git a/components/heap_profiling/test_driver.cc b/components/heap_profiling/test_driver.cc index a070690..592467a 100644 --- a/components/heap_profiling/test_driver.cc +++ b/components/heap_profiling/test_driver.cc
@@ -901,7 +901,8 @@ if (IsRecordingAllAllocations()) { if (should_validate_dumps) { result = ValidateDump(heaps_v2, kMallocAllocSize * kMallocAllocCount, - kMallocAllocCount, "malloc", kMallocTypeTag, + kMallocAllocCount, "malloc", + HasPseudoFrames() ? kMallocTypeTag : nullptr, HasPseudoFrames() ? kMallocEvent : "", thread_name); if (!result) { LOG(ERROR) << "Failed to validate malloc fixed allocations";
diff --git a/components/services/heap_profiling/public/cpp/allocator_shim.cc b/components/services/heap_profiling/public/cpp/allocator_shim.cc index 5841f51..ef76601 100644 --- a/components/services/heap_profiling/public/cpp/allocator_shim.cc +++ b/components/services/heap_profiling/public/cpp/allocator_shim.cc
@@ -735,8 +735,7 @@ break; case mojom::StackMode::NATIVE_WITH_THREAD_NAMES: case mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES: - // This would track task contexts only. - AllocationContextTracker::SetCaptureMode(CaptureMode::NATIVE_STACK); + AllocationContextTracker::SetCaptureMode(CaptureMode::DISABLED); break; } @@ -792,8 +791,7 @@ *context = allocation_context.type_name; } -void SerializeFramesFromBacktrace(FrameSerializer* serializer, - const char** context) { +void SerializeFramesFromBacktrace(FrameSerializer* serializer) { // Skip 3 top frames related to the profiler itself, e.g.: // base::debug::StackTrace::StackTrace // heap_profiling::RecordAndSendAlloc @@ -826,13 +824,6 @@ const char* thread_name = GetOrSetThreadName(); serializer->AddCString(thread_name); } - - if (!*context) { - const auto* tracker = - AllocationContextTracker::GetInstanceForCurrentThread(); - if (tracker) - *context = tracker->TaskContext(); - } } void AllocatorShimLogAlloc(AllocatorType type, @@ -904,7 +895,7 @@ capture_mode == CaptureMode::MIXED_STACK) { SerializeFramesFromAllocationContext(&serializer, &context); } else { - SerializeFramesFromBacktrace(&serializer, &context); + SerializeFramesFromBacktrace(&serializer); } size_t context_len = context ? strnlen(context, kMaxContextLen) : 0;
diff --git a/components/web_modal/web_contents_modal_dialog_manager.cc b/components/web_modal/web_contents_modal_dialog_manager.cc index 3ce19d1..4669249e 100644 --- a/components/web_modal/web_contents_modal_dialog_manager.cc +++ b/components/web_modal/web_contents_modal_dialog_manager.cc
@@ -106,6 +106,10 @@ // then set the block state. Advantage: could restrict some of the // WCMDM delegate methods, then, and pass them behind the scenes. void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked) { + if (blocked == web_contents_is_blocked_) + return; + web_contents_is_blocked_ = blocked; + WebContents* contents = web_contents(); if (!contents) { // The WebContents has already disconnected. @@ -124,6 +128,7 @@ while (!child_dialogs_.empty()) { child_dialogs_.front().manager->Close(); } + BlockWebContentsInteraction(false); closing_all_dialogs_ = false; }
diff --git a/components/web_modal/web_contents_modal_dialog_manager.h b/components/web_modal/web_contents_modal_dialog_manager.h index 5a646b8..844003c 100644 --- a/components/web_modal/web_contents_modal_dialog_manager.h +++ b/components/web_modal/web_contents_modal_dialog_manager.h
@@ -30,14 +30,6 @@ WebContentsModalDialogManagerDelegate* delegate() const { return delegate_; } void SetDelegate(WebContentsModalDialogManagerDelegate* d); -#if defined(OS_MACOSX) - // Note: This method is not defined inside components/web_modal/ as its - // definition (needed for Cocoa builds) depends on chrome/browser/ui/cocoa/. - static SingleWebContentsDialogManager* CreateNativeWebModalManager( - gfx::NativeWindow dialog, - SingleWebContentsDialogManagerDelegate* native_delegate); -#endif - // Allow clients to supply their own native dialog manager. Suitable for // bubble clients. void ShowDialogWithManager( @@ -117,6 +109,9 @@ // True while closing the dialogs on WebContents close. bool closing_all_dialogs_; + // True if the WebContents is blocked. + bool web_contents_is_blocked_ = false; + DISALLOW_COPY_AND_ASSIGN(WebContentsModalDialogManager); };
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc index 3a5dd45c..b5d3af0 100644 --- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -290,6 +290,12 @@ // http:/crbug.com/889013 IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest, + DISABLED_AccessibilityEventsCaretHide) { + RunEventTest(FILE_PATH_LITERAL("caret-hide.html")); +} + +// http:/crbug.com/889013 +IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest, DISABLED_AccessibilityEventsCaretMove) { RunEventTest(FILE_PATH_LITERAL("caret-move.html")); }
diff --git a/content/browser/fileapi/README.md b/content/browser/fileapi/README.md new file mode 100644 index 0000000..4707361 --- /dev/null +++ b/content/browser/fileapi/README.md
@@ -0,0 +1,23 @@ +# FileSystem API + +This directory contains part of the browser side implementation of various +filesystem related APIs. + +## Related directories + +[`//storage/browser/fileapi/`](../../../storage/browser/fileapi) contains the +rest of the browser side implementation, while +[`blink/renderer/modules/filesystem`](../../../third_party/blink/renderer/modules/filesystem) +contains the renderer side implementation and +[`blink/public/mojom/filesystem`](../../../third_party/blink/public/mojom/filesystem) +contains the mojom interfaces for these APIs. + +## In this directory + +[`FileSystemManagerImpl`](file_system_manager_impl.h) is the main entry point +for calls from the renderer, it mostly redirects incoming mojom calls to a +`storage::FileSystemContext` instance. + +[`FileSystemChooser`](file_system_chooser.h) uses ui::SelectFileDialog to show +a file or directory picker, and is responsible for granting a process the right +permissions for actually accessing the files that were selected.
diff --git a/content/browser/fileapi/file_system_chooser.cc b/content/browser/fileapi/file_system_chooser.cc index 0c8ae67..9b62430 100644 --- a/content/browser/fileapi/file_system_chooser.cc +++ b/content/browser/fileapi/file_system_chooser.cc
@@ -5,6 +5,8 @@ #include "content/browser/fileapi/file_system_chooser.h" #include "base/bind.h" +#include "base/files/file_util.h" +#include "base/task/post_task.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/content_browser_client.h" @@ -19,20 +21,37 @@ void FileSystemChooser::CreateAndShow( int render_process_id, int frame_id, + blink::mojom::ChooseFileSystemEntryType type, ResultCallback callback, scoped_refptr<base::TaskRunner> callback_runner) { DCHECK_CURRENTLY_ON(BrowserThread::UI); RenderFrameHost* rfh = RenderFrameHost::FromID(render_process_id, frame_id); WebContents* web_contents = WebContents::FromRenderFrameHost(rfh); - auto* listener = new FileSystemChooser(render_process_id, std::move(callback), - std::move(callback_runner)); + auto* listener = new FileSystemChooser( + render_process_id, type, std::move(callback), std::move(callback_runner)); listener->dialog_ = ui::SelectFileDialog::Create( listener, GetContentClient()->browser()->CreateSelectFilePolicy(web_contents)); // TODO(https://crbug.com/878581): Better/more specific options to pass to // SelectFile. + ui::SelectFileDialog::Type dialog_type = ui::SelectFileDialog::SELECT_NONE; + switch (type) { + case blink::mojom::ChooseFileSystemEntryType::kOpenFile: + dialog_type = ui::SelectFileDialog::SELECT_OPEN_FILE; + break; + case blink::mojom::ChooseFileSystemEntryType::kOpenMultipleFiles: + dialog_type = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE; + break; + case blink::mojom::ChooseFileSystemEntryType::kSaveFile: + dialog_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; + break; + case blink::mojom::ChooseFileSystemEntryType::kOpenDirectory: + dialog_type = ui::SelectFileDialog::SELECT_FOLDER; + break; + } + DCHECK_NE(dialog_type, ui::SelectFileDialog::SELECT_NONE); listener->dialog_->SelectFile( - ui::SelectFileDialog::SELECT_OPEN_FILE, /*title=*/base::string16(), + dialog_type, /*title=*/base::string16(), /*default_path=*/base::FilePath(), /*file_types=*/nullptr, /*file_type_index=*/0, /*default_extension=*/base::FilePath::StringType(), @@ -42,11 +61,13 @@ FileSystemChooser::FileSystemChooser( int render_process_id, + blink::mojom::ChooseFileSystemEntryType type, ResultCallback callback, scoped_refptr<base::TaskRunner> callback_runner) : render_process_id_(render_process_id), callback_(std::move(callback)), - callback_runner_(std::move(callback_runner)) {} + callback_runner_(std::move(callback_runner)), + type_(type) {} FileSystemChooser::~FileSystemChooser() { if (dialog_) @@ -73,21 +94,72 @@ for (const auto& path : files) { auto entry = blink::mojom::FileSystemEntry::New(); entry->file_system_id = isolated_context->RegisterFileSystemForPath( - storage::kFileSystemTypeNativeForPlatformApp, std::string(), path, + storage::kFileSystemTypeNativeLocal, std::string(), path, &entry->base_name); - // TODO(https://crbug.com/878585): Determine if we always want to grant - // write permission. security_policy->GrantReadFileSystem(render_process_id_, entry->file_system_id); - security_policy->GrantWriteFileSystem(render_process_id_, - entry->file_system_id); - security_policy->GrantDeleteFromFileSystem(render_process_id_, - entry->file_system_id); + // TODO(https://crbug.com/878585): Don't grant write/modify permissions + // unless a website already has the appropriate permissions. + if (type_ == blink::mojom::ChooseFileSystemEntryType::kOpenDirectory) { + // Only grant Create permissions if we're opening a directory. And + // just granting Create permissions on top of Write and Delete does not + // actually grant the same permissions as calling this method. + security_policy->GrantCreateReadWriteFileSystem(render_process_id_, + entry->file_system_id); + } else { + security_policy->GrantWriteFileSystem(render_process_id_, + entry->file_system_id); + security_policy->GrantDeleteFromFileSystem(render_process_id_, + entry->file_system_id); + } result.push_back(std::move(entry)); } + if (type_ == blink::mojom::ChooseFileSystemEntryType::kSaveFile) { + // Create files if they don't yet exist. + // TODO(mek): If we change FileSystemFileHandle to be able to represent a + // file that doesn't exist on disk, we should be able to get rid of this + // step and make the whole API slightly more robust. + base::PostTaskWithTraits( + FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()}, + base::BindOnce( + [](const std::vector<base::FilePath>& files, + std::vector<blink::mojom::FileSystemEntryPtr> result, + scoped_refptr<base::TaskRunner> callback_runner, + ResultCallback callback) { + for (const auto& path : files) { + // Checking if a path exists, and then creating it if it doesn't + // is of course racy, but external applications could just as + // well be deleting the entire directory, or similar problematic + // cases, so no matter what we do there are always going to be + // race conditions and websites will just have to deal with any + // method being able to fail in unexpected ways. + if (base::PathExists(path)) + continue; + int creation_flags = + base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ; + base::File file(path, creation_flags); + + if (!file.IsValid()) { + callback_runner->PostTask( + FROM_HERE, + base::BindOnce( + std::move(callback), base::File::FILE_ERROR_FAILED, + std::vector<blink::mojom::FileSystemEntryPtr>())); + return; + } + } + callback_runner->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), base::File::FILE_OK, + std::move(result))); + }, + files, std::move(result), callback_runner_, std::move(callback_))); + delete this; + return; + } callback_runner_->PostTask( FROM_HERE, base::BindOnce(std::move(callback_), base::File::FILE_OK, std::move(result)));
diff --git a/content/browser/fileapi/file_system_chooser.h b/content/browser/fileapi/file_system_chooser.h index 2283a6725..d2f24d8 100644 --- a/content/browser/fileapi/file_system_chooser.h +++ b/content/browser/fileapi/file_system_chooser.h
@@ -25,10 +25,12 @@ static void CreateAndShow(int render_process_id, int frame_id, + blink::mojom::ChooseFileSystemEntryType type, ResultCallback callback, scoped_refptr<base::TaskRunner> callback_runner); FileSystemChooser(int render_process_id, + blink::mojom::ChooseFileSystemEntryType type, ResultCallback callback, scoped_refptr<base::TaskRunner> callback_runner); @@ -46,6 +48,7 @@ int render_process_id_; ResultCallback callback_; scoped_refptr<base::TaskRunner> callback_runner_; + blink::mojom::ChooseFileSystemEntryType type_; scoped_refptr<ui::SelectFileDialog> dialog_; };
diff --git a/content/browser/fileapi/file_system_chooser_browsertest.cc b/content/browser/fileapi/file_system_chooser_browsertest.cc new file mode 100644 index 0000000..97cfcd3 --- /dev/null +++ b/content/browser/fileapi/file_system_chooser_browsertest.cc
@@ -0,0 +1,267 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/test/scoped_feature_list.h" +#include "base/threading/thread_restrictions.h" +#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 "third_party/blink/public/common/features.h" +#include "ui/shell_dialogs/select_file_dialog.h" +#include "ui/shell_dialogs/select_file_dialog_factory.h" +#include "ui/shell_dialogs/select_file_policy.h" + +namespace content { + +namespace { + +struct SelectFileDialogParams { + ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_NONE; +}; + +// A fake ui::SelectFileDialog, which will cancel the file selection instead of +// selecting a file. +class CancellingSelectFileDialog : public ui::SelectFileDialog { + public: + CancellingSelectFileDialog(Listener* listener, + std::unique_ptr<ui::SelectFilePolicy> policy) + : ui::SelectFileDialog(listener, std::move(policy)) {} + + protected: + void SelectFileImpl(Type type, + const base::string16& title, + const base::FilePath& default_path, + const FileTypeInfo* file_types, + int file_type_index, + const base::FilePath::StringType& default_extension, + gfx::NativeWindow owning_window, + void* params) override { + listener_->FileSelectionCanceled(params); + } + + bool IsRunning(gfx::NativeWindow owning_window) const override { + return false; + } + void ListenerDestroyed() override {} + bool HasMultipleFileTypeChoicesImpl() override { return false; } + + private: + ~CancellingSelectFileDialog() override = default; +}; + +class CancellingSelectFileDialogFactory : public ui::SelectFileDialogFactory { + public: + CancellingSelectFileDialogFactory() {} + + ui::SelectFileDialog* Create( + ui::SelectFileDialog::Listener* listener, + std::unique_ptr<ui::SelectFilePolicy> policy) override { + return new CancellingSelectFileDialog(listener, std::move(policy)); + } +}; + +// A fake ui::SelectFileDialog, which will select one or more pre-determined +// files. +class FakeSelectFileDialog : public ui::SelectFileDialog { + public: + FakeSelectFileDialog(std::vector<base::FilePath> result, + SelectFileDialogParams* out_params, + Listener* listener, + std::unique_ptr<ui::SelectFilePolicy> policy) + : ui::SelectFileDialog(listener, std::move(policy)), + result_(std::move(result)), + out_params_(out_params) {} + + protected: + void SelectFileImpl(Type type, + const base::string16& title, + const base::FilePath& default_path, + const FileTypeInfo* file_types, + int file_type_index, + const base::FilePath::StringType& default_extension, + gfx::NativeWindow owning_window, + void* params) override { + if (out_params_) { + out_params_->type = type; + } + if (result_.size() == 1) + listener_->FileSelected(result_[0], 0, params); + else + listener_->MultiFilesSelected(result_, params); + } + + bool IsRunning(gfx::NativeWindow owning_window) const override { + return false; + } + void ListenerDestroyed() override {} + bool HasMultipleFileTypeChoicesImpl() override { return false; } + + private: + ~FakeSelectFileDialog() override = default; + std::vector<base::FilePath> result_; + SelectFileDialogParams* out_params_; +}; + +class FakeSelectFileDialogFactory : public ui::SelectFileDialogFactory { + public: + explicit FakeSelectFileDialogFactory(std::vector<base::FilePath> result, + SelectFileDialogParams* out_params) + : result_(std::move(result)), out_params_(out_params) {} + + ui::SelectFileDialog* Create( + ui::SelectFileDialog::Listener* listener, + std::unique_ptr<ui::SelectFilePolicy> policy) override { + return new FakeSelectFileDialog(result_, out_params_, listener, + std::move(policy)); + } + + private: + std::vector<base::FilePath> result_; + SelectFileDialogParams* out_params_; +}; + +} // namespace + +// This browser test implements end-to-end tests for the chooseFileSystemEntry +// API. +class FileSystemChooserBrowserTest : public ContentBrowserTest { + public: + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + scoped_feature_list_.InitAndEnableFeature( + blink::features::kWritableFilesAPI); + ContentBrowserTest::SetUp(); + } + + void TearDown() override { + ContentBrowserTest::TearDown(); + ASSERT_TRUE(temp_dir_.Delete()); + ui::SelectFileDialog::SetFactory(nullptr); + } + + base::FilePath CreateTestFile(const std::string& contents) { + base::ScopedAllowBlockingForTesting allow_blocking; + base::FilePath result; + EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &result)); + EXPECT_EQ(int{contents.size()}, + base::WriteFile(result, contents.data(), contents.size())); + return result; + } + + base::FilePath CreateTestDir() { + base::ScopedAllowBlockingForTesting allow_blocking; + base::FilePath result; + EXPECT_TRUE(base::CreateTemporaryDirInDir( + temp_dir_.GetPath(), FILE_PATH_LITERAL("test"), &result)); + return result; + } + + protected: + const std::string kBlankHtml = "<!DOCTYPE html><html><body>"; + const GURL kTestUrl = GURL("https://foobar.com/"); + + private: + base::test::ScopedFeatureList scoped_feature_list_; + base::ScopedTempDir temp_dir_; +}; + +IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, CancelDialog) { + ui::SelectFileDialog::SetFactory(new CancellingSelectFileDialogFactory); + LoadDataWithBaseURL(shell(), kTestUrl, kBlankHtml, kTestUrl); + auto result = EvalJs(shell(), "self.chooseFileSystemEntries()"); + EXPECT_TRUE(result.error.find("AbortError") != std::string::npos) + << result.error; +} + +IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenFile) { + const std::string file_contents = "hello world!"; + const base::FilePath test_file = CreateTestFile(file_contents); + SelectFileDialogParams dialog_params; + ui::SelectFileDialog::SetFactory( + new FakeSelectFileDialogFactory({test_file}, &dialog_params)); + LoadDataWithBaseURL(shell(), kTestUrl, kBlankHtml, kTestUrl); + EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(), + EvalJs(shell(), + "(async () => {" + " let e = await self.chooseFileSystemEntries();" + " self.selected_entry = e;" + " return e.name; })()")); + EXPECT_EQ(ui::SelectFileDialog::SELECT_OPEN_FILE, dialog_params.type); + EXPECT_EQ( + file_contents, + EvalJs(shell(), + "(async () => { const file = await self.selected_entry.getFile(); " + "return await new Response(file).text(); })()")); +} + +IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, SaveFile) { + const std::string file_contents = "file contents to write"; + const base::FilePath test_file = CreateTestFile(""); + { + // Delete file, since SaveFile should be able to deal with non-existing + // files. + base::ScopedAllowBlockingForTesting allow_blocking; + ASSERT_TRUE(base::DeleteFile(test_file, false)); + } + SelectFileDialogParams dialog_params; + ui::SelectFileDialog::SetFactory( + new FakeSelectFileDialogFactory({test_file}, &dialog_params)); + LoadDataWithBaseURL(shell(), kTestUrl, kBlankHtml, kTestUrl); + EXPECT_EQ(test_file.BaseName().AsUTF8Unsafe(), + EvalJs(shell(), + "(async () => {" + " let e = await self.chooseFileSystemEntries(" + " {type: 'saveFile'});" + " self.entry = e;" + " return e.name; })()")); + EXPECT_EQ(ui::SelectFileDialog::SELECT_SAVEAS_FILE, dialog_params.type); + EXPECT_EQ(int{file_contents.size()}, + EvalJs(shell(), + JsReplace("(async () => {" + " const w = await self.entry.createWriter();" + " await w.write(0, new Blob([$1]));" + " return (await self.entry.getFile()).size; })()", + file_contents))); + { + base::ScopedAllowBlockingForTesting allow_blocking; + std::string read_contents; + EXPECT_TRUE(base::ReadFileToString(test_file, &read_contents)); + EXPECT_EQ(file_contents, read_contents); + } +} + +IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenMultipleFiles) { + const base::FilePath test_file1 = CreateTestFile("file1"); + const base::FilePath test_file2 = CreateTestFile("file2"); + SelectFileDialogParams dialog_params; + ui::SelectFileDialog::SetFactory(new FakeSelectFileDialogFactory( + {test_file1, test_file2}, &dialog_params)); + LoadDataWithBaseURL(shell(), kTestUrl, kBlankHtml, kTestUrl); + EXPECT_EQ(ListValueOf(test_file1.BaseName().AsUTF8Unsafe(), + test_file2.BaseName().AsUTF8Unsafe()), + EvalJs(shell(), + "(async () => {" + " let e = await self.chooseFileSystemEntries(" + " {multiple: true});" + " return e.map(x => x.name); })()")); + EXPECT_EQ(ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE, dialog_params.type); +} + +IN_PROC_BROWSER_TEST_F(FileSystemChooserBrowserTest, OpenDirectory) { + base::FilePath test_dir = CreateTestDir(); + SelectFileDialogParams dialog_params; + ui::SelectFileDialog::SetFactory( + new FakeSelectFileDialogFactory({test_dir}, &dialog_params)); + LoadDataWithBaseURL(shell(), kTestUrl, kBlankHtml, kTestUrl); + EXPECT_EQ(test_dir.BaseName().AsUTF8Unsafe(), + EvalJs(shell(), + "(async () => {" + " let e = await self.chooseFileSystemEntries(" + " {type: 'openDirectory'});" + " self.selected_entry = e;" + " return e.name; })()")); + EXPECT_EQ(ui::SelectFileDialog::SELECT_FOLDER, dialog_params.type); +} + +} // namespace content \ No newline at end of file
diff --git a/content/browser/fileapi/file_system_manager_impl.cc b/content/browser/fileapi/file_system_manager_impl.cc index 29f1d2d..91d5202 100644 --- a/content/browser/fileapi/file_system_manager_impl.cc +++ b/content/browser/fileapi/file_system_manager_impl.cc
@@ -592,7 +592,9 @@ std::move(callback).Run(base::File::FILE_OK, std::move(writer)); } -void FileSystemManagerImpl::ChooseEntry(ChooseEntryCallback callback) { +void FileSystemManagerImpl::ChooseEntry( + blink::mojom::ChooseFileSystemEntryType type, + ChooseEntryCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (!base::FeatureList::IsEnabled(blink::features::kWritableFilesAPI)) { bindings_.ReportBadMessage("FSMI_WRITABLE_FILES_DISABLED"); @@ -602,7 +604,7 @@ base::PostTaskWithTraits( FROM_HERE, {BrowserThread::UI}, base::BindOnce( - &FileSystemChooser::CreateAndShow, process_id_, frame_id_, + &FileSystemChooser::CreateAndShow, process_id_, frame_id_, type, std::move(callback), base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}))); }
diff --git a/content/browser/fileapi/file_system_manager_impl.h b/content/browser/fileapi/file_system_manager_impl.h index e92c5e46..4fe924e 100644 --- a/content/browser/fileapi/file_system_manager_impl.h +++ b/content/browser/fileapi/file_system_manager_impl.h
@@ -125,7 +125,8 @@ GetPlatformPathCallback callback) override; void CreateWriter(const GURL& file_path, CreateWriterCallback callback) override; - void ChooseEntry(ChooseEntryCallback callback) override; + void ChooseEntry(blink::mojom::ChooseFileSystemEntryType type, + ChooseEntryCallback callback) override; private: class FileSystemCancellableOperationImpl;
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 020f0d12..34a7d12 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -130,6 +130,7 @@ void DidPresentCompositorFrame( uint32_t frame_token, const gfx::PresentationFeedback& feedback) override {} + void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override {} // LayerTreeHostSingleThreadClient implementation. void DidSubmitCompositorFrame() override;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 286904c..1cad17bc 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -392,8 +392,6 @@ bool Animate(base::TimeTicks frame_time); void RequestDisallowInterceptTouchEvent(); - bool SyncCompositorOnMessageReceived(const IPC::Message& message); - void ComputeEventLatencyOSTouchHistograms(const ui::MotionEvent& event); void CreateOverscrollControllerIfPossible();
diff --git a/content/browser/scheduler/browser_task_executor.cc b/content/browser/scheduler/browser_task_executor.cc index 0b7d514..e966424 100644 --- a/content/browser/scheduler/browser_task_executor.cc +++ b/content/browser/scheduler/browser_task_executor.cc
@@ -17,8 +17,8 @@ // BrowserThread. BrowserThreadTaskRunners are vended by // base::Create*TaskRunnerWithTraits({BrowserThread::UI/IO}). // -// TODO(gab): Consider replacing this with direct calls to task runners -// |BrowserThreadImpl::GetTaskRunnerForThread()| -- only works if none are +// TODO(gab): Consider replacing this with direct calls to task runners obtained +// via |BrowserThreadImpl::GetTaskRunnerForThread()| -- only works if none are // requested before starting the threads. class BrowserThreadTaskRunner : public base::SingleThreadTaskRunner { public:
diff --git a/content/renderer/gpu/layer_tree_view.cc b/content/renderer/gpu/layer_tree_view.cc index b471c15..1690631 100644 --- a/content/renderer/gpu/layer_tree_view.cc +++ b/content/renderer/gpu/layer_tree_view.cc
@@ -673,6 +673,10 @@ } } +void LayerTreeView::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) { + delegate_->RecordEndOfFrameMetrics(frame_begin_time); +} + void LayerTreeView::RequestScheduleAnimation() { delegate_->RequestScheduleAnimation(); }
diff --git a/content/renderer/gpu/layer_tree_view.h b/content/renderer/gpu/layer_tree_view.h index 644d239..820d1a2 100644 --- a/content/renderer/gpu/layer_tree_view.h +++ b/content/renderer/gpu/layer_tree_view.h
@@ -197,6 +197,7 @@ void DidPresentCompositorFrame( uint32_t frame_token, const gfx::PresentationFeedback& feedback) override; + void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override; // cc::LayerTreeHostSingleThreadClient implementation. void RequestScheduleAnimation() override;
diff --git a/content/renderer/gpu/layer_tree_view_delegate.h b/content/renderer/gpu/layer_tree_view_delegate.h index 0f13c9d..d28c056 100644 --- a/content/renderer/gpu/layer_tree_view_delegate.h +++ b/content/renderer/gpu/layer_tree_view_delegate.h
@@ -69,6 +69,12 @@ // will be displayed. virtual void DidReceiveCompositorFrameAck() = 0; + // Requests that a UMA and UKM metric be recorded for the total frame time. + // Call this as soon as the total frame time becomes known for a given frame. + // For example, ProxyMain::BeginMainFrame calls it immediately before aborting + // or committing a frame (at the same time Tracing measurements are taken). + virtual void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) = 0; + // Indicates whether the LayerTreeView is about to close. virtual bool IsClosing() const = 0;
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 77f9bd6..21f16fa 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -1099,6 +1099,13 @@ } } +void RenderWidget::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) { + if (!GetWebWidget()) + return; + + GetWebWidget()->RecordEndOfFrameMetrics(frame_begin_time); +} + void RenderWidget::WillBeginCompositorFrame() { TRACE_EVENT0("gpu", "RenderWidget::willBeginCompositorFrame");
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index 5a3c9a8..7bb9097 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h
@@ -272,6 +272,7 @@ void DidCommitCompositorFrame() override; void DidCompletePageScaleAnimation() override; void DidReceiveCompositorFrameAck() override; + void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override; bool IsClosing() const override; void RequestScheduleAnimation() override; void UpdateVisualState() override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index f99c8790..c003c79 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -757,6 +757,7 @@ # These tests have incorrect threading (https://crbug.com/860547). #"../browser/fileapi/file_system_url_loader_factory_browsertest.cc", + "../browser/fileapi/file_system_chooser_browsertest.cc", "../browser/fileapi/fileapi_browsertest.cc", "../browser/find_request_manager_browsertest.cc", "../browser/font_unique_name_lookup/font_unique_name_browsertest.cc",
diff --git a/content/test/data/accessibility/event/caret-hide-expected-win.txt b/content/test/data/accessibility/event/caret-hide-expected-win.txt new file mode 100644 index 0000000..632f1d8b --- /dev/null +++ b/content/test/data/accessibility/event/caret-hide-expected-win.txt
@@ -0,0 +1,7 @@ +EVENT_OBJECT_FOCUS on <input#btn> role=ROLE_SYSTEM_PUSHBUTTON name="Submit" FOCUSED,FOCUSABLE +EVENT_OBJECT_FOCUS on <input#in1> role=ROLE_SYSTEM_TEXT value="abcde" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE +EVENT_OBJECT_HIDE role=ROLE_SYSTEM_CARET INVISIBLE window_class=Chrome_WidgetWin_0 +EVENT_OBJECT_LOCATIONCHANGE role=ROLE_SYSTEM_CARET window_class=Chrome_WidgetWin_0 +EVENT_OBJECT_SHOW role=ROLE_SYSTEM_CARET window_class=Chrome_WidgetWin_0 +EVENT_OBJECT_VALUECHANGE on <input#in1> role=ROLE_SYSTEM_TEXT value="end" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE +IA2_EVENT_TEXT_CARET_MOVED on <input#in1> role=ROLE_SYSTEM_TEXT value="abcde" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE \ No newline at end of file
diff --git a/content/test/data/accessibility/event/caret-hide.html b/content/test/data/accessibility/event/caret-hide.html new file mode 100644 index 0000000..0845f54b --- /dev/null +++ b/content/test/data/accessibility/event/caret-hide.html
@@ -0,0 +1,25 @@ +<!-- +@RUN-UNTIL-EVENT:EVENT_OBJECT_VALUECHANGE +@WIN-DENY:IA2_EVENT_TEXT_INSERTED* +@WIN-DENY:IA2_EVENT_TEXT_REMOVED* +--> +<!DOCTYPE html> +<html> +<body> +<input id="in1" type="text" value="abcde"> +<input id="btn" type="submit"> +<script> + function go() { + const inp = document.getElementById('in1'); + inp.focus(); + inp.setSelectionRange(0, 0); + setTimeout(() => { + document.getElementById('btn').focus(); + setTimeout(() => { + inp.value = 'end'; // Trigger test end. + }, 50); + }, 50); +} +</script> +</body> +</html> \ No newline at end of file
diff --git a/content/test/stub_layer_tree_view_delegate.h b/content/test/stub_layer_tree_view_delegate.h index 65dc3b5..83bba53 100644 --- a/content/test/stub_layer_tree_view_delegate.h +++ b/content/test/stub_layer_tree_view_delegate.h
@@ -20,6 +20,7 @@ void RecordWheelAndTouchScrollingCount(bool has_scrolled_by_wheel, bool has_scrolled_by_touch) override {} void BeginMainFrame(base::TimeTicks frame_time) override {} + void RecordEndOfFrameMetrics(base::TimeTicks) override {} void RequestNewLayerTreeFrameSink( LayerTreeFrameSinkCallback callback) override; void DidCommitAndDrawCompositorFrame() override {}
diff --git a/device/gamepad/raw_input_gamepad_device_win.cc b/device/gamepad/raw_input_gamepad_device_win.cc index d434c8d7..c124bfe 100644 --- a/device/gamepad/raw_input_gamepad_device_win.cc +++ b/device/gamepad/raw_input_gamepad_device_win.cc
@@ -31,9 +31,24 @@ const uint32_t kHomeUsageNumber = 0x0223; const uint32_t kBackUsageNumber = 0x0224; -// Blacklisted vendor IDs. +// Vendor IDs. const uint32_t kVendorOculus = 0x2833; const uint32_t kVendorBlue = 0xb58e; +const uint32_t kVendorMicrosoft = 0x045e; + +// Product IDs. +const uint32_t kProductSurfacePro2017Keyboard = 0x0922; + +struct VendorProductPair { + const uint16_t vendor; + const uint16_t product; +} kFilteredDevices[] = { + // The Surface Pro 2017's detachable keyboard is a composite device with + // several HID sub-devices. Filter out the keyboard's device ID to avoid + // treating these sub-devices as gamepads. + {kVendorMicrosoft, kProductSurfacePro2017Keyboard}, +}; +const size_t kFilteredDevicesLen = base::size(kFilteredDevices); // The fetcher will collect all HID usages from the Button usage page and any // additional usages listed below. @@ -216,10 +231,26 @@ if (vendor_id_ == kVendorOculus || vendor_id_ == kVendorBlue) return false; + for (size_t i = 0; i < kFilteredDevicesLen; ++i) { + const auto& filter = kFilteredDevices[i]; + if (vendor_id_ == filter.vendor && product_id_ == filter.product) + return false; + } + // Fetch the device's |name_| (RIDI_DEVICENAME). if (!QueryDeviceName()) return false; + // From the name we can guess at the bus type. PCI HID devices have "VEN" and + // "DEV" instead of "VID" and "PID". PCI HID devices are typically not + // gamepads and are ignored. + // Example PCI device name: \\?\HID#VEN_1234&DEV_ABCD + // TODO(crbug/881539): Potentially allow PCI HID devices to be enumerated, but + // prefer known gamepads when there is contention. + std::wstring pci_prefix = L"\\\\?\\HID#VEN_"; + if (!name_.compare(0, pci_prefix.size(), pci_prefix)) + return false; + // Fetch the human-friendly |product_string_|, if available. if (!QueryProductString()) product_string_ = L"Unknown Gamepad";
diff --git a/device/usb/usb_device_handle_usbfs.cc b/device/usb/usb_device_handle_usbfs.cc index afbd070..1ebe96b 100644 --- a/device/usb/usb_device_handle_usbfs.cc +++ b/device/usb/usb_device_handle_usbfs.cc
@@ -19,7 +19,7 @@ #include "base/posix/eintr_wrapper.h" #include "base/sequence_checker.h" #include "base/stl_util.h" -#include "base/threading/thread_restrictions.h" +#include "base/threading/scoped_blocking_call.h" #include "base/threading/thread_task_runner_handle.h" #include "components/device_event_log/device_event_log.h" #include "device/usb/usb_device_linux.h" @@ -211,7 +211,6 @@ } void UsbDeviceHandleUsbfs::FileThreadHelper::Start() { - base::AssertBlockingAllowed(); sequence_checker_.DetachFromSequence(); DCHECK(sequence_checker_.CalledOnValidSequence()); @@ -234,6 +233,7 @@ ResultCallback callback) { DCHECK(sequence_checker_.CalledOnValidSequence()); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); int rc = HANDLE_EINTR( ioctl(fd_.get(), USBDEVFS_SETCONFIGURATION, &configuration_value)); if (rc) @@ -249,6 +249,7 @@ ResultCallback callback) { DCHECK(sequence_checker_.CalledOnValidSequence()); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); int rc = HANDLE_EINTR( ioctl(fd_.get(), USBDEVFS_RELEASEINTERFACE, &interface_number)); if (rc) { @@ -272,6 +273,8 @@ usbdevfs_setinterface cmd = {0}; cmd.interface = interface_number; cmd.altsetting = alternate_setting; + + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_SETINTERFACE, &cmd)); if (rc) { USB_PLOG(DEBUG) << "Failed to set interface " << interface_number @@ -285,6 +288,7 @@ ResultCallback callback) { DCHECK(sequence_checker_.CalledOnValidSequence()); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); // TODO(reillyg): libusb releases interfaces before and then reclaims // interfaces after a reset. We should probably do this too or document that // callers have to call ClaimInterface as well. @@ -301,6 +305,7 @@ DCHECK(sequence_checker_.CalledOnValidSequence()); int tmp_endpoint = endpoint_address; + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_CLEAR_HALT, &tmp_endpoint)); if (rc) { USB_PLOG(DEBUG) << "Failed to clear the stall condition on endpoint " @@ -313,6 +318,7 @@ void UsbDeviceHandleUsbfs::FileThreadHelper::DiscardUrb(Transfer* transfer) { DCHECK(sequence_checker_.CalledOnValidSequence()); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_DISCARDURB, &transfer->urb)); task_runner_->PostTask(FROM_HERE, @@ -327,6 +333,8 @@ std::vector<usbdevfs_urb*> urbs; urbs.reserve(MAX_URBS_PER_EVENT); for (size_t i = 0; i < MAX_URBS_PER_EVENT; ++i) { + base::ScopedBlockingCall scoped_blocking_call( + base::BlockingType::MAY_BLOCK); usbdevfs_urb* urb; int rc = HANDLE_EINTR(ioctl(fd_.get(), USBDEVFS_REAPURBNDELAY, &urb)); if (rc) {
diff --git a/device/usb/usb_device_impl.cc b/device/usb/usb_device_impl.cc index ab734eab..e7e3f86 100644 --- a/device/usb/usb_device_impl.cc +++ b/device/usb/usb_device_impl.cc
@@ -15,7 +15,7 @@ #include "base/sequenced_task_runner.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" -#include "base/threading/thread_restrictions.h" +#include "base/threading/scoped_blocking_call.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "components/device_event_log/device_event_log.h" @@ -101,7 +101,7 @@ OpenCallback callback, scoped_refptr<base::TaskRunner> task_runner, scoped_refptr<base::SequencedTaskRunner> blocking_task_runner) { - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); libusb_device_handle* handle = nullptr; const int rv = libusb_open(platform_device(), &handle); if (LIBUSB_SUCCESS == rv) {
diff --git a/device/usb/usb_service_linux.cc b/device/usb/usb_service_linux.cc index a3423257..b876dff7 100644 --- a/device/usb/usb_service_linux.cc +++ b/device/usb/usb_service_linux.cc
@@ -20,8 +20,8 @@ #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/threading/scoped_blocking_call.h" #include "base/threading/sequenced_task_runner_handle.h" -#include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "components/device_event_log/device_event_log.h" #include "device/udev_linux/udev_watcher.h" @@ -102,7 +102,7 @@ // static void UsbServiceLinux::FileThreadHelper::Start() { DCHECK(sequence_checker_.CalledOnValidSequence()); - base::AssertBlockingAllowed(); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); // Initializing udev for device enumeration and monitoring may fail. In that // case this service will continue to exist but no devices will be found. @@ -117,6 +117,8 @@ void UsbServiceLinux::FileThreadHelper::OnDeviceAdded( ScopedUdevDevicePtr device) { DCHECK(sequence_checker_.CalledOnValidSequence()); + + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); const char* subsystem = udev_device_get_subsystem(device.get()); if (!subsystem || strcmp(subsystem, "usb") != 0) return; @@ -176,6 +178,8 @@ void UsbServiceLinux::FileThreadHelper::OnDeviceRemoved( ScopedUdevDevicePtr device) { DCHECK(sequence_checker_.CalledOnValidSequence()); + base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); + const char* device_path = udev_device_get_devnode(device.get()); if (device_path) { task_runner_->PostTask(
diff --git a/docs/README.md b/docs/README.md index 7a36442..ffe325ae 100644 --- a/docs/README.md +++ b/docs/README.md
@@ -48,6 +48,8 @@ (on a Linux host) * [Cast for Android Build Instructions](android_cast_build_instructions.md) - Cast for Android (on a Linux host) +* [Fuchsia Build Instructions](fuchsia_build_instructions.md) - Fuchsia target + (on a Linux host) * [iOS Build Instructions](ios/build_instructions.md) - iOS target (on a MacOS host) * [Chrome OS Build Instructions](chromeos_build_instructions.md) - Chrome OS
diff --git a/docs/fuchsia_build_instructions.md b/docs/fuchsia_build_instructions.md index a137bc0..539d0d0a 100644 --- a/docs/fuchsia_build_instructions.md +++ b/docs/fuchsia_build_instructions.md
@@ -3,7 +3,7 @@ ***Note that the Fuchsia port is in the early stages, and things are likely to frequently be broken. Try #cr-fuchsia on Freenode if something seems awry.*** -There are instructions for other platforms linked from the +There are instructions for other platforms linked from the [get the code](get_the_code.md) page. ## System requirements @@ -49,9 +49,6 @@ $ fetch --nohooks chromium ``` -If you don't want the full repo history, you can save a lot of time by -adding the `--no-history` flag to `fetch`. - Expect the command to take 30 minutes on even a fast connection, and many hours on slower ones. @@ -74,8 +71,14 @@ Note that this should be added as a top-level statement in the `.gclient` file, not an entry inside the `solutions` dict. -You will then need to re-run `gclient runhooks`. This makes sure the Fuchsia SDK -is available in third\_party and keeps it up to date. +You will then need to run: + +```shell +$ gclient runhooks +``` + +This makes sure the Fuchsia SDK is available in third\_party and keeps it up to +date. The remaining instructions assume you have switched to the `src` directory: @@ -83,6 +86,25 @@ $ cd src ``` +### Update your checkout + +To update an existing checkout, you can run + +```shell +$ git rebase-update +$ gclient sync +``` + +The first command updates the primary Chromium source repository and rebases +any of your local branches on top of tip-of-tree (aka the Git branch +`origin/master`). If you don't want to use this script, you can also just use +`git pull` or other common Git commands to update the repo. + +The second command syncs dependencies to the appropriate versions and re-runs +hooks as needed. `gclient sync` updates dependencies to the versions specified +in `DEPS`, so any time that file is modified (pulling, changing branches, etc.) +`gclient sync` should be run. + ## (Mac-only) Download additional required Clang binaries Go to [this page](https://chrome-infra-packages.appspot.com/p/fuchsia/clang/mac-amd64/+/) @@ -136,9 +158,3 @@ script. The run script also symbolizes backtraces. - -A useful alias (for "Build And Run Filtered") is: -```shell -alias barf='ninja -C out/fuchsia net_unittests -j1000 && out/fuchsia/bin/run_net_unittests --test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.net_unittests.filter' -``` -to build and run only the tests that are not excluded/known-failing on the bot.
diff --git a/docs/get_the_code.md b/docs/get_the_code.md index e4bb6e35..a25bce6 100644 --- a/docs/get_the_code.md +++ b/docs/get_the_code.md
@@ -12,6 +12,7 @@ * [Android](android_build_instructions.md) * [Android Cast](android_cast_build_instructions.md) * [Chrome OS](chromeos_build_instructions.md) +* [Fuchsia](fuchsia_build_instructions.md) * [iOS](ios/build_instructions.md) * [Linux](linux_build_instructions.md) * [Linux Cast](linux_cast_build_instructions.md)
diff --git a/extensions/common/extension_builder.cc b/extensions/common/extension_builder.cc index 37b4de0..c948cda1 100644 --- a/extensions/common/extension_builder.cc +++ b/extensions/common/extension_builder.cc
@@ -30,10 +30,10 @@ std::unique_ptr<base::DictionaryValue> GetValue() const { DictionaryBuilder manifest; - manifest.Set("name", name) - .Set("manifest_version", 2) - .Set("version", version.value_or("0.1")) - .Set("description", "some description"); + manifest.Set(manifest_keys::kName, name) + .Set(manifest_keys::kManifestVersion, 2) + .Set(manifest_keys::kVersion, version.value_or("0.1")) + .Set(manifest_keys::kDescription, "some description"); switch (type) { case Type::EXTENSION: @@ -52,7 +52,7 @@ ListBuilder permissions_builder; for (const std::string& permission : permissions) permissions_builder.Append(permission); - manifest.Set("permissions", permissions_builder.Build()); + manifest.Set(manifest_keys::kPermissions, permissions_builder.Build()); } if (action) { @@ -92,11 +92,12 @@ matches.Append(match); scripts_value.Append( DictionaryBuilder() - .Set("js", ListBuilder().Append(script.first).Build()) - .Set("matches", matches.Build()) + .Set(manifest_keys::kJs, + ListBuilder().Append(script.first).Build()) + .Set(manifest_keys::kMatches, matches.Build()) .Build()); } - manifest.Set("content_scripts", scripts_value.Build()); + manifest.Set(manifest_keys::kContentScripts, scripts_value.Build()); } std::unique_ptr<base::DictionaryValue> result = manifest.Build();
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 875ff26..5737483f6 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc
@@ -446,7 +446,7 @@ LoggingNativeHandler* logging = new LoggingNativeHandler(context); logging->Initialize(); context->AddInvalidationObserver( - base::Bind(&NativeHandler::Invalidate, base::Owned(logging))); + base::BindOnce(&NativeHandler::Invalidate, base::Owned(logging))); // Execute the main function with its dependencies passed in as arguments. v8::Local<v8::Value> args[] = {
diff --git a/extensions/renderer/event_bindings.cc b/extensions/renderer/event_bindings.cc index 8d75bc61..588932fb 100644 --- a/extensions/renderer/event_bindings.cc +++ b/extensions/renderer/event_bindings.cc
@@ -83,7 +83,7 @@ // It's safe to use base::Unretained here because |context| will always // outlive us. context->AddInvalidationObserver( - base::Bind(&EventBindings::OnInvalidated, base::Unretained(this))); + base::BindOnce(&EventBindings::OnInvalidated, base::Unretained(this))); } EventBindings::~EventBindings() {}
diff --git a/extensions/renderer/gc_callback.cc b/extensions/renderer/gc_callback.cc index 330e8a7..bc24a8a 100644 --- a/extensions/renderer/gc_callback.cc +++ b/extensions/renderer/gc_callback.cc
@@ -42,8 +42,8 @@ if (!v8_callback.IsEmpty()) v8_callback_.Reset(context->isolate(), v8_callback); object_.SetWeak(this, OnObjectGC, v8::WeakCallbackType::kParameter); - context->AddInvalidationObserver(base::Bind(&GCCallback::OnContextInvalidated, - weak_ptr_factory_.GetWeakPtr())); + context->AddInvalidationObserver(base::BindOnce( + &GCCallback::OnContextInvalidated, weak_ptr_factory_.GetWeakPtr())); } GCCallback::~GCCallback() {}
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc index 69feec88..7ee5528 100644 --- a/extensions/renderer/script_context.cc +++ b/extensions/renderer/script_context.cc
@@ -138,10 +138,10 @@ // Swap |invalidate_observers_| to a local variable to clear it, and to make // sure it's not mutated as we iterate. - std::vector<base::Closure> observers; + std::vector<base::OnceClosure> observers; observers.swap(invalidate_observers_); - for (const base::Closure& observer : observers) { - observer.Run(); + for (base::OnceClosure& observer : observers) { + std::move(observer).Run(); } DCHECK(invalidate_observers_.empty()) << "Invalidation observers cannot be added during invalidation"; @@ -149,9 +149,9 @@ v8_context_.Reset(); } -void ScriptContext::AddInvalidationObserver(const base::Closure& observer) { +void ScriptContext::AddInvalidationObserver(base::OnceClosure observer) { DCHECK(thread_checker_.CalledOnValidThread()); - invalidate_observers_.push_back(observer); + invalidate_observers_.push_back(std::move(observer)); } const std::string& ScriptContext::GetExtensionID() const {
diff --git a/extensions/renderer/script_context.h b/extensions/renderer/script_context.h index 84e2bf6..f2ac3b89 100644 --- a/extensions/renderer/script_context.h +++ b/extensions/renderer/script_context.h
@@ -70,7 +70,7 @@ // Registers |observer| to be run when this context is invalidated. Closures // are run immediately when Invalidate() is called, not in a message loop. - void AddInvalidationObserver(const base::Closure& observer); + void AddInvalidationObserver(base::OnceClosure observer); // Returns true if this context is still valid, false if it isn't. // A context becomes invalid via Invalidate(). @@ -277,9 +277,9 @@ // The set of capabilities granted to this context by extensions. APIPermissionSet content_capabilities_; - // A list of base::Closure instances as an observer interface for + // A list of base::OnceClosure instances as an observer interface for // invalidation. - std::vector<base::Closure> invalidate_observers_; + std::vector<base::OnceClosure> invalidate_observers_; v8::Isolate* isolate_;
diff --git a/extensions/renderer/wake_event_page.cc b/extensions/renderer/wake_event_page.cc index ea449213..731afcfd 100644 --- a/extensions/renderer/wake_event_page.cc +++ b/extensions/renderer/wake_event_page.cc
@@ -46,7 +46,7 @@ weak_ptr_factory_(this) { // Delete self on invalidation. base::Unretained because by definition this // can't be deleted before it's deleted. - context->AddInvalidationObserver(base::Bind( + context->AddInvalidationObserver(base::BindOnce( &WakeEventPageNativeHandler::DeleteSelf, base::Unretained(this))); }
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc index 2b712b3..1f3829a 100644 --- a/gpu/ipc/in_process_command_buffer.cc +++ b/gpu/ipc/in_process_command_buffer.cc
@@ -89,6 +89,7 @@ base::AtomicSequenceNumber g_next_route_id; base::AtomicSequenceNumber g_next_image_id; +base::AtomicSequenceNumber g_next_transfer_buffer_id; CommandBufferId NextCommandBufferId() { return CommandBufferIdFromChannelAndRoute(kInProcessCommandBufferClientId, @@ -934,7 +935,7 @@ size_t size, int32_t* id) { scoped_refptr<Buffer> buffer = MakeMemoryBuffer(size); - *id = ++next_transfer_buffer_id_; + *id = g_next_transfer_buffer_id.GetNext() + 1; ScheduleGpuTask( base::BindOnce(&InProcessCommandBuffer::RegisterTransferBufferOnGpuThread, gpu_thread_weak_ptr_factory_.GetWeakPtr(), *id, buffer));
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h index 3561538..43ca25b 100644 --- a/gpu/ipc/in_process_command_buffer.h +++ b/gpu/ipc/in_process_command_buffer.h
@@ -330,7 +330,6 @@ int32_t last_put_offset_ = -1; Capabilities capabilities_; GpuMemoryBufferManager* gpu_memory_buffer_manager_ = nullptr; - int32_t next_transfer_buffer_id_ = 1; uint64_t next_fence_sync_release_ = 1; uint64_t flushed_fence_sync_release_ = 0; std::vector<SyncToken> next_flush_sync_token_fences_;
diff --git a/gpu/ipc/service/direct_composition_surface_win.cc b/gpu/ipc/service/direct_composition_surface_win.cc index 846a7702..b5afb09 100644 --- a/gpu/ipc/service/direct_composition_surface_win.cc +++ b/gpu/ipc/service/direct_composition_surface_win.cc
@@ -23,6 +23,7 @@ #include "gpu/ipc/service/gpu_channel_manager_delegate.h" #include "ui/display/display_switches.h" #include "ui/gfx/color_space_win.h" +#include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/transform.h" @@ -319,12 +320,10 @@ Microsoft::WRL::ComPtr<IDCompositionSurface> surface; uint64_t dcomp_surface_serial = 0; - gfx::Rect bounds; - float swap_chain_scale_x = 0.0f; - float swap_chain_scale_y = 0.0f; bool is_clipped = false; gfx::Rect clip_rect; gfx::Transform transform; + gfx::Point offset; }; // These functions return true if the visual tree was changed. @@ -336,12 +335,15 @@ const ui::DCRendererLayerParams& params); bool UpdateVisualClip(VisualInfo* visual_info, const ui::DCRendererLayerParams& params); + bool UpdateVisualTransform(VisualInfo* visual_info, + const gfx::Transform& video_transform, + const gfx::Point& offset); void CalculateVideoSwapChainParameters( const ui::DCRendererLayerParams& params, - gfx::Rect* video_visual_bounds_rect, - gfx::Size* video_input_size, - gfx::Size* video_swap_chain_size) const; + gfx::Size* video_swap_chain_size, + gfx::Transform* video_visual_transform, + gfx::Point* video_visual_offset) const; DirectCompositionSurfaceWin* surface_; std::vector<std::unique_ptr<ui::DCRendererLayerParams>> pending_overlays_; @@ -1008,12 +1010,13 @@ visual_info->surface.Reset(); } - gfx::Rect bounds_rect; - gfx::Size video_input_size; + gfx::Size video_input_size = gfx::ToCeiledSize(params.contents_rect.size()); gfx::Size swap_chain_size; + gfx::Transform video_transform; + gfx::Point video_offset; - CalculateVideoSwapChainParameters(params, &bounds_rect, &video_input_size, - &swap_chain_size); + CalculateVideoSwapChainParameters(params, &swap_chain_size, &video_transform, + &video_offset); Microsoft::WRL::ComPtr<IDCompositionVisual2> dc_visual = visual_info->content_visual; @@ -1049,58 +1052,28 @@ changed = true; } - // This is the scale from the swapchain size to the size of the contents - // onscreen. - float swap_chain_scale_x = - bounds_rect.width() * 1.0f / swap_chain_size.width(); - float swap_chain_scale_y = - bounds_rect.height() * 1.0f / swap_chain_size.height(); - - // This visual's transform changed. - if (swap_chain_scale_x != visual_info->swap_chain_scale_x || - swap_chain_scale_y != visual_info->swap_chain_scale_y || - params.transform != visual_info->transform || - bounds_rect != visual_info->bounds) { - visual_info->swap_chain_scale_x = swap_chain_scale_x; - visual_info->swap_chain_scale_y = swap_chain_scale_y; - visual_info->transform = params.transform; - visual_info->bounds = bounds_rect; - - gfx::Transform final_transform = params.transform; - gfx::Transform scale_transform; - scale_transform.Scale(swap_chain_scale_x, swap_chain_scale_y); - final_transform.PreconcatTransform(scale_transform); - final_transform.Transpose(); - - dc_visual->SetOffsetX(bounds_rect.x()); - dc_visual->SetOffsetY(bounds_rect.y()); - Microsoft::WRL::ComPtr<IDCompositionMatrixTransform> dcomp_transform; - dcomp_device_->CreateMatrixTransform(dcomp_transform.GetAddressOf()); - DCHECK(dcomp_transform); - D2D_MATRIX_3X2_F d2d_matrix = {{{final_transform.matrix().get(0, 0), - final_transform.matrix().get(0, 1), - final_transform.matrix().get(1, 0), - final_transform.matrix().get(1, 1), - final_transform.matrix().get(3, 0), - final_transform.matrix().get(3, 1)}}}; - dcomp_transform->SetMatrix(d2d_matrix); - dc_visual->SetTransform(dcomp_transform.Get()); + if (UpdateVisualTransform(visual_info, video_transform, video_offset)) { changed = true; } + return changed; } void DCLayerTree::CalculateVideoSwapChainParameters( const ui::DCRendererLayerParams& params, - gfx::Rect* video_visual_bounds_rect, - gfx::Size* video_input_size, - gfx::Size* video_swap_chain_size) const { + gfx::Size* video_swap_chain_size, + gfx::Transform* video_visual_transform, + gfx::Point* video_visual_offset) const { // Swap chain size is the minimum of the on-screen size and the source // size so the video processor can do the minimal amount of work and // the overlay has to read the minimal amount of data. // DWM is also less likely to promote a surface to an overlay if it's // much larger than its area on-screen. - gfx::Rect bounds_rect = params.rect; + + // display_rect is the rect on screen + gfx::RectF transformed_rect = gfx::RectF(params.rect); + params.transform.TransformRect(&transformed_rect); + gfx::Rect display_rect = gfx::ToEnclosingRect(transformed_rect); if (workarounds().disable_larger_than_screen_overlays && !g_overlay_monitor_size.IsEmpty()) { @@ -1115,34 +1088,86 @@ // TODO(jbauman): Remove when http://crbug.com/668278 is fixed. const int kOversizeMargin = 3; - if ((bounds_rect.x() >= 0) && - (bounds_rect.width() > g_overlay_monitor_size.width()) && - (bounds_rect.width() <= + if ((display_rect.x() >= 0) && + (display_rect.width() > g_overlay_monitor_size.width()) && + (display_rect.width() <= g_overlay_monitor_size.width() + kOversizeMargin)) { - bounds_rect.set_width(g_overlay_monitor_size.width()); + display_rect.set_width(g_overlay_monitor_size.width()); } - if ((bounds_rect.y() >= 0) && - (bounds_rect.height() > g_overlay_monitor_size.height()) && - (bounds_rect.height() <= + if ((display_rect.y() >= 0) && + (display_rect.height() > g_overlay_monitor_size.height()) && + (display_rect.height() <= g_overlay_monitor_size.height() + kOversizeMargin)) { - bounds_rect.set_height(g_overlay_monitor_size.height()); + display_rect.set_height(g_overlay_monitor_size.height()); } } - gfx::Size ceiled_input_size = gfx::ToCeiledSize(params.contents_rect.size()); - gfx::Size swap_chain_size = bounds_rect.size(); + // Downscaling doesn't work on Intel display HW, and so DWM will perform + // an extra BLT to avoid HW downscaling. This prevents the use of hardware + // overlays especially for protected video. + gfx::Size swap_chain_size = display_rect.size(); - if (g_supports_scaled_overlays) + if (g_supports_scaled_overlays) { + gfx::Size ceiled_input_size = + gfx::ToCeiledSize(params.contents_rect.size()); swap_chain_size.SetToMin(ceiled_input_size); + } // YUV surfaces must have an even width. if (swap_chain_size.width() % 2 == 1) swap_chain_size.set_width(swap_chain_size.width() + 1); - *video_visual_bounds_rect = bounds_rect; - *video_input_size = ceiled_input_size; + // Update the transform matrix. It will be used in dc_visual->SetTransform() + // This is the scale from the swapchain size to the size of the contents + // onscreen. + float swap_chain_scale_x = + params.rect.width() * 1.0f / swap_chain_size.width(); + float swap_chain_scale_y = + params.rect.height() * 1.0f / swap_chain_size.height(); + gfx::Transform transform = params.transform; + gfx::Transform scale_transform; + scale_transform.Scale(swap_chain_scale_x, swap_chain_scale_y); + transform.PreconcatTransform(scale_transform); + transform.Transpose(); + + // Offset relative to its parent, used in dc_visual->SetOffsetX() + // TODO(magchen): We should consider recalculating offset when it's non-zero. + // Have not seen non-zero params.rect.x() and y() so far. + gfx::Point offset(params.rect.x(), params.rect.y()); + *video_swap_chain_size = swap_chain_size; + *video_visual_transform = transform; + *video_visual_offset = offset; +} + +bool DCLayerTree::UpdateVisualTransform(VisualInfo* visual_info, + const gfx::Transform& transform, + const gfx::Point& offset) { + bool changed = false; + + // This visual's transform changed. + if (transform != visual_info->transform || offset != visual_info->offset) { + visual_info->transform = transform; + visual_info->offset = offset; + + Microsoft::WRL::ComPtr<IDCompositionVisual2> dc_visual = + visual_info->content_visual; + dc_visual->SetOffsetX(offset.x()); + dc_visual->SetOffsetY(offset.y()); + Microsoft::WRL::ComPtr<IDCompositionMatrixTransform> dcomp_transform; + dcomp_device_->CreateMatrixTransform(dcomp_transform.GetAddressOf()); + DCHECK(dcomp_transform); + D2D_MATRIX_3X2_F d2d_matrix = { + {{transform.matrix().get(0, 0), transform.matrix().get(0, 1), + transform.matrix().get(1, 0), transform.matrix().get(1, 1), + transform.matrix().get(3, 0), transform.matrix().get(3, 1)}}}; + dcomp_transform->SetMatrix(d2d_matrix); + dc_visual->SetTransform(dcomp_transform.Get()); + changed = true; + } + + return changed; } bool DCLayerTree::UpdateVisualForBackbuffer( @@ -1167,12 +1192,11 @@ changed = true; } - gfx::Rect bounds_rect = params.rect; - if (visual_info->bounds != bounds_rect || - !visual_info->transform.IsIdentity()) { - dc_visual->SetOffsetX(bounds_rect.x()); - dc_visual->SetOffsetY(bounds_rect.y()); - visual_info->bounds = bounds_rect; + gfx::Point offset = params.rect.origin(); + if (visual_info->offset != offset || !visual_info->transform.IsIdentity()) { + dc_visual->SetOffsetX(offset.x()); + dc_visual->SetOffsetY(offset.y()); + visual_info->offset = offset; dc_visual->SetTransform(nullptr); visual_info->transform = gfx::Transform(); changed = true; @@ -1327,8 +1351,9 @@ } // static -void DirectCompositionSurfaceWin::EnableScaledOverlaysForTesting() { - g_supports_scaled_overlays = true; +void DirectCompositionSurfaceWin::SetScaledOverlaysSupportedForTesting( + bool value) { + g_supports_scaled_overlays = value; } // static
diff --git a/gpu/ipc/service/direct_composition_surface_win.h b/gpu/ipc/service/direct_composition_surface_win.h index bc61dacd..f03d17a7 100644 --- a/gpu/ipc/service/direct_composition_surface_win.h +++ b/gpu/ipc/service/direct_composition_surface_win.h
@@ -50,7 +50,7 @@ // displays. Tearing is only used if vsync is also disabled via command line. static bool IsSwapChainTearingSupported(); - static void EnableScaledOverlaysForTesting(); + static void SetScaledOverlaysSupportedForTesting(bool value); bool InitializeNativeWindow();
diff --git a/gpu/ipc/service/direct_composition_surface_win_unittest.cc b/gpu/ipc/service/direct_composition_surface_win_unittest.cc index 0410f6d..5ce3fc40 100644 --- a/gpu/ipc/service/direct_composition_surface_win_unittest.cc +++ b/gpu/ipc/service/direct_composition_surface_win_unittest.cc
@@ -401,6 +401,155 @@ DestroySurface(std::move(surface)); } +// Ensure the swapchain size is set to the correct size if HW overlay scaling +// is support - swapchain should be the minimum of the decoded +// video buffer size and the onscreen video size +TEST(DirectCompositionSurfaceTest, SwapchainSizeWithScaledOverlays) { + if (!CheckIfDCSupported()) + return; + + TestImageTransportSurfaceDelegate delegate; + scoped_refptr<DirectCompositionSurfaceWin> surface( + new DirectCompositionSurfaceWin(nullptr, delegate.AsWeakPtr(), + ui::GetHiddenWindow())); + EXPECT_TRUE(surface->Initialize()); + + scoped_refptr<gl::GLContext> context = + gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs()); + EXPECT_TRUE(context->MakeCurrent(surface.get())); + + surface->SetEnableDCLayers(true); + + Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device = + gl::QueryD3D11DeviceObjectFromANGLE(); + + gfx::Size texture_size(64, 64); + Microsoft::WRL::ComPtr<ID3D11Texture2D> texture = + CreateNV12Texture(d3d11_device, texture_size, false); + + scoped_refptr<gl::GLImageDXGI> image_dxgi( + new gl::GLImageDXGI(texture_size, nullptr)); + image_dxgi->SetTexture(texture, 0); + image_dxgi->SetColorSpace(gfx::ColorSpace::CreateREC709()); + + // HW supports scaled overlays + // The input texture size is maller than the window size. + surface->SetScaledOverlaysSupportedForTesting(true); + gfx::Size window_size(100, 100); + ui::DCRendererLayerParams params( + false, gfx::Rect(), 1, gfx::Transform(), + std::vector<scoped_refptr<gl::GLImage>>{image_dxgi}, + gfx::RectF(gfx::Rect(texture_size)), gfx::Rect(window_size), 0, 0, 1.0, 0, + false); + + surface->ScheduleDCLayer(params); + EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing())); + Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain = + surface->GetLayerSwapChainForTesting(1); + ASSERT_TRUE(swap_chain); + + DXGI_SWAP_CHAIN_DESC Desc; + EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc(&Desc))); + EXPECT_EQ((int)Desc.BufferDesc.Width, texture_size.width()); + EXPECT_EQ((int)Desc.BufferDesc.Height, texture_size.height()); + + // The input texture size is bigger than the window size. + window_size = gfx::Size(32, 48); + ui::DCRendererLayerParams params2( + false, gfx::Rect(), 1, gfx::Transform(), + std::vector<scoped_refptr<gl::GLImage>>{image_dxgi}, + gfx::RectF(gfx::Rect(texture_size)), gfx::Rect(window_size), 0, 0, 1.0, 0, + false); + + surface->ScheduleDCLayer(params2); + EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing())); + + Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 = + surface->GetLayerSwapChainForTesting(1); + ASSERT_TRUE(swap_chain2); + + EXPECT_TRUE(SUCCEEDED(swap_chain2->GetDesc(&Desc))); + EXPECT_EQ((int)Desc.BufferDesc.Width, window_size.width()); + EXPECT_EQ((int)Desc.BufferDesc.Height, window_size.height()); + + context = nullptr; + DestroySurface(std::move(surface)); +} + +// Ensure the swapchain size is set to the correct size if HW overlay scaling +// is not support - swapchain should be the onscreen video size +TEST(DirectCompositionSurfaceTest, SwapchainSizeWithoutScaledOverlays) { + if (!CheckIfDCSupported()) + return; + + TestImageTransportSurfaceDelegate delegate; + scoped_refptr<DirectCompositionSurfaceWin> surface( + new DirectCompositionSurfaceWin(nullptr, delegate.AsWeakPtr(), + ui::GetHiddenWindow())); + EXPECT_TRUE(surface->Initialize()); + + scoped_refptr<gl::GLContext> context = + gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs()); + EXPECT_TRUE(context->MakeCurrent(surface.get())); + + surface->SetEnableDCLayers(true); + + Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device = + gl::QueryD3D11DeviceObjectFromANGLE(); + + gfx::Size texture_size(80, 80); + Microsoft::WRL::ComPtr<ID3D11Texture2D> texture = + CreateNV12Texture(d3d11_device, texture_size, false); + + scoped_refptr<gl::GLImageDXGI> image_dxgi( + new gl::GLImageDXGI(texture_size, nullptr)); + image_dxgi->SetTexture(texture, 0); + image_dxgi->SetColorSpace(gfx::ColorSpace::CreateREC709()); + + // HW doesn't support scaled overlays + // The input texture size is bigger than the window size. + surface->SetScaledOverlaysSupportedForTesting(false); + gfx::Size window_size(42, 42); + ui::DCRendererLayerParams params( + false, gfx::Rect(), 1, gfx::Transform(), + std::vector<scoped_refptr<gl::GLImage>>{image_dxgi}, + gfx::RectF(gfx::Rect(texture_size)), gfx::Rect(window_size), 0, 0, 1.0, 0, + false); + + surface->ScheduleDCLayer(params); + EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing())); + Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain = + surface->GetLayerSwapChainForTesting(1); + ASSERT_TRUE(swap_chain); + + DXGI_SWAP_CHAIN_DESC Desc; + EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc(&Desc))); + EXPECT_EQ((int)Desc.BufferDesc.Width, window_size.width()); + EXPECT_EQ((int)Desc.BufferDesc.Height, window_size.height()); + + // The input texture size is smaller than the window size. + window_size = gfx::Size(124, 136); + ui::DCRendererLayerParams params2( + false, gfx::Rect(), 1, gfx::Transform(), + std::vector<scoped_refptr<gl::GLImage>>{image_dxgi}, + gfx::RectF(gfx::Rect(texture_size)), gfx::Rect(window_size), 0, 0, 1.0, 0, + false); + + surface->ScheduleDCLayer(params2); + EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing())); + + Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 = + surface->GetLayerSwapChainForTesting(1); + ASSERT_TRUE(swap_chain2); + + EXPECT_TRUE(SUCCEEDED(swap_chain2->GetDesc(&Desc))); + EXPECT_EQ((int)Desc.BufferDesc.Width, window_size.width()); + EXPECT_EQ((int)Desc.BufferDesc.Height, window_size.height()); + + context = nullptr; + DestroySurface(std::move(surface)); +} + SkColor ReadBackWindowPixel(HWND window, const gfx::Point& point) { base::win::ScopedCreateDC mem_hdc(::CreateCompatibleDC(nullptr)); void* bits = nullptr; @@ -751,7 +900,7 @@ InitializeSurface(); // Swap chain size is overridden to content rect size only if scaled overlays // are supported. - DirectCompositionSurfaceWin::EnableScaledOverlaysForTesting(); + DirectCompositionSurfaceWin::SetScaledOverlaysSupportedForTesting(true); surface_->SetEnableDCLayers(true); gfx::Size window_size(100, 100);
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h index 6d7bd9f7..334be37 100644 --- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h +++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
@@ -65,7 +65,7 @@ void ConfirmSaveAutofillProfile(const AutofillProfile& profile, base::OnceClosure callback) override; void ConfirmSaveCreditCardLocally(const CreditCard& card, - const base::Closure& callback) override; + base::OnceClosure callback) override; void ConfirmSaveCreditCardToCloud( const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, @@ -74,7 +74,7 @@ void ConfirmCreditCardFillAssist(const CreditCard& card, const base::Closure& callback) override; void LoadRiskData( - const base::Callback<void(const std::string&)>& callback) override; + base::OnceCallback<void(const std::string&)> callback) override; bool HasCreditCardScanFeature() override; void ScanCreditCard(const CreditCardScanCallback& callback) override; void ShowAutofillPopup(
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm index 470bd5b..b22fddc 100644 --- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm +++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
@@ -161,13 +161,13 @@ void ChromeAutofillClientIOS::ConfirmSaveCreditCardLocally( const CreditCard& card, - const base::Closure& callback) { + base::OnceClosure callback) { infobar_manager_->AddInfoBar(CreateSaveCardInfoBarMobile( std::make_unique<AutofillSaveCardInfoBarDelegateMobile>( false, card, std::unique_ptr<base::DictionaryValue>(nullptr), /*upload_save_card_callback=*/ base::OnceCallback<void(const base::string16&)>(), - /*local_save_card_callback=*/callback, GetPrefs()))); + /*local_save_card_callback=*/std::move(callback), GetPrefs()))); } void ChromeAutofillClientIOS::ShowLocalCardMigrationDialog( @@ -214,8 +214,8 @@ } void ChromeAutofillClientIOS::LoadRiskData( - const base::Callback<void(const std::string&)>& callback) { - callback.Run(ios::GetChromeBrowserProvider()->GetRiskData()); + base::OnceCallback<void(const std::string&)> callback) { + std::move(callback).Run(ios::GetChromeBrowserProvider()->GetRiskData()); } bool ChromeAutofillClientIOS::HasCreditCardScanFeature() {
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index 6e57b50..b8c17fc5 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -5126,14 +5126,30 @@ CGFloat newPageOffset = 0; UIView* newPage = nil; CGFloat offset = 0; - GURL tabURL = tab.webState->GetLastCommittedURL(); // Toolbar snapshot is only used for the UIRefresh animation. UIView* toolbarSnapshot; - // Vislble URL should be more correct here than last committed, but for - // safety, limiting the scope only to WKBasedNavigationManager, which needs - // it to correctly animate NTP. See https://crbug.com/819606. - if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) + + GURL tabURL = tab.webState->GetLastCommittedURL(); + BOOL expectingPageLoad = NO; + if (_browserState && !_isShutdown) { + WebStateListWebUsageEnabler* webUsageEnabler = + WebStateListWebUsageEnablerFactory::GetInstance()->GetForBrowserState( + _browserState); + expectingPageLoad = webUsageEnabler->IsWebUsageEnabled() && + webUsageEnabler->TriggersInitialLoad(); + } + if (web::GetWebClient()->IsSlimNavigationManagerEnabled() || + expectingPageLoad) { + // The visible URL is more correct here. However, the last committed URL + // has been used historically, and it's unclear if there are unintended side + // effects from from using the visible URL in all situations. In order to + // mitigate the risk from using the visible URL, additional checks are used + // here to only update the URL for known conditions in which the last- + // committed URL is incorrect. + // TODO(crbug.com/880262): Update to use visible URL for all new tabs. tabURL = tab.webState->GetVisibleURL(); + } + if (tabURL == kChromeUINewTabURL && !_isOffTheRecord && ![self canShowTabStrip]) { offset = 0;
diff --git a/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm index fd5b1ae..4ddaebb 100644 --- a/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm +++ b/ios/chrome/browser/ui/payments/payment_request_picker_view_controller.mm
@@ -138,6 +138,12 @@ [self addChildViewController:self.appBarViewController]; ConfigureAppBarViewControllerWithCardStyle(self.appBarViewController); self.appBarViewController.headerView.trackingScrollView = self.tableView; + // Match the width of the parent view. + CGRect frame = self.appBarViewController.view.frame; + frame.origin.x = 0; + frame.size.width = + self.appBarViewController.parentViewController.view.bounds.size.width; + self.appBarViewController.view.frame = frame; [self.view addSubview:self.appBarViewController.view]; [self.appBarViewController didMoveToParentViewController:self]; }
diff --git a/ios/web/navigation/navigation_item_storage_builder.mm b/ios/web/navigation/navigation_item_storage_builder.mm index 2efd08a..899f58c6 100644 --- a/ios/web/navigation/navigation_item_storage_builder.mm +++ b/ios/web/navigation/navigation_item_storage_builder.mm
@@ -46,6 +46,8 @@ item->page_display_state_ = navigation_item_storage.displayState; item->should_skip_repost_form_confirmation_ = navigation_item_storage.shouldSkipRepostFormConfirmation; + // Use reload transition type to avoid incorrect increase for typed count. + item->transition_type_ = ui::PAGE_TRANSITION_RELOAD; item->user_agent_type_ = navigation_item_storage.userAgentType; item->post_data_ = navigation_item_storage.POSTData; item->http_request_headers_ =
diff --git a/ios/web/web_state/web_state_observer_inttest.mm b/ios/web/web_state/web_state_observer_inttest.mm index b2aab579..bede7a971 100644 --- a/ios/web/web_state/web_state_observer_inttest.mm +++ b/ios/web/web_state/web_state_observer_inttest.mm
@@ -490,10 +490,9 @@ EXPECT_NE(0, *nav_id); EXPECT_EQ(url, (*context)->GetUrl()); EXPECT_TRUE((*context)->HasUserGesture()); - // Transition type is not restored (crbug.com/888011). ui::PageTransition actual_transition = (*context)->GetPageTransition(); - EXPECT_TRUE(PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_LINK, - actual_transition)) + EXPECT_TRUE(PageTransitionCoreTypeIs( + ui::PageTransition::PAGE_TRANSITION_RELOAD, actual_transition)) << "Got unexpected transition: " << actual_transition; EXPECT_FALSE((*context)->IsSameDocument()); EXPECT_FALSE((*context)->HasCommitted()); @@ -526,10 +525,9 @@ EXPECT_EQ(*nav_id, (*context)->GetNavigationId()); EXPECT_EQ(url, (*context)->GetUrl()); EXPECT_TRUE((*context)->HasUserGesture()); - // Transition type is not restored (crbug.com/888011). ui::PageTransition actual_transition = (*context)->GetPageTransition(); - EXPECT_TRUE(PageTransitionCoreTypeIs(ui::PageTransition::PAGE_TRANSITION_LINK, - actual_transition)) + EXPECT_TRUE(PageTransitionCoreTypeIs( + ui::PageTransition::PAGE_TRANSITION_RELOAD, actual_transition)) << "Got unexpected transition: " << actual_transition; EXPECT_FALSE((*context)->IsSameDocument()); EXPECT_TRUE((*context)->HasCommitted());
diff --git a/ios/web_view/internal/autofill/cwv_autofill_client_ios_bridge.h b/ios/web_view/internal/autofill/cwv_autofill_client_ios_bridge.h index d9ecc63..9d7bde75 100644 --- a/ios/web_view/internal/autofill/cwv_autofill_client_ios_bridge.h +++ b/ios/web_view/internal/autofill/cwv_autofill_client_ios_bridge.h
@@ -21,7 +21,7 @@ // Bridge for AutofillClient's method |ConfirmSaveCreditCardLocally|. - (void)confirmSaveCreditCardLocally:(const autofill::CreditCard&)creditCard - callback:(const base::RepeatingClosure&)callback; + callback:(base::OnceClosure)callback; // Bridge for AutofillClient's method |ShowUnmaskPrompt|. - (void)
diff --git a/ios/web_view/internal/autofill/cwv_autofill_controller.mm b/ios/web_view/internal/autofill/cwv_autofill_controller.mm index 37d5265..bbc581c 100644 --- a/ios/web_view/internal/autofill/cwv_autofill_controller.mm +++ b/ios/web_view/internal/autofill/cwv_autofill_controller.mm
@@ -305,20 +305,18 @@ } - (void)confirmSaveCreditCardLocally:(const autofill::CreditCard&)creditCard - callback:(const base::RepeatingClosure&)callback { + callback:(base::OnceClosure)callback { if ([_delegate respondsToSelector:@selector (autofillController:decidePolicyForLocalStorageOfCreditCard :decisionHandler:)]) { CWVCreditCard* card = [[CWVCreditCard alloc] initWithCreditCard:creditCard]; - __block base::RepeatingClosure scopedCallback = callback; + __block base::OnceClosure scopedCallback = std::move(callback); [_delegate autofillController:self decidePolicyForLocalStorageOfCreditCard:card decisionHandler:^(CWVStoragePolicy policy) { if (policy == CWVStoragePolicyAllow) { - if (scopedCallback) { - scopedCallback.Run(); - scopedCallback.Reset(); - } + if (scopedCallback) + std::move(scopedCallback).Run(); } }]; }
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h index 54e9e51..9afdfcf 100644 --- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h +++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
@@ -58,7 +58,7 @@ void ConfirmSaveAutofillProfile(const AutofillProfile& profile, base::OnceClosure callback) override; void ConfirmSaveCreditCardLocally(const CreditCard& card, - const base::Closure& callback) override; + base::OnceClosure callback) override; void ConfirmSaveCreditCardToCloud( const CreditCard& card, std::unique_ptr<base::DictionaryValue> legal_message, @@ -67,7 +67,7 @@ void ConfirmCreditCardFillAssist(const CreditCard& card, const base::Closure& callback) override; void LoadRiskData( - const base::Callback<void(const std::string&)>& callback) override; + base::OnceCallback<void(const std::string&)> callback) override; bool HasCreditCardScanFeature() override; void ScanCreditCard(const CreditCardScanCallback& callback) override; void ShowAutofillPopup(
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm index 425288c..9577f35 100644 --- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm +++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
@@ -113,8 +113,8 @@ void WebViewAutofillClientIOS::ConfirmSaveCreditCardLocally( const CreditCard& card, - const base::RepeatingClosure& callback) { - [bridge_ confirmSaveCreditCardLocally:card callback:callback]; + base::OnceClosure callback) { + [bridge_ confirmSaveCreditCardLocally:card callback:std::move(callback)]; } void WebViewAutofillClientIOS::ConfirmSaveCreditCardToCloud( @@ -128,7 +128,7 @@ const base::Closure& callback) {} void WebViewAutofillClientIOS::LoadRiskData( - const base::Callback<void(const std::string&)>& callback) {} + base::OnceCallback<void(const std::string&)> callback) {} bool WebViewAutofillClientIOS::HasCreditCardScanFeature() { return false;
diff --git a/media/base/eme_constants.h b/media/base/eme_constants.h index a7b85a0..0da02be 100644 --- a/media/base/eme_constants.h +++ b/media/base/eme_constants.h
@@ -18,26 +18,23 @@ // Defines bitmask values that specify codecs used in Encrypted Media Extension // (EME). Each value represents a codec within a specific container. -// -// TODO(yucliu): Remove container name from the enum. See crbug.com/724362 for -// more details. enum EmeCodec : uint32_t { EME_CODEC_NONE = 0, - EME_CODEC_WEBM_OPUS = 1 << 0, - EME_CODEC_WEBM_VORBIS = 1 << 1, - EME_CODEC_WEBM_VP8 = 1 << 2, - EME_CODEC_WEBM_VP9 = 1 << 3, - EME_CODEC_MP4_AAC = 1 << 4, + EME_CODEC_OPUS = 1 << 0, + EME_CODEC_VORBIS = 1 << 1, + EME_CODEC_VP8 = 1 << 2, + EME_CODEC_LEGACY_VP9 = 1 << 3, + EME_CODEC_AAC = 1 << 4, // AVC1 is shared by MP4 and MP2T. - EME_CODEC_MP4_AVC1 = 1 << 5, - EME_CODEC_COMMON_VP9 = 1 << 6, - EME_CODEC_MP4_HEVC = 1 << 7, - EME_CODEC_MP4_DV_AVC = 1 << 8, - EME_CODEC_MP4_DV_HEVC = 1 << 9, - EME_CODEC_MP4_AC3 = 1 << 10, - EME_CODEC_MP4_EAC3 = 1 << 11, - EME_CODEC_MP4_MPEG_H_AUDIO = 1 << 12, - EME_CODEC_MP4_FLAC = 1 << 13, + EME_CODEC_AVC1 = 1 << 5, + EME_CODEC_VP9 = 1 << 6, // New multi-part VP9 for WebM and MP4. + EME_CODEC_HEVC = 1 << 7, + EME_CODEC_DOLBY_VISION_AVC = 1 << 8, + EME_CODEC_DOLBY_VISION_HEVC = 1 << 9, + EME_CODEC_AC3 = 1 << 10, + EME_CODEC_EAC3 = 1 << 11, + EME_CODEC_MPEG_H_AUDIO = 1 << 12, + EME_CODEC_FLAC = 1 << 13, }; // *_ALL values should only be used for masking, do not use them to specify @@ -46,30 +43,31 @@ using SupportedCodecs = uint32_t; constexpr SupportedCodecs GetMp4AudioCodecs() { - SupportedCodecs codecs = EME_CODEC_MP4_FLAC; + SupportedCodecs codecs = EME_CODEC_FLAC; #if BUILDFLAG(USE_PROPRIETARY_CODECS) - codecs |= EME_CODEC_MP4_AAC; + codecs |= EME_CODEC_AAC; #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) - codecs |= EME_CODEC_MP4_AC3 | EME_CODEC_MP4_EAC3; + codecs |= EME_CODEC_AC3 | EME_CODEC_EAC3; #endif // BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) #if BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING) - codecs |= EME_CODEC_MP4_MPEG_H_AUDIO; + codecs |= EME_CODEC_MPEG_H_AUDIO; #endif // BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING) #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) return codecs; } constexpr SupportedCodecs GetMp4VideoCodecs() { - SupportedCodecs codecs = EME_CODEC_COMMON_VP9; + // VP9 is supported in MP4, but legacy VP9 is not. + SupportedCodecs codecs = EME_CODEC_VP9; #if BUILDFLAG(USE_PROPRIETARY_CODECS) - codecs |= EME_CODEC_MP4_AVC1; + codecs |= EME_CODEC_AVC1; #if BUILDFLAG(ENABLE_HEVC_DEMUXING) - codecs |= EME_CODEC_MP4_HEVC; + codecs |= EME_CODEC_HEVC; #endif // BUILDFLAG(ENABLE_HEVC_DEMUXING) #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) - codecs |= EME_CODEC_MP4_DV_AVC; + codecs |= EME_CODEC_DOLBY_VISION_AVC; #if BUILDFLAG(ENABLE_HEVC_DEMUXING) - codecs |= EME_CODEC_MP4_DV_HEVC; + codecs |= EME_CODEC_DOLBY_VISION_HEVC; #endif // BUILDFLAG(ENABLE_HEVC_DEMUXING) #endif // BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) @@ -77,10 +75,11 @@ } constexpr SupportedCodecs EME_CODEC_WEBM_AUDIO_ALL = - EME_CODEC_WEBM_OPUS | EME_CODEC_WEBM_VORBIS; + EME_CODEC_OPUS | EME_CODEC_VORBIS; +// Both VP9 and legacy VP9 are supported in WebM. constexpr SupportedCodecs EME_CODEC_WEBM_VIDEO_ALL = - EME_CODEC_WEBM_VP8 | EME_CODEC_WEBM_VP9 | EME_CODEC_COMMON_VP9; + EME_CODEC_VP8 | EME_CODEC_LEGACY_VP9 | EME_CODEC_VP9; constexpr SupportedCodecs EME_CODEC_WEBM_ALL = EME_CODEC_WEBM_AUDIO_ALL | EME_CODEC_WEBM_VIDEO_ALL; @@ -102,7 +101,7 @@ #if BUILDFLAG(USE_PROPRIETARY_CODECS) #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) -constexpr SupportedCodecs EME_CODEC_MP2T_VIDEO_ALL = EME_CODEC_MP4_AVC1; +constexpr SupportedCodecs EME_CODEC_MP2T_VIDEO_ALL = EME_CODEC_AVC1; static_assert( (EME_CODEC_MP2T_VIDEO_ALL & EME_CODEC_VIDEO_ALL) == EME_CODEC_MP2T_VIDEO_ALL,
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc index c62d06e..9cf3dd8 100644 --- a/media/base/key_systems.cc +++ b/media/base/key_systems.cc
@@ -58,35 +58,35 @@ // Mapping between codec names and enum values. static const NameToCodec kCodecMap[] = { - {"opus", EME_CODEC_WEBM_OPUS}, // Opus. - {"vorbis", EME_CODEC_WEBM_VORBIS}, // Vorbis. - {"vp8", EME_CODEC_WEBM_VP8}, // VP8. - {"vp8.0", EME_CODEC_WEBM_VP8}, // VP8. - {"vp9", EME_CODEC_WEBM_VP9}, // VP9. - {"vp9.0", EME_CODEC_WEBM_VP9}, // VP9. - {"vp09", EME_CODEC_COMMON_VP9}, // New multi-part VP9 for WebM and MP4. - {"flac", EME_CODEC_MP4_FLAC}, // FLAC. + {"opus", EME_CODEC_OPUS}, // Opus. + {"vorbis", EME_CODEC_VORBIS}, // Vorbis. + {"vp8", EME_CODEC_VP8}, // VP8. + {"vp8.0", EME_CODEC_VP8}, // VP8. + {"vp9", EME_CODEC_LEGACY_VP9}, // VP9. + {"vp9.0", EME_CODEC_LEGACY_VP9}, // VP9. + {"vp09", EME_CODEC_VP9}, // New multi-part VP9 for WebM and MP4. + {"flac", EME_CODEC_FLAC}, // FLAC. #if BUILDFLAG(USE_PROPRIETARY_CODECS) - {"mp4a", EME_CODEC_MP4_AAC}, // AAC. + {"mp4a", EME_CODEC_AAC}, // AAC. #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING) - {"ac-3", EME_CODEC_MP4_AC3}, // AC3. - {"ec-3", EME_CODEC_MP4_EAC3}, // EAC3. + {"ac-3", EME_CODEC_AC3}, // AC3. + {"ec-3", EME_CODEC_EAC3}, // EAC3. #endif #if BUILDFLAG(ENABLE_MPEG_H_AUDIO_DEMUXING) - {"mhm1", EME_CODEC_MP4_MPEG_H_AUDIO}, // MPEG-H Audio. + {"mhm1", EME_CODEC_MPEG_H_AUDIO}, // MPEG-H Audio. #endif - {"avc1", EME_CODEC_MP4_AVC1}, // AVC1 for MP4 and MP2T - {"avc3", EME_CODEC_MP4_AVC1}, // AVC3 for MP4 and MP2T + {"avc1", EME_CODEC_AVC1}, // AVC1 for MP4 and MP2T + {"avc3", EME_CODEC_AVC1}, // AVC3 for MP4 and MP2T #if BUILDFLAG(ENABLE_HEVC_DEMUXING) - {"hev1", EME_CODEC_MP4_HEVC}, // HEV1. - {"hvc1", EME_CODEC_MP4_HEVC}, // HVC1. + {"hev1", EME_CODEC_HEVC}, // HEV1. + {"hvc1", EME_CODEC_HEVC}, // HVC1. #endif #if BUILDFLAG(ENABLE_DOLBY_VISION_DEMUXING) - {"dva1", EME_CODEC_MP4_DV_AVC}, // DolbyVision AVC - {"dvav", EME_CODEC_MP4_DV_AVC}, // DolbyVision AVC + {"dva1", EME_CODEC_DOLBY_VISION_AVC}, // DolbyVision AVC + {"dvav", EME_CODEC_DOLBY_VISION_AVC}, // DolbyVision AVC #if BUILDFLAG(ENABLE_HEVC_DEMUXING) - {"dvh1", EME_CODEC_MP4_DV_HEVC}, // DolbyVision HEVC - {"dvhe", EME_CODEC_MP4_DV_HEVC}, // DolbyVision HEVC + {"dvh1", EME_CODEC_DOLBY_VISION_HEVC}, // DolbyVision HEVC + {"dvhe", EME_CODEC_DOLBY_VISION_HEVC}, // DolbyVision HEVC #endif #endif #endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 18e6c5a..6d9f018 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -349,6 +349,11 @@ const base::Feature kHardwareSecureDecryption{ "HardwareSecureDecryption", base::FEATURE_DISABLED_BY_DEFAULT}; +// Limits number of media tags loading in parallel to 6. This speeds up +// preloading of any media that requires multiple requests to preload. +const base::Feature kLimitParallelMediaPreloading{ + "LimitParallelMediaPreloading", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables low-delay video rendering in media pipeline on "live" stream. const base::Feature kLowDelayVideoRenderingOnLiveStream{ "low-delay-video-rendering-on-live-stream",
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index ebb96a8f3..c0220d36 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -101,17 +101,16 @@ MEDIA_EXPORT extern const base::Feature kAutoplayIgnoreWebAudio; MEDIA_EXPORT extern const base::Feature kAutoplaySoundSettings; MEDIA_EXPORT extern const base::Feature kAv1Decoder; -MEDIA_EXPORT extern const base::Feature kBackgroundVideoPauseOptimization; MEDIA_EXPORT extern const base::Feature kBackgroundSrcVideoTrackOptimization; -MEDIA_EXPORT extern const base::Feature kD3D11VideoDecoder; +MEDIA_EXPORT extern const base::Feature kBackgroundVideoPauseOptimization; MEDIA_EXPORT extern const base::Feature kD3D11EncryptedMedia; MEDIA_EXPORT extern const base::Feature kD3D11VP9Decoder; +MEDIA_EXPORT extern const base::Feature kD3D11VideoDecoder; MEDIA_EXPORT extern const base::Feature kExternalClearKeyForTesting; MEDIA_EXPORT extern const base::Feature kHardwareSecureDecryption; +MEDIA_EXPORT extern const base::Feature kLimitParallelMediaPreloading; MEDIA_EXPORT extern const base::Feature kLowDelayVideoRenderingOnLiveStream; MEDIA_EXPORT extern const base::Feature kMediaCastOverlayButton; -MEDIA_EXPORT extern const base::Feature kRecordMediaEngagementScores; -MEDIA_EXPORT extern const base::Feature kRecordWebAudioEngagement; MEDIA_EXPORT extern const base::Feature kMediaEngagementBypassAutoplayPolicies; MEDIA_EXPORT extern const base::Feature kMemoryPressureBasedSourceBufferGC; MEDIA_EXPORT extern const base::Feature kMojoVideoDecoder; @@ -124,19 +123,22 @@ MEDIA_EXPORT extern const base::Feature kPictureInPicture; MEDIA_EXPORT extern const base::Feature kPreloadMediaEngagementData; MEDIA_EXPORT extern const base::Feature kPreloadMetadataLazyLoad; -MEDIA_EXPORT extern const base::Feature kResumeBackgroundVideo; +MEDIA_EXPORT extern const base::Feature kPreloadMetadataSuspend; MEDIA_EXPORT extern const base::Feature kRTCVideoDecoderAdapter; +MEDIA_EXPORT extern const base::Feature kRecordMediaEngagementScores; +MEDIA_EXPORT extern const base::Feature kRecordWebAudioEngagement; +MEDIA_EXPORT extern const base::Feature kResumeBackgroundVideo; MEDIA_EXPORT extern const base::Feature kSpecCompliantCanPlayThrough; +MEDIA_EXPORT extern const base::Feature kUnifiedAutoplay; MEDIA_EXPORT extern const base::Feature kUseAndroidOverlay; MEDIA_EXPORT extern const base::Feature kUseAndroidOverlayAggressively; +MEDIA_EXPORT extern const base::Feature kUseModernMediaControls; MEDIA_EXPORT extern const base::Feature kUseNewMediaCache; MEDIA_EXPORT extern const base::Feature kUseR16Texture; -MEDIA_EXPORT extern const base::Feature kVaapiVP8Encoder; -MEDIA_EXPORT extern const base::Feature kVideoBlitColorAccuracy; -MEDIA_EXPORT extern const base::Feature kUnifiedAutoplay; MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideo; MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideoMS; -MEDIA_EXPORT extern const base::Feature kUseModernMediaControls; +MEDIA_EXPORT extern const base::Feature kVaapiVP8Encoder; +MEDIA_EXPORT extern const base::Feature kVideoBlitColorAccuracy; #if defined(OS_ANDROID) MEDIA_EXPORT extern const base::Feature kMediaControlsExpandGesture;
diff --git a/media/blink/multibuffer_data_source.cc b/media/blink/multibuffer_data_source.cc index 3d6a8ffb..69198c9 100644 --- a/media/blink/multibuffer_data_source.cc +++ b/media/blink/multibuffer_data_source.cc
@@ -120,7 +120,7 @@ MultibufferDataSource::MultibufferDataSource( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - scoped_refptr<UrlData> url_data, + scoped_refptr<UrlData> url_data_arg, MediaLog* media_log, BufferedDataSourceHost* host, const DownloadingCB& downloading_cb) @@ -129,7 +129,6 @@ loading_(false), failed_(false), render_task_runner_(task_runner), - url_data_(std::move(url_data)), stop_signal_received_(false), media_has_played_(false), single_origin_(true), @@ -141,13 +140,14 @@ host_(host), downloading_cb_(downloading_cb), weak_factory_(this) { + url_data_and_loading_state_.SetUrlData(std::move(url_data_arg)); weak_ptr_ = weak_factory_.GetWeakPtr(); DCHECK(host_); DCHECK(downloading_cb_); DCHECK(render_task_runner_->BelongsToCurrentThread()); - DCHECK(url_data_); - url_data_->Use(); - url_data_->OnRedirect( + DCHECK(url_data()); + url_data()->Use(); + url_data()->OnRedirect( base::Bind(&MultibufferDataSource::OnRedirect, weak_ptr_)); } @@ -160,7 +160,7 @@ } bool MultibufferDataSource::assume_fully_buffered() { - return !url_data_->url().SchemeIsHTTPOrHTTPS(); + return !url_data()->url().SchemeIsHTTPOrHTTPS(); } void MultibufferDataSource::SetReader(MultiBufferReader* reader) { @@ -174,7 +174,7 @@ DCHECK(render_task_runner_->BelongsToCurrentThread()); SetReader(new MultiBufferReader( - url_data_->multibuffer(), first_byte_position, last_byte_position, + url_data()->multibuffer(), first_byte_position, last_byte_position, base::Bind(&MultibufferDataSource::ProgressCallback, weak_ptr_))); reader_->SetIsClientAudioElement(is_client_audio_element_); UpdateBufferSizes(); @@ -187,7 +187,7 @@ lock_.AssertAcquired(); reader_.reset(new MultiBufferReader( - url_data_->multibuffer(), first_byte_position, last_byte_position, + url_data()->multibuffer(), first_byte_position, last_byte_position, base::Bind(&MultibufferDataSource::ProgressCallback, weak_ptr_))); UpdateBufferSizes(); } @@ -199,6 +199,8 @@ init_cb_ = init_cb; + url_data_and_loading_state_.SetLoadingState( + UrlData::UrlDataWithLoadingState::LoadingState::kPreload); CreateResourceLoader(0, kPositionNotSpecified); // We're not allowed to call Wait() if data is already available. @@ -236,14 +238,14 @@ StopLoader(); return; } - if (url_data_->url().GetOrigin() != destination->url().GetOrigin()) { + if (url_data()->url().GetOrigin() != destination->url().GetOrigin()) { single_origin_ = false; } SetReader(nullptr); - url_data_ = destination; + url_data_and_loading_state_.SetUrlData(std::move(destination)); - if (url_data_) { - url_data_->OnRedirect( + if (url_data()) { + url_data()->OnRedirect( base::Bind(&MultibufferDataSource::OnRedirect, weak_ptr_)); if (init_cb_) { @@ -285,7 +287,7 @@ } bool MultibufferDataSource::DidPassCORSAccessCheck() const { - if (url_data_->cors_mode() == UrlData::CORS_UNSPECIFIED) + if (url_data()->cors_mode() == UrlData::CORS_UNSPECIFIED) return false; // If init_cb is set, we know initialization is not finished yet. @@ -297,7 +299,7 @@ } bool MultibufferDataSource::DidGetOpaqueResponseViaServiceWorker() const { - return url_data_->has_opaque_data(); + return url_data()->has_opaque_data(); // TODO(falken): Do we need to do something about |init_cb_| like // in DidPassCORSAccessCheck()? @@ -320,6 +322,8 @@ cancel_on_defer_ = false; // Once we start playing, we need preloading. preload_ = AUTO; + url_data_and_loading_state_.SetLoadingState( + UrlData::UrlDataWithLoadingState::LoadingState::kHasPlayed); UpdateBufferSizes(); } @@ -355,6 +359,8 @@ void MultibufferDataSource::OnBufferingHaveEnough(bool always_cancel) { DCHECK(render_task_runner_->BelongsToCurrentThread()); + url_data_and_loading_state_.SetLoadingState( + UrlData::UrlDataWithLoadingState::LoadingState::kIdle); if (reader_ && (always_cancel || (preload_ == METADATA && !media_has_played_ && !IsStreaming()))) { cancel_on_defer_ = true; @@ -374,12 +380,12 @@ int64_t MultibufferDataSource::GetMemoryUsage() const { // TODO(hubbe): Make more accurate when url_data_ is shared. - return base::checked_cast<int64_t>(url_data_->CachedSize()) - << url_data_->multibuffer()->block_size_shift(); + return base::checked_cast<int64_t>(url_data()->CachedSize()) + << url_data()->multibuffer()->block_size_shift(); } GURL MultibufferDataSource::GetUrlAfterRedirects() const { - return url_data_->url(); + return url_data()->url(); } void MultibufferDataSource::Read(int64_t position, @@ -509,7 +515,7 @@ if (read_op_) return; - url_data_->AddBytesRead(bytes_read_); + url_data()->AddBytesRead(bytes_read_); bytes_read_ = 0; if (reader_) { @@ -585,18 +591,18 @@ // All responses must be successful. Resources that are assumed to be fully // buffered must have a known content length. - bool success = reader_ && reader_->Available() > 0 && url_data_ && + bool success = reader_ && reader_->Available() > 0 && url_data() && (!assume_fully_buffered() || - url_data_->length() != kPositionNotSpecified); + url_data()->length() != kPositionNotSpecified); if (success) { { base::AutoLock auto_lock(lock_); - total_bytes_ = url_data_->length(); + total_bytes_ = url_data()->length(); } streaming_ = !assume_fully_buffered() && (total_bytes_ == kPositionNotSpecified || - !url_data_->range_supported()); + !url_data()->range_supported()); media_log_->SetDoubleProperty("total_bytes", static_cast<double>(total_bytes_)); @@ -624,7 +630,7 @@ media_log_->SetBooleanProperty("passed_cors_access_check", DidPassCORSAccessCheck()); media_log_->SetBooleanProperty("range_header_supported", - url_data_->range_supported()); + url_data()->range_supported()); } render_task_runner_->PostTask(FROM_HERE, @@ -728,7 +734,7 @@ // Increase buffering slowly at a rate of 10% of data downloaded so // far, maxing out at the preload size. int64_t extra_buffer = std::min( - preload, url_data_->BytesReadFromCache() * kSlowPreloadPercentage / 100); + preload, url_data()->BytesReadFromCache() * kSlowPreloadPercentage / 100); // Add extra buffer to preload. preload += extra_buffer; @@ -756,14 +762,14 @@ extra_buffer * 3, preload_high + pin_backward + extra_buffer); - if (url_data_->FullyCached() || - (url_data_->length() != kPositionNotSpecified && - url_data_->length() < kDefaultPinSize)) { + if (url_data()->FullyCached() || + (url_data()->length() != kPositionNotSpecified && + url_data()->length() < kDefaultPinSize)) { // We just make pin_forwards/backwards big enough to encompass the // whole file regardless of where we are, with some extra margins. - pin_forward = std::max(pin_forward, url_data_->length() * 2); - pin_backward = std::max(pin_backward, url_data_->length() * 2); - buffer_size = url_data_->length(); + pin_forward = std::max(pin_forward, url_data()->length() * 2); + pin_backward = std::max(pin_backward, url_data()->length() * 2); + buffer_size = url_data()->length(); } reader_->SetMaxBuffer(buffer_size);
diff --git a/media/blink/multibuffer_data_source.h b/media/blink/multibuffer_data_source.h index 43d1140c..19d61eb 100644 --- a/media/blink/multibuffer_data_source.h +++ b/media/blink/multibuffer_data_source.h
@@ -123,6 +123,8 @@ } protected: + UrlData* url_data() const { return url_data_and_loading_state_.url_data(); } + void OnRedirect(const scoped_refptr<UrlData>& destination); // A factory method to create a BufferedResourceLoader based on the read @@ -211,7 +213,7 @@ const scoped_refptr<base::SingleThreadTaskRunner> render_task_runner_; // URL of the resource requested. - scoped_refptr<UrlData> url_data_; + UrlData::UrlDataWithLoadingState url_data_and_loading_state_; // A resource reader for the media resource. std::unique_ptr<MultiBufferReader> reader_;
diff --git a/media/blink/multibuffer_data_source_unittest.cc b/media/blink/multibuffer_data_source_unittest.cc index 89793c79..284a75df 100644 --- a/media/blink/multibuffer_data_source_unittest.cc +++ b/media/blink/multibuffer_data_source_unittest.cc
@@ -9,7 +9,9 @@ #include "base/macros.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" +#include "base/test/scoped_feature_list.h" #include "media/base/media_log.h" +#include "media/base/media_switches.h" #include "media/base/mock_filters.h" #include "media/base/test_helpers.h" #include "media/blink/buffered_data_source_host_impl.h" @@ -153,6 +155,8 @@ return last_url_data_; } + size_t load_queue_size() { return loading_queue_.size(); } + private: scoped_refptr<TestUrlData> last_url_data_; }; @@ -186,7 +190,7 @@ bool downloading() { return downloading_; } void set_downloading(bool downloading) { downloading_ = downloading; } - bool range_supported() { return url_data_->range_supported(); } + bool range_supported() { return url_data()->range_supported(); } void CallSeekTask() { SeekTask(); } private: @@ -442,7 +446,7 @@ } double data_source_playback_rate() { return data_source_->playback_rate_; } bool is_local_source() { return data_source_->assume_fully_buffered(); } - scoped_refptr<UrlData> url_data() { return data_source_->url_data_; } + scoped_refptr<UrlData> url_data() { return data_source_->url_data(); } void set_might_be_reused_from_cache_in_future(bool value) { url_data()->set_cacheable(value); } @@ -1747,4 +1751,43 @@ Stop(); } +TEST_F(MultibufferDataSourceTest, LoadLimitTest) { + base::test::ScopedFeatureList feature_list; + feature_list.InitFromCommandLine(kLimitParallelMediaPreloading.name, ""); + + StrictMock<MockBufferedDataSourceHost> hosts[7]; + std::vector<std::unique_ptr<MockMultibufferDataSource>> sources; + for (size_t i = 0; i < base::size(hosts); i++) { + sources.push_back(std::make_unique<MockMultibufferDataSource>( + base::ThreadTaskRunnerHandle::Get(), + url_index_->GetByUrl( + GURL(std::string(kHttpUrl) + "?" + base::IntToString(i)), + UrlData::CORS_UNSPECIFIED), + &hosts[i])); + sources[i]->SetPreload(preload_); + sources[i]->Initialize(base::Bind(&MultibufferDataSourceTest::OnInitialize, + base::Unretained(this))); + } + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1UL, url_index_->load_queue_size()); +} + +TEST_F(MultibufferDataSourceTest, LoadLimitTestNoLimit) { + StrictMock<MockBufferedDataSourceHost> hosts[7]; + std::vector<std::unique_ptr<MockMultibufferDataSource>> sources; + for (size_t i = 0; i < base::size(hosts); i++) { + sources.push_back(std::make_unique<MockMultibufferDataSource>( + base::ThreadTaskRunnerHandle::Get(), + url_index_->GetByUrl( + GURL(std::string(kHttpUrl) + "?" + base::IntToString(i)), + UrlData::CORS_UNSPECIFIED), + &hosts[i])); + sources[i]->SetPreload(preload_); + sources[i]->Initialize(base::Bind(&MultibufferDataSourceTest::OnInitialize, + base::Unretained(this))); + } + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(0UL, url_index_->load_queue_size()); +} + } // namespace media
diff --git a/media/blink/new_session_cdm_result_promise.cc b/media/blink/new_session_cdm_result_promise.cc index a6ab3f6..e8c2300 100644 --- a/media/blink/new_session_cdm_result_promise.cc +++ b/media/blink/new_session_cdm_result_promise.cc
@@ -68,6 +68,8 @@ } void NewSessionCdmResultPromise::resolve(const std::string& session_id) { + DVLOG(1) << __func__ << ": session_id = " << session_id; + // |new_session_created_cb_| uses a WeakPtr<> and may not do anything // if the session object has been destroyed. SessionInitStatus status = SessionInitStatus::UNKNOWN_STATUS; @@ -93,6 +95,9 @@ void NewSessionCdmResultPromise::reject(CdmPromise::Exception exception_code, uint32_t system_code, const std::string& error_message) { + DVLOG(1) << __func__ << ": system_code = " << system_code + << ", error_message = " << error_message; + MarkPromiseSettled(); ReportCdmResultUMA(uma_name_, ConvertCdmExceptionToResultForUMA(exception_code));
diff --git a/media/blink/resource_multibuffer_data_provider.cc b/media/blink/resource_multibuffer_data_provider.cc index 221fca59..cfb35c21 100644 --- a/media/blink/resource_multibuffer_data_provider.cc +++ b/media/blink/resource_multibuffer_data_provider.cc
@@ -80,11 +80,11 @@ } // Prepare the request. - WebURLRequest request(url_data_->url()); - request.SetRequestContext(is_client_audio_element_ - ? WebURLRequest::kRequestContextAudio - : WebURLRequest::kRequestContextVideo); - request.SetHTTPHeaderField( + auto request = std::make_unique<WebURLRequest>(url_data_->url()); + request->SetRequestContext(is_client_audio_element_ + ? WebURLRequest::kRequestContextAudio + : WebURLRequest::kRequestContextVideo); + request->SetHTTPHeaderField( WebString::FromUTF8(net::HttpRequestHeaders::kRange), WebString::FromUTF8( net::HttpByteRange::RightUnbounded(byte_pos()).GetHeaderValue())); @@ -94,8 +94,8 @@ // This lets the data reduction proxy know that we don't have anything // previously cached data for this resource. We can only send it if this is // the first request for this resource. - request.SetHTTPHeaderField(WebString::FromUTF8("chrome-proxy"), - WebString::FromUTF8("frfr")); + request->SetHTTPHeaderField(WebString::FromUTF8("chrome-proxy"), + WebString::FromUTF8("frfr")); } // We would like to send an if-match header with the request to @@ -105,7 +105,7 @@ // along the way. See crbug/504194 and crbug/689989 for more information. // Disable compression, compression for audio/video doesn't make sense... - request.SetHTTPHeaderField( + request->SetHTTPHeaderField( WebString::FromUTF8(net::HttpRequestHeaders::kAcceptEncoding), WebString::FromUTF8("identity;q=1, *;q=0")); @@ -117,15 +117,24 @@ options.preflight_policy = network::mojom::CORSPreflightPolicy::kPreventPreflight; - request.SetFetchRequestMode(network::mojom::FetchRequestMode::kCORS); + request->SetFetchRequestMode(network::mojom::FetchRequestMode::kCORS); if (url_data_->cors_mode() != UrlData::CORS_USE_CREDENTIALS) { - request.SetFetchCredentialsMode( + request->SetFetchCredentialsMode( network::mojom::FetchCredentialsMode::kSameOrigin); } } + active_loader_ = url_data_->url_index()->fetch_context()->CreateUrlLoader(options); - active_loader_->LoadAsynchronously(request, this); + + url_data_->WaitToLoad( + base::BindOnce(&ResourceMultiBufferDataProvider::StartLoading, + weak_factory_.GetWeakPtr(), std::move(request))); +} + +void ResourceMultiBufferDataProvider::StartLoading( + std::unique_ptr<WebURLRequest> request) { + active_loader_->LoadAsynchronously(*request, this); } /////////////////////////////////////////////////////////////////////////////
diff --git a/media/blink/resource_multibuffer_data_provider.h b/media/blink/resource_multibuffer_data_provider.h index 1260e70..68f360a 100644 --- a/media/blink/resource_multibuffer_data_provider.h +++ b/media/blink/resource_multibuffer_data_provider.h
@@ -70,6 +70,10 @@ // Callback used when we're asked to fetch data after the end of the file. void Terminate(); + // At the end of Start(), we potentially wait for other loaders to + // finish, when they do a callback calls this function. + void StartLoading(std::unique_ptr<blink::WebURLRequest> request); + // Parse a Content-Range header into its component pieces and return true if // each of the expected elements was found & parsed correctly. // |*instance_size| may be set to kPositionNotSpecified if the range ends in
diff --git a/media/blink/url_index.cc b/media/blink/url_index.cc index be61b169..6968b19cd 100644 --- a/media/blink/url_index.cc +++ b/media/blink/url_index.cc
@@ -8,11 +8,13 @@ #include <utility> #include "base/bind.h" +#include "base/feature_list.h" #include "base/location.h" #include "base/metrics/histogram_macros.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" +#include "media/base/media_switches.h" #include "media/blink/resource_multibuffer_data_provider.h" namespace media { @@ -20,6 +22,18 @@ const int kBlockSizeShift = 15; // 1<<15 == 32kb const int kUrlMappingTimeoutSeconds = 300; +// Max number of resource preloading in parallel. +const size_t kMaxParallelPreload = 6; + +namespace { +// Helper function, return max parallel preloads. +size_t GetMaxParallelPreload() { + if (base::FeatureList::IsEnabled(media::kLimitParallelMediaPreloading)) + return kMaxParallelPreload; + return std::numeric_limits<size_t>::max(); +} +}; // namespace + ResourceMultiBuffer::ResourceMultiBuffer(UrlData* url_data, int block_shift) : MultiBuffer(block_shift, url_data->url_index_->lru_), url_data_(url_data) {} @@ -60,6 +74,8 @@ BytesReadFromCache() >> 10); UMA_HISTOGRAM_MEMORY_KB("Media.BytesReadFromNetwork", BytesReadFromNetwork() >> 10); + DCHECK_EQ(0, playing_); + DCHECK_EQ(0, preloading_); } std::pair<GURL, UrlData::CORSMode> UrlData::key() const { @@ -210,6 +226,124 @@ return multibuffer()->map().size(); } +UrlData::UrlDataWithLoadingState::UrlDataWithLoadingState() {} +UrlData::UrlDataWithLoadingState::~UrlDataWithLoadingState() { + SetLoadingState(LoadingState::kIdle); +} + +void UrlData::UrlDataWithLoadingState::SetLoadingState( + LoadingState loading_state) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!url_data_) + return; + // Note that we increase loading state first and decrease afterwards to avoid + // having the loading/playing counts go to zero temporarily. + url_data_->IncreaseLoadersInState(loading_state); + url_data_->DecreaseLoadersInState(loading_state_); + loading_state_ = loading_state; +} + +void UrlData::UrlDataWithLoadingState::SetUrlData( + scoped_refptr<UrlData> url_data) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // Note that we increase loading state first and decrease afterwards to avoid + // having the loading/playing counts go to zero temporarily. + if (url_data) + url_data->IncreaseLoadersInState(loading_state_); + if (url_data_) + url_data_->DecreaseLoadersInState(loading_state_); + url_data_ = std::move(url_data); +} + +bool UrlData::IsPreloading() const { + return preloading_ > 0 && playing_ == 0; +} + +void UrlData::IncreaseLoadersInState( + UrlDataWithLoadingState::LoadingState state) { + switch (state) { + case UrlDataWithLoadingState::LoadingState::kIdle: + break; + case UrlDataWithLoadingState::LoadingState::kPreload: + preloading_++; + break; + case UrlDataWithLoadingState::LoadingState::kHasPlayed: + playing_++; + if (playing_ == 1) + url_index_->RemoveLoading(this); + break; + } +} + +void UrlData::DecreaseLoadersInState( + UrlDataWithLoadingState::LoadingState state) { + switch (state) { + case UrlDataWithLoadingState::LoadingState::kIdle: + return; + case UrlDataWithLoadingState::LoadingState::kPreload: + preloading_--; + DCHECK_GE(preloading_, 0); + break; + case UrlDataWithLoadingState::LoadingState::kHasPlayed: + playing_--; + DCHECK_GE(playing_, 0); + break; + } + if (preloading_ == 0 && playing_ == 0) + url_index_->RemoveLoading(this); +} + +void UrlData::WaitToLoad(base::OnceClosure cb) { + // We only limit and queue preloading requests. + if (!IsPreloading()) { + std::move(cb).Run(); + } else { + waiting_load_callbacks_.emplace_back(std::move(cb)); + if (waiting_load_callbacks_.size() == 1) + url_index_->WaitToLoad(this); + } +} + +void UrlData::LoadNow() { + // Move the callbacks into local variables in case + // any of the callbacks decide to call WaitToLoad(). + std::vector<base::OnceClosure> waiting_load_callbacks; + std::swap(waiting_load_callbacks, waiting_load_callbacks_); + for (auto& i : waiting_load_callbacks) + std::move(i).Run(); +} + + +void UrlIndex::WaitToLoad(UrlData* url_data) { + if (loading_.find(url_data) != loading_.end()) { + // Already loading + url_data->LoadNow(); + return; + } + if (loading_.size() < GetMaxParallelPreload()) { + loading_.insert(url_data); + url_data->LoadNow(); + return; + } + loading_queue_.push_back(url_data); +} + +void UrlIndex::RemoveLoading(UrlData* url_data) { + auto i = loading_.find(url_data); + if (i == loading_.end()) + return; + loading_.erase(i); + while (loading_.size() < GetMaxParallelPreload() && !loading_queue_.empty()) { + auto url_data = loading_queue_.front(); + loading_queue_.pop_front(); + if (url_data->IsPreloading()) { + WaitToLoad(url_data.get()); + } else { + url_data->LoadNow(); + } + } +} + UrlIndex::UrlIndex(ResourceFetchContext* fetch_context) : UrlIndex(fetch_context, kBlockSizeShift) {} @@ -236,6 +370,8 @@ auto i = indexed_data_.find(url_data->key()); if (i != indexed_data_.end() && i->second == url_data) indexed_data_.erase(i); + + RemoveLoading(url_data.get()); } scoped_refptr<UrlData> UrlIndex::GetByUrl(const GURL& gurl,
diff --git a/media/blink/url_index.h b/media/blink/url_index.h index 2ebaad1..77ea0e4d 100644 --- a/media/blink/url_index.h +++ b/media/blink/url_index.h
@@ -28,6 +28,7 @@ class ResourceFetchContext; class UrlData; +class UrlIndexTest; // A multibuffer for loading media resources which knows // how to create MultiBufferDataProviders to load data @@ -60,6 +61,31 @@ enum CORSMode { CORS_UNSPECIFIED, CORS_ANONYMOUS, CORS_USE_CREDENTIALS }; typedef std::pair<GURL, CORSMode> KeyType; + // UrlData keeps track of how many clients are preloading or + // playing from this resource. This class encapsulates the + // adding and removing of counts to guarantee that the counts + // are accurate. Clients who wish to change the loading + // counts need to have one of these, assign an UrlData to it + // and call SetLoadingState() to releflect what the client is + // currently doing. + class MEDIA_BLINK_EXPORT UrlDataWithLoadingState { + public: + UrlDataWithLoadingState(); + ~UrlDataWithLoadingState(); + + enum class LoadingState { kIdle, kPreload, kHasPlayed }; + + void SetLoadingState(LoadingState loading_state); + void SetUrlData(scoped_refptr<UrlData> url_data); + UrlData* url_data() const { return url_data_.get(); } + + private: + LoadingState loading_state_ = LoadingState::kIdle; + scoped_refptr<UrlData> url_data_; + SEQUENCE_CHECKER(sequence_checker_); + DISALLOW_COPY_AND_ASSIGN(UrlDataWithLoadingState); + }; + // Accessors const GURL& url() const { return url_; } @@ -149,6 +175,10 @@ void AddBytesReadFromNetwork(int64_t b) { bytes_read_from_network_ += b; } int64_t BytesReadFromNetwork() const { return bytes_read_from_network_; } + // Call |cb| when it's ok to start preloading an URL. + // Note that |cb| may be called directly from inside this function. + void WaitToLoad(base::OnceClosure cb); + protected: UrlData(const GURL& url, CORSMode cors_mode, UrlIndex* url_index); virtual ~UrlData(); @@ -156,11 +186,28 @@ private: friend class ResourceMultiBuffer; friend class UrlIndex; + friend class UrlIndexTest; friend class base::RefCounted<UrlData>; + // Returns true if one or more clients are prelaoding and no clients + // are currently playing. + bool IsPreloading() const; + + // Called by url_index when it's time to fire callbacks sent to WaitToLoad(). + void LoadNow(); + void OnEmpty(); void MergeFrom(const scoped_refptr<UrlData>& other); + // These two are called from UrlDataWithLoadingState to + // increase and decrease |playing_| and |preloading_|. + // They will also call the UrlIndex and and tell it to + // de-queue other resources waiting to load as needed. + void IncreaseLoadersInState( + UrlDataWithLoadingState::LoadingState loading_state); + void DecreaseLoadersInState( + UrlDataWithLoadingState::LoadingState loading_state); + // Url we represent, note that there may be multiple UrlData for // the same url. const GURL url_; @@ -215,6 +262,14 @@ ResourceMultiBuffer multibuffer_; std::vector<RedirectCB> redirect_callbacks_; + // Number of data sources that are currently preloading this url. + int preloading_ = 0; + + // Number of data sources that are playing this url. + int playing_ = 0; + + std::vector<base::OnceClosure> waiting_load_callbacks_; + base::ThreadChecker thread_checker_; DISALLOW_COPY_AND_ASSIGN(UrlData); }; @@ -256,11 +311,21 @@ ResourceFetchContext* fetch_context() const { return fetch_context_; } int block_shift() const { return block_shift_; } - private: + // Protected rather than private for testing. + protected: friend class UrlData; friend class ResourceMultiBuffer; + friend class UrlIndexTest; void RemoveUrlData(const scoped_refptr<UrlData>& url_data); + // Call url_data->LoadNow() when it's ok to start preloading. + // Note that LoadNow may be called immediately. + void WaitToLoad(UrlData* url_data); + + // Let us know that |url_data| is done preloading. If other resources + // are waiting, we will let one of them know it's ok to load now. + void RemoveLoading(UrlData* url_data); + // Virtual so we can override it in tests. virtual scoped_refptr<UrlData> NewUrlData(const GURL& url, UrlData::CORSMode cors_mode); @@ -277,6 +342,9 @@ // Currently only changed for testing purposes. const int block_shift_; + std::set<UrlData*> loading_; + std::deque<scoped_refptr<UrlData>> loading_queue_; + base::MemoryPressureListener memory_pressure_listener_; };
diff --git a/media/blink/url_index_unittest.cc b/media/blink/url_index_unittest.cc index 9a309cb..cf84153 100644 --- a/media/blink/url_index_unittest.cc +++ b/media/blink/url_index_unittest.cc
@@ -8,7 +8,10 @@ #include <string> #include "base/logging.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" +#include "base/test/scoped_feature_list.h" +#include "media/base/media_switches.h" #include "media/blink/url_index.h" #include "testing/gtest/include/gtest/gtest.h" @@ -26,6 +29,15 @@ return ret; } + void AddToLoadQueue(UrlData* url_data, base::OnceClosure cb) { + url_data->waiting_load_callbacks_.emplace_back(std::move(cb)); + url_index_.loading_queue_.push_back(url_data); + } + + void AddToLoading(UrlData* url_data) { + url_index_.loading_.insert(url_data); + } + UrlIndex url_index_; }; @@ -153,4 +165,27 @@ EXPECT_EQ(b, GetByUrl(url, UrlData::CORS_UNSPECIFIED)); } +namespace { +void SetBoolWhenCalled(bool* b) { + *b = true; +} +}; // namespace + +TEST_F(UrlIndexTest, SetLoadingState) { + bool called = false; + GURL url_a("http://foo.bar.com"); + scoped_refptr<UrlData> a = GetByUrl(url_a, UrlData::CORS_UNSPECIFIED); + AddToLoadQueue(a.get(), base::BindOnce(&SetBoolWhenCalled, &called)); + UrlData::UrlDataWithLoadingState url_data_with_loading_state; + url_data_with_loading_state.SetUrlData(a); + EXPECT_FALSE(called); + url_data_with_loading_state.SetLoadingState( + UrlData::UrlDataWithLoadingState::LoadingState::kPreload); + AddToLoading(a.get()); + EXPECT_FALSE(called); + url_data_with_loading_state.SetLoadingState( + UrlData::UrlDataWithLoadingState::LoadingState::kHasPlayed); + EXPECT_TRUE(called); +} + } // namespace media
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc index 02c4981..61c3e4b 100644 --- a/media/cdm/cdm_adapter.cc +++ b/media/cdm/cdm_adapter.cc
@@ -659,6 +659,7 @@ void CdmAdapter::SetServerCertificate( const std::vector<uint8_t>& certificate, std::unique_ptr<SimpleCdmPromise> promise) { + DVLOG(2) << __func__; DCHECK(task_runner_->BelongsToCurrentThread()); if (certificate.size() < limits::kMinCertificateLength || @@ -677,9 +678,12 @@ HdcpVersion min_hdcp_version, std::unique_ptr<KeyStatusCdmPromise> promise) { DCHECK(task_runner_->BelongsToCurrentThread()); + uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); + DVLOG(2) << __func__ << ": promise_id = " << promise_id; if (!cdm_->GetStatusForPolicy(promise_id, ToCdmHdcpVersion(min_hdcp_version))) { + DVLOG(1) << __func__ << ": GetStatusForPolicy not supported"; cdm_promise_adapter_.RejectPromise( promise_id, CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0, "GetStatusForPolicy not supported."); @@ -694,6 +698,8 @@ DCHECK(task_runner_->BelongsToCurrentThread()); uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); + DVLOG(2) << __func__ << ": promise_id = " << promise_id; + cdm_->CreateSessionAndGenerateRequest( promise_id, ToCdmSessionType(session_type), ToCdmInitDataType(init_data_type), init_data.data(), init_data.size()); @@ -705,6 +711,9 @@ DCHECK(task_runner_->BelongsToCurrentThread()); uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); + DVLOG(2) << __func__ << ": session_id = " << session_id + << ", promise_id = " << promise_id; + cdm_->LoadSession(promise_id, ToCdmSessionType(session_type), session_id.data(), session_id.size()); } @@ -717,6 +726,9 @@ DCHECK(!response.empty()); uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); + DVLOG(2) << __func__ << ": session_id = " << session_id + << ", promise_id = " << promise_id; + cdm_->UpdateSession(promise_id, session_id.data(), session_id.size(), response.data(), response.size()); } @@ -727,6 +739,9 @@ DCHECK(!session_id.empty()); uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); + DVLOG(2) << __func__ << ": session_id = " << session_id + << ", promise_id = " << promise_id; + cdm_->CloseSession(promise_id, session_id.data(), session_id.size()); } @@ -736,6 +751,9 @@ DCHECK(!session_id.empty()); uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise)); + DVLOG(2) << __func__ << ": session_id = " << session_id + << ", promise_id = " << promise_id; + cdm_->RemoveSession(promise_id, session_id.data(), session_id.size()); } @@ -758,19 +776,24 @@ // TODO(xhwang): Fix External Clear Key key system to be able to set // |use_hw_secure_codecs| so that we don't have to check both. // TODO(xhwang): Update this logic to support transcryption. - if (cdm_config_.use_hw_secure_codecs || cdm_proxy_created_) + if (cdm_config_.use_hw_secure_codecs || cdm_proxy_created_) { + DVLOG(2) << __func__ << ": GetDecryptor() returns null"; return nullptr; + } return this; } int CdmAdapter::GetCdmId() const { DCHECK(task_runner_->BelongsToCurrentThread()); - return helper_->GetCdmProxyCdmId(); + int cdm_id = helper_->GetCdmProxyCdmId(); + DVLOG(2) << __func__ << ": cdm_id = " << cdm_id; + return cdm_id; } void CdmAdapter::RegisterNewKeyCB(StreamType stream_type, const NewKeyCB& key_added_cb) { + DVLOG(3) << __func__; DCHECK(task_runner_->BelongsToCurrentThread()); switch (stream_type) { case kAudio: @@ -821,6 +844,7 @@ void CdmAdapter::InitializeAudioDecoder(const AudioDecoderConfig& config, const DecoderInitCB& init_cb) { + DVLOG(2) << __func__ << ": " << config.AsHumanReadableString(); DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(!audio_init_cb_); @@ -847,6 +871,7 @@ void CdmAdapter::InitializeVideoDecoder(const VideoDecoderConfig& config, const DecoderInitCB& init_cb) { + DVLOG(2) << __func__ << ": " << config.AsHumanReadableString(); DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(!video_init_cb_); @@ -940,7 +965,9 @@ } void CdmAdapter::ResetDecoder(StreamType stream_type) { + DVLOG(2) << __func__ << ": stream_type = " << stream_type; DCHECK(task_runner_->BelongsToCurrentThread()); + cdm_->ResetDecoder(ToCdmStreamType(stream_type)); } @@ -985,12 +1012,15 @@ void CdmAdapter::OnResolveKeyStatusPromise(uint32_t promise_id, cdm::KeyStatus key_status) { + DVLOG(2) << __func__ << ": promise_id = " << promise_id + << ", key_status = " << key_status; DCHECK(task_runner_->BelongsToCurrentThread()); cdm_promise_adapter_.ResolvePromise(promise_id, ToCdmKeyInformationKeyStatus(key_status)); } void CdmAdapter::OnResolvePromise(uint32_t promise_id) { + DVLOG(2) << __func__ << ": promise_id = " << promise_id; DCHECK(task_runner_->BelongsToCurrentThread()); cdm_promise_adapter_.ResolvePromise(promise_id); } @@ -998,6 +1028,7 @@ void CdmAdapter::OnResolveNewSessionPromise(uint32_t promise_id, const char* session_id, uint32_t session_id_size) { + DVLOG(2) << __func__ << ": promise_id = " << promise_id; DCHECK(task_runner_->BelongsToCurrentThread()); cdm_promise_adapter_.ResolvePromise(promise_id, std::string(session_id, session_id_size)); @@ -1008,6 +1039,11 @@ uint32_t system_code, const char* error_message, uint32_t error_message_size) { + std::string error_message_str(error_message, error_message_size); + DVLOG(2) << __func__ << ": promise_id = " << promise_id + << ", exception = " << exception << ", system_code = " << system_code + << ", error_message = " << error_message_str; + // This is the central place for library CDM promise rejection. Cannot report // this in more generic classes like CdmPromise or CdmPromiseAdapter because // they may be used multiple times in one promise chain that involves IPC. @@ -1021,9 +1057,9 @@ } DCHECK(task_runner_->BelongsToCurrentThread()); - cdm_promise_adapter_.RejectPromise( - promise_id, ToMediaExceptionType(exception), system_code, - std::string(error_message, error_message_size)); + cdm_promise_adapter_.RejectPromise(promise_id, + ToMediaExceptionType(exception), + system_code, error_message_str); } void CdmAdapter::OnSessionMessage(const char* session_id, @@ -1031,11 +1067,13 @@ cdm::MessageType message_type, const char* message, uint32_t message_size) { + std::string session_id_str(session_id, session_id_size); + DVLOG(2) << __func__ << ": session_id = " << session_id_str; DCHECK(task_runner_->BelongsToCurrentThread()); + const uint8_t* message_ptr = reinterpret_cast<const uint8_t*>(message); session_message_cb_.Run( - std::string(session_id, session_id_size), - ToMediaMessageType(message_type), + session_id_str, ToMediaMessageType(message_type), std::vector<uint8_t>(message_ptr, message_ptr + message_size)); } @@ -1044,6 +1082,8 @@ bool has_additional_usable_key, const cdm::KeyInformation* keys_info, uint32_t keys_info_count) { + std::string session_id_str(session_id, session_id_size); + DVLOG(2) << __func__ << ": session_id = " << session_id_str; DCHECK(task_runner_->BelongsToCurrentThread()); CdmKeysInfo keys; @@ -1064,16 +1104,19 @@ new_video_key_cb_.Run(); } - session_keys_change_cb_.Run(std::string(session_id, session_id_size), - has_additional_usable_key, std::move(keys)); + session_keys_change_cb_.Run(session_id_str, has_additional_usable_key, + std::move(keys)); } void CdmAdapter::OnExpirationChange(const char* session_id, uint32_t session_id_size, cdm::Time new_expiry_time) { + std::string session_id_str(session_id, session_id_size); + DVLOG(2) << __func__ << ": session_id = " << session_id_str + << ", new_expiry_time = " << new_expiry_time; DCHECK(task_runner_->BelongsToCurrentThread()); - session_expiration_update_cb_.Run(std::string(session_id, session_id_size), + session_expiration_update_cb_.Run(session_id_str, base::Time::FromDoubleT(new_expiry_time)); } @@ -1247,6 +1290,9 @@ } void CdmAdapter::RequestStorageId(uint32_t version) { + DVLOG(2) << __func__ << ": version = " << version; + DCHECK(task_runner_->BelongsToCurrentThread()); + if (!cdm_config_.allow_persistent_state || !(version == kCurrentStorageIdVersion || version == kRequestLatestStorageIdVersion)) {
diff --git a/mojo/core/ports/message_queue.cc b/mojo/core/ports/message_queue.cc index 074b35a..0abb713 100644 --- a/mojo/core/ports/message_queue.cc +++ b/mojo/core/ports/message_queue.cc
@@ -6,6 +6,7 @@ #include <algorithm> +#include "base/compiler_specific.h" #include "base/logging.h" #include "mojo/core/ports/message_filter.h" @@ -53,6 +54,16 @@ total_queued_bytes_ -= (*message)->GetSizeIfSerialized(); heap_.pop_back(); + // We keep the capacity of |heap_| in check so that a large batch of incoming + // messages doesn't permanently wreck available memory. The choice of interval + // here is somewhat arbitrary. + constexpr size_t kHeapMinimumShrinkSize = 16; + constexpr size_t kHeapShrinkInterval = 512; + if (UNLIKELY(heap_.size() > kHeapMinimumShrinkSize && + heap_.size() % kHeapShrinkInterval == 0)) { + heap_.shrink_to_fit(); + } + next_sequence_num_++; }
diff --git a/pdf/BUILD.gn b/pdf/BUILD.gn index ee973f4..044f882 100644 --- a/pdf/BUILD.gn +++ b/pdf/BUILD.gn
@@ -110,7 +110,18 @@ } } + source_set("pdf_test_utils") { + testonly = true + sources = [ + "test/test_client.cc", + "test/test_client.h", + "test/test_document_loader.cc", + "test/test_document_loader.h", + ] + } + test("pdf_unittests") { + testonly = true sources = [ "chunk_stream_unittest.cc", "document_loader_impl_unittest.cc", @@ -121,6 +132,7 @@ deps = [ ":pdf", + ":pdf_test_utils", "//base", "//base/test:test_support", "//ppapi/c", @@ -139,6 +151,9 @@ sources += [ "pdfium/findtext_unittest.cc", "pdfium/pdfium_engine_exports_unittest.cc", + "pdfium/pdfium_print_unittest.cc", + "pdfium/pdfium_test_base.cc", + "pdfium/pdfium_test_base.h", ] include_dirs = [ "//third_party/pdfium" ]
diff --git a/pdf/pdfium/findtext_unittest.cc b/pdf/pdfium/findtext_unittest.cc index 068c62a..af3e34ea 100644 --- a/pdf/pdfium/findtext_unittest.cc +++ b/pdf/pdfium/findtext_unittest.cc
@@ -2,14 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/files/file_util.h" #include "base/optional.h" -#include "base/path_service.h" -#include "pdf/document_loader.h" #include "pdf/pdfium/pdfium_engine.h" -#include "pdf/url_loader_wrapper.h" +#include "pdf/pdfium/pdfium_test_base.h" +#include "pdf/test/test_client.h" #include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" using testing::InSequence; using testing::_; @@ -18,82 +15,15 @@ namespace { -class TestDocumentLoader : public DocumentLoader { +class FindTextTestClient : public TestClient { public: - TestDocumentLoader(Client* client, const base::FilePath::StringType& pdf_name) - : client_(client) { - base::FilePath pdf_path; - CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &pdf_path)); - pdf_path = pdf_path.Append(FILE_PATH_LITERAL("pdf")) - .Append(FILE_PATH_LITERAL("test")) - .Append(FILE_PATH_LITERAL("data")) - .Append(pdf_name); - CHECK(base::ReadFileToString(pdf_path, &pdf_data_)); - } - ~TestDocumentLoader() override = default; - - // DocumentLoader: - bool Init(std::unique_ptr<URLLoaderWrapper> loader, - const std::string& url) override { - NOTREACHED(); - return false; - } - - bool GetBlock(uint32_t position, uint32_t size, void* buf) const override { - if (!IsDataAvailable(position, size)) - return false; - - memcpy(buf, pdf_data_.data() + position, size); - return true; - } - - bool IsDataAvailable(uint32_t position, uint32_t size) const override { - return position < pdf_data_.size() && size <= pdf_data_.size() && - position + size <= pdf_data_.size(); - } - - void RequestData(uint32_t position, uint32_t size) override { - client_->OnDocumentComplete(); - } - - bool IsDocumentComplete() const override { return true; } - - uint32_t GetDocumentSize() const override { return pdf_data_.size(); } - - uint32_t BytesReceived() const override { return pdf_data_.size(); } - - private: - Client* const client_; - std::string pdf_data_; -}; - -const base::FilePath::CharType* g_test_pdf_name; - -std::unique_ptr<DocumentLoader> CreateTestDocumentLoader( - DocumentLoader::Client* client) { - return std::make_unique<TestDocumentLoader>(client, g_test_pdf_name); -} - -class TestClient : public PDFEngine::Client { - public: - TestClient() = default; - ~TestClient() override = default; + FindTextTestClient() = default; + ~FindTextTestClient() override = default; // PDFEngine::Client: MOCK_METHOD2(NotifyNumberOfFindResultsChanged, void(int, bool)); MOCK_METHOD1(NotifySelectedFindResultChanged, void((int))); - bool Confirm(const std::string& message) override { return false; } - - std::string Prompt(const std::string& question, - const std::string& default_answer) override { - return std::string(); - } - - std::string GetURL() override { return std::string(); } - - pp::URLLoader CreateURLLoader() override { return pp::URLLoader(); } - std::vector<SearchStringResult> SearchString(const base::char16* string, const base::char16* term, bool case_sensitive) override { @@ -118,59 +48,18 @@ return results; } - pp::Instance* GetPluginInstance() override { return nullptr; } - - bool IsPrintPreview() override { return false; } - - uint32_t GetBackgroundColor() override { return 0; } - - float GetToolbarHeightInScreenCoords() override { return 0; } - private: - DISALLOW_COPY_AND_ASSIGN(TestClient); + DISALLOW_COPY_AND_ASSIGN(FindTextTestClient); }; } // namespace -class FindTextTest : public testing::Test { - public: - FindTextTest() = default; - ~FindTextTest() override = default; - - protected: - void SetUp() override { - InitializePDFium(); - } - - void TearDown() override { - PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(nullptr); - g_test_pdf_name = nullptr; - FPDF_DestroyLibrary(); - } - - void InitializePDFium() { - FPDF_LIBRARY_CONFIG config; - config.version = 2; - config.m_pUserFontPaths = nullptr; - config.m_pIsolate = nullptr; - config.m_v8EmbedderSlot = 0; - FPDF_InitLibraryWithConfig(&config); - } - - void SetDocumentForTest(const base::FilePath::CharType* test_pdf_name) { - g_test_pdf_name = test_pdf_name; - PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting( - &CreateTestDocumentLoader); - } - - private: - DISALLOW_COPY_AND_ASSIGN(FindTextTest); -}; +using FindTextTest = PDFiumTestBase; TEST_F(FindTextTest, FindText) { SetDocumentForTest(FILE_PATH_LITERAL("hello_world2.pdf")); pp::URLLoader dummy_loader; - TestClient client; + FindTextTestClient client; PDFiumEngine engine(&client, true); ASSERT_TRUE(engine.New("https://chromium.org/dummy.pdf", "")); ASSERT_TRUE(engine.HandleDocumentLoad(dummy_loader)); @@ -191,7 +80,7 @@ TEST_F(FindTextTest, FindHyphenatedText) { SetDocumentForTest(FILE_PATH_LITERAL("spanner.pdf")); pp::URLLoader dummy_loader; - TestClient client; + FindTextTestClient client; PDFiumEngine engine(&client, true); ASSERT_TRUE(engine.New("https://chromium.org/dummy.pdf", "")); ASSERT_TRUE(engine.HandleDocumentLoad(dummy_loader)); @@ -208,4 +97,5 @@ engine.StartFind("application", /*case_sensitive=*/true); } + } // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_print_unittest.cc b/pdf/pdfium/pdfium_print_unittest.cc new file mode 100644 index 0000000..2cb4372 --- /dev/null +++ b/pdf/pdfium/pdfium_print_unittest.cc
@@ -0,0 +1,33 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/pdfium/pdfium_print.h" + +#include "base/stl_util.h" +#include "ppapi/c/dev/ppp_printing_dev.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chrome_pdf { + +using testing::ElementsAre; + +TEST(PDFiumPrintTest, GetPageNumbersFromPrintPageNumberRange) { + std::vector<uint32_t> page_numbers; + + { + PP_PrintPageNumberRange_Dev page_ranges[] = {{0, 2}}; + page_numbers = PDFiumPrint::GetPageNumbersFromPrintPageNumberRange( + &page_ranges[0], base::size(page_ranges)); + EXPECT_THAT(page_numbers, ElementsAre(0, 1, 2)); + } + { + PP_PrintPageNumberRange_Dev page_ranges[] = {{0, 0}, {2, 2}, {4, 5}}; + page_numbers = PDFiumPrint::GetPageNumbersFromPrintPageNumberRange( + &page_ranges[0], base::size(page_ranges)); + EXPECT_THAT(page_numbers, ElementsAre(0, 2, 4, 5)); + } +} + +} // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_test_base.cc b/pdf/pdfium/pdfium_test_base.cc new file mode 100644 index 0000000..87f4706 --- /dev/null +++ b/pdf/pdfium/pdfium_test_base.cc
@@ -0,0 +1,56 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/pdfium/pdfium_test_base.h" + +#include <memory> + +#include "pdf/pdfium/pdfium_engine.h" +#include "pdf/test/test_document_loader.h" + +namespace chrome_pdf { + +namespace { + +const base::FilePath::CharType* g_test_pdf_name; + +std::unique_ptr<DocumentLoader> CreateTestDocumentLoader( + DocumentLoader::Client* client) { + return std::make_unique<TestDocumentLoader>(client, g_test_pdf_name); +} + +} // namespace + +PDFiumTestBase::PDFiumTestBase() = default; + +PDFiumTestBase::~PDFiumTestBase() = default; + +void PDFiumTestBase::SetUp() { + InitializePDFium(); +} + +void PDFiumTestBase::TearDown() { + PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(nullptr); + g_test_pdf_name = nullptr; + FPDF_DestroyLibrary(); +} + +void PDFiumTestBase::SetDocumentForTest( + const base::FilePath::CharType* pdf_name) { + DCHECK(!g_test_pdf_name); + g_test_pdf_name = pdf_name; + PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting( + &CreateTestDocumentLoader); +} + +void PDFiumTestBase::InitializePDFium() { + FPDF_LIBRARY_CONFIG config; + config.version = 2; + config.m_pUserFontPaths = nullptr; + config.m_pIsolate = nullptr; + config.m_v8EmbedderSlot = 0; + FPDF_InitLibraryWithConfig(&config); +} + +} // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_test_base.h b/pdf/pdfium/pdfium_test_base.h new file mode 100644 index 0000000..90a1447 --- /dev/null +++ b/pdf/pdfium/pdfium_test_base.h
@@ -0,0 +1,36 @@ +// 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 PDF_PDFIUM_PDFIUM_TEST_BASE_H_ +#define PDF_PDFIUM_PDFIUM_TEST_BASE_H_ + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace chrome_pdf { + +class PDFiumTestBase : public testing::Test { + public: + PDFiumTestBase(); + ~PDFiumTestBase() override; + + protected: + // testing::Test: + void SetUp() override; + void TearDown() override; + + // Sets the PDF to load for a test. This must be called for tests that use + // TestDocumentLoader. See TestDocumentLoader for more info. + void SetDocumentForTest(const base::FilePath::CharType* pdf_name); + + private: + void InitializePDFium(); + + DISALLOW_COPY_AND_ASSIGN(PDFiumTestBase); +}; + +} // namespace chrome_pdf + +#endif // PDF_PDFIUM_PDFIUM_TEST_BASE_H_
diff --git a/pdf/test/test_client.cc b/pdf/test/test_client.cc new file mode 100644 index 0000000..c3f7118 --- /dev/null +++ b/pdf/test/test_client.cc
@@ -0,0 +1,46 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/test/test_client.h" + +namespace chrome_pdf { + +TestClient::TestClient() = default; + +TestClient::~TestClient() = default; + +bool TestClient::Confirm(const std::string& message) { + return false; +} + +std::string TestClient::Prompt(const std::string& question, + const std::string& default_answer) { + return std::string(); +} + +std::string TestClient::GetURL() { + return std::string(); +} + +pp::URLLoader TestClient::CreateURLLoader() { + return pp::URLLoader(); +} + +pp::Instance* TestClient::GetPluginInstance() { + return nullptr; +} + +bool TestClient::IsPrintPreview() { + return false; +} + +uint32_t TestClient::GetBackgroundColor() { + return 0; +} + +float TestClient::GetToolbarHeightInScreenCoords() { + return 0; +} + +} // namespace chrome_pdf
diff --git a/pdf/test/test_client.h b/pdf/test/test_client.h new file mode 100644 index 0000000..0540879 --- /dev/null +++ b/pdf/test/test_client.h
@@ -0,0 +1,36 @@ +// 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 PDF_TEST_TEST_CLIENT_H_ +#define PDF_TEST_TEST_CLIENT_H_ + +#include <string> + +#include "pdf/pdf_engine.h" + +namespace chrome_pdf { + +class TestClient : public PDFEngine::Client { + public: + TestClient(); + ~TestClient() override; + + // PDFEngine::Client: + bool Confirm(const std::string& message) override; + std::string Prompt(const std::string& question, + const std::string& default_answer) override; + std::string GetURL() override; + pp::URLLoader CreateURLLoader() override; + pp::Instance* GetPluginInstance() override; + bool IsPrintPreview() override; + uint32_t GetBackgroundColor() override; + float GetToolbarHeightInScreenCoords() override; + + private: + DISALLOW_COPY_AND_ASSIGN(TestClient); +}; + +} // namespace chrome_pdf + +#endif // PDF_TEST_TEST_CLIENT_H_
diff --git a/pdf/test/test_document_loader.cc b/pdf/test/test_document_loader.cc new file mode 100644 index 0000000..6a7bc5c --- /dev/null +++ b/pdf/test/test_document_loader.cc
@@ -0,0 +1,68 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "pdf/test/test_document_loader.h" + +#include "base/base_paths.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "pdf/url_loader_wrapper.h" + +namespace chrome_pdf { + +TestDocumentLoader::TestDocumentLoader( + Client* client, + const base::FilePath::StringType& pdf_name) + : client_(client) { + base::FilePath pdf_path; + CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &pdf_path)); + pdf_path = pdf_path.Append(FILE_PATH_LITERAL("pdf")) + .Append(FILE_PATH_LITERAL("test")) + .Append(FILE_PATH_LITERAL("data")) + .Append(pdf_name); + CHECK(base::ReadFileToString(pdf_path, &pdf_data_)); +} + +TestDocumentLoader::~TestDocumentLoader() = default; + +bool TestDocumentLoader::Init(std::unique_ptr<URLLoaderWrapper> loader, + const std::string& url) { + NOTREACHED(); + return false; +} + +bool TestDocumentLoader::GetBlock(uint32_t position, + uint32_t size, + void* buf) const { + if (!IsDataAvailable(position, size)) + return false; + + memcpy(buf, pdf_data_.data() + position, size); + return true; +} + +bool TestDocumentLoader::IsDataAvailable(uint32_t position, + uint32_t size) const { + return position < pdf_data_.size() && size <= pdf_data_.size() && + position + size <= pdf_data_.size(); +} + +void TestDocumentLoader::RequestData(uint32_t position, uint32_t size) { + client_->OnDocumentComplete(); +} + +bool TestDocumentLoader::IsDocumentComplete() const { + return true; +} + +uint32_t TestDocumentLoader::GetDocumentSize() const { + return pdf_data_.size(); +} + +uint32_t TestDocumentLoader::BytesReceived() const { + return pdf_data_.size(); +} + +} // namespace chrome_pdf
diff --git a/pdf/test/test_document_loader.h b/pdf/test/test_document_loader.h new file mode 100644 index 0000000..4068c9da --- /dev/null +++ b/pdf/test/test_document_loader.h
@@ -0,0 +1,41 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PDF_TEST_TEST_DOCUMENT_LOADER_H_ +#define PDF_TEST_TEST_DOCUMENT_LOADER_H_ + +#include <memory> +#include <string> + +#include "base/files/file_path.h" +#include "pdf/document_loader.h" + +namespace chrome_pdf { + +// Loads test PDFs from pdf/test/data. +class TestDocumentLoader : public DocumentLoader { + public: + // |pdf_name| is the base name for a PDF file. + TestDocumentLoader(Client* client, + const base::FilePath::StringType& pdf_name); + ~TestDocumentLoader() override; + + // DocumentLoader: + bool Init(std::unique_ptr<URLLoaderWrapper> loader, + const std::string& url) override; + bool GetBlock(uint32_t position, uint32_t size, void* buf) const override; + bool IsDataAvailable(uint32_t position, uint32_t size) const override; + void RequestData(uint32_t position, uint32_t size) override; + bool IsDocumentComplete() const override; + uint32_t GetDocumentSize() const override; + uint32_t BytesReceived() const override; + + private: + Client* const client_; + std::string pdf_data_; +}; + +} // namespace chrome_pdf + +#endif // PDF_TEST_TEST_DOCUMENT_LOADER_H_
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc index f609019..1594e7e 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc
@@ -868,14 +868,14 @@ // since the concern is the effect that entering suspend mode has on // sockets. See https://crbug.com/651120. if (pending_write_) - CompletePendingWrite(); + CompletePendingWrite(url_request_->status().is_success()); NotifyCompleted(url_request_->status().ToNetError()); // |this| will have been deleted. return; } if (complete_read) { - CompletePendingWrite(); + CompletePendingWrite(true /* success */); } if (completed_synchronously) { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -1012,9 +1012,18 @@ response_ = nullptr; } -void URLLoader::CompletePendingWrite() { - response_body_stream_ = - pending_write_->Complete(pending_write_buffer_offset_); +void URLLoader::CompletePendingWrite(bool success) { + if (success) { + // The write can only be completed immediately in case of a success, since + // doing so invalidates memory of any attached NetToMojoIOBuffer's; but in + // case of an abort, particularly one caused by a suspend, the failure may + // be delivered to URLLoader while the disk_cache layer is still hanging on + // to the now-invalid IOBuffer in some worker thread trying to commit it to + // disk. In case of an error, this will have to wait till everything is + // destroyed. + response_body_stream_ = + pending_write_->Complete(pending_write_buffer_offset_); + } total_written_bytes_ += pending_write_buffer_offset_; pending_write_ = nullptr; pending_write_buffer_offset_ = 0;
diff --git a/services/network/url_loader.h b/services/network/url_loader.h index cf4c5af..1b14cd7 100644 --- a/services/network/url_loader.h +++ b/services/network/url_loader.h
@@ -142,7 +142,7 @@ void OnResponseBodyStreamReady(MojoResult result); void DeleteSelf(); void SendResponseToClient(); - void CompletePendingWrite(); + void CompletePendingWrite(bool success); void SetRawResponseHeaders(scoped_refptr<const net::HttpResponseHeaders>); void SendUploadProgress(const net::UploadProgress& progress); void OnUploadProgressACK();
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc index 320a91e..2db1d9b 100644 --- a/services/network/url_loader_unittest.cc +++ b/services/network/url_loader_unittest.cc
@@ -268,6 +268,68 @@ DISALLOW_COPY_AND_ASSIGN(EternalSyncReadsInterceptor); }; +// Simulates handing over things to the disk to write before returning to the +// caller. +class URLRequestSimulatedCacheJob : public net::URLRequestJob { + public: + // If |fill_entire_buffer| is true, each read fills the entire read buffer at + // once. Otherwise, one byte is read at a time. + URLRequestSimulatedCacheJob( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + scoped_refptr<net::IOBuffer>* simulated_cache_dest) + : URLRequestJob(request, network_delegate), + simulated_cache_dest_(simulated_cache_dest), + weak_factory_(this) {} + + // net::URLRequestJob implementation: + void Start() override { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&URLRequestSimulatedCacheJob::StartAsync, + weak_factory_.GetWeakPtr())); + } + + int ReadRawData(net::IOBuffer* buf, int buf_size) override { + DCHECK_GT(buf_size, 0); + + // Pretend this is the entire network stack, which has sent the buffer + // to some worker thread to be written to disk. + memset(buf->data(), 'a', buf_size); + *simulated_cache_dest_ = buf; + + // The network stack will not report the read result until the write + // completes. + return net::ERR_IO_PENDING; + } + + private: + ~URLRequestSimulatedCacheJob() override {} + void StartAsync() { NotifyHeadersComplete(); } + + scoped_refptr<net::IOBuffer>* simulated_cache_dest_; + base::WeakPtrFactory<URLRequestSimulatedCacheJob> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(URLRequestSimulatedCacheJob); +}; + +class SimulatedCacheInterceptor : public net::URLRequestInterceptor { + public: + explicit SimulatedCacheInterceptor( + scoped_refptr<net::IOBuffer>* simulated_cache_dest) + : simulated_cache_dest_(simulated_cache_dest) {} + + net::URLRequestJob* MaybeInterceptRequest( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + return new URLRequestSimulatedCacheJob(request, network_delegate, + simulated_cache_dest_); + } + + private: + scoped_refptr<net::IOBuffer>* simulated_cache_dest_; + DISALLOW_COPY_AND_ASSIGN(SimulatedCacheInterceptor); +}; + class RequestInterceptor : public net::URLRequestInterceptor { public: using InterceptCallback = base::Callback<void(net::URLRequest*)>; @@ -1988,6 +2050,54 @@ unowned_power_monitor_source->Resume(); } +TEST_F(URLLoaderTest, EnterSuspendDiskCacheWriteQueued) { + // Test to make sure that fetch abort on suspend doesn't yank out the backing + // for IOBuffer for an issued disk_cache Write. + + GURL url("http://www.example.com"); + scoped_refptr<net::IOBuffer> simulated_cache_dest; + net::URLRequestFilter::GetInstance()->AddUrlInterceptor( + url, std::make_unique<SimulatedCacheInterceptor>(&simulated_cache_dest)); + + std::unique_ptr<TestPowerMonitorSource> power_monitor_source = + std::make_unique<TestPowerMonitorSource>(); + TestPowerMonitorSource* unowned_power_monitor_source = + power_monitor_source.get(); + base::PowerMonitor power_monitor(std::move(power_monitor_source)); + + ResourceRequest request = CreateResourceRequest("GET", url); + + base::RunLoop delete_run_loop; + mojom::URLLoaderPtr loader; + std::unique_ptr<URLLoader> url_loader; + mojom::URLLoaderFactoryParams params; + params.process_id = mojom::kBrowserProcessId; + params.is_corb_enabled = false; + url_loader = std::make_unique<URLLoader>( + context(), nullptr /* network_service_client */, + DeleteLoaderCallback(&delete_run_loop, &url_loader), + mojo::MakeRequest(&loader), mojom::kURLLoadOptionNone, request, false, + client()->CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS, ¶ms, + 0 /* request_id */, resource_scheduler_client(), nullptr, + nullptr /* network_usage_accumulator */); + + // Spin until the job has produced a (simulated) cache write. + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(simulated_cache_dest); + + unowned_power_monitor_source->Suspend(); + + client()->RunUntilComplete(); + + EXPECT_EQ(net::ERR_ABORTED, client()->completion_status().error_code); + delete_run_loop.Run(); + + unowned_power_monitor_source->Resume(); + + // The "cache write" should still have data available. + EXPECT_EQ('a', simulated_cache_dest->data()[0]); +} + class FakeSSLPrivateKeyImpl : public network::mojom::SSLPrivateKey { public: explicit FakeSSLPrivateKeyImpl(
diff --git a/services/ws/input_devices/input_device_unittests.cc b/services/ws/input_devices/input_device_unittests.cc index ad2c3f5..a45f806 100644 --- a/services/ws/input_devices/input_device_unittests.cc +++ b/services/ws/input_devices/input_device_unittests.cc
@@ -128,8 +128,8 @@ TEST_F(InputDeviceTest, AddDeviceAfterComplete) { const ui::InputDevice keyboard1(100, ui::INPUT_DEVICE_INTERNAL, "Keyboard1"); - const ui::InputDevice keyboard2(200, ui::INPUT_DEVICE_EXTERNAL, "Keyboard2"); - const ui::InputDevice mouse(300, ui::INPUT_DEVICE_EXTERNAL, "Mouse"); + const ui::InputDevice keyboard2(200, ui::INPUT_DEVICE_USB, "Keyboard2"); + const ui::InputDevice mouse(300, ui::INPUT_DEVICE_USB, "Mouse"); TestInputDeviceClient client; AddClientAsObserver(&client);
diff --git a/storage/browser/fileapi/README.md b/storage/browser/fileapi/README.md new file mode 100644 index 0000000..ced2bcfe --- /dev/null +++ b/storage/browser/fileapi/README.md
@@ -0,0 +1,15 @@ +# FileSystem API + +This directory contains part of the browser side implementation of various +filesystem related APIs, as well as interfaces to treat various types of native +and non-native filesystems mostly the same without having to worry about the +underlying implementation. + +## Related directories + +[`//content/browser/fileapi/`](../../../content/browser/fileapi) contains the +rest of the browser side implementation, while +[`blink/renderer/modules/filesystem`](../../../third_party/blink/renderer/modules/filesystem) +contains the renderer side implementation and +[`blink/public/mojom/filesystem`](../../../third_party/blink/public/mojom/filesystem) +contains the mojom interfaces for these APIs.
diff --git a/testing/buildbot/filters/webui_polymer2_browser_tests.filter b/testing/buildbot/filters/webui_polymer2_browser_tests.filter index e6117fb..17a8ff0 100644 --- a/testing/buildbot/filters/webui_polymer2_browser_tests.filter +++ b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
@@ -288,6 +288,7 @@ PrintPreviewModelTest.* PrintPreviewNewDestinationSearchTest.* PrintPreviewNumberSettingsSectionTest.* +PrintPreviewPagesSettingsTest.* PrintPreviewPolicyTest.* PrintPreviewPreviewGenerationTest.* PrintPreviewPrintButtonTest.*
diff --git a/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter b/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter index e8f5f670..4d638837 100644 --- a/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter +++ b/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter
@@ -15,5 +15,4 @@ MaterialHistoryFocusTest.All PrintPreviewDestinationDialogInteractiveTest.FocusSearchBox PrintPreviewPrintHeaderInteractiveTest.FocusPrintOnReady -PrintPreviewPagesSettingsTest.* SettingsUIBrowserTest.All
diff --git a/testing/buildbot/generate_buildbot_json.py b/testing/buildbot/generate_buildbot_json.py index f5a8cb0..d2e11b0 100755 --- a/testing/buildbot/generate_buildbot_json.py +++ b/testing/buildbot/generate_buildbot_json.py
@@ -557,7 +557,7 @@ result, test_name, tester_name, tester_config, waterfall) return result - def substitute_gpu_args(self, tester_config, args): + def substitute_gpu_args(self, tester_config, swarming_config, args): substitutions = { # Any machine in waterfalls.pyl which desires to run GPU tests # must provide the os_type key. @@ -565,7 +565,7 @@ 'gpu_vendor_id': '0', 'gpu_device_id': '0', } - dimension_set = tester_config['swarming']['dimension_sets'][0] + dimension_set = swarming_config['dimension_sets'][0] if 'gpu' in dimension_set: # First remove the driver version, then split into vendor and device. gpu = dimension_set['gpu'] @@ -610,7 +610,7 @@ '--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc', ] + args result['args'] = self.maybe_fixup_args_array(self.substitute_gpu_args( - tester_config, args)) + tester_config, result['swarming'], args)) return result def get_test_generator_map(self): @@ -729,7 +729,13 @@ if not 'swarming_mixins' in test: return test - must_be_list(test['swarming_mixins'], 'test', test['test']) + test_name = test.get('name') + if not test_name: + test_name = test.get('test') + if not test_name: # pragma: no cover + # Not the best name, but we should say something. + test_name = str(test) + must_be_list(test['swarming_mixins'], 'test', test_name) for mixin in test['swarming_mixins']: valid_mixin(mixin) test = self.apply_swarming_mixin(self.swarming_mixins[mixin], test)
diff --git a/testing/buildbot/generate_buildbot_json_unittest.py b/testing/buildbot/generate_buildbot_json_unittest.py index 2c32627..bc22253 100755 --- a/testing/buildbot/generate_buildbot_json_unittest.py +++ b/testing/buildbot/generate_buildbot_json_unittest.py
@@ -162,6 +162,24 @@ ] """ +FOO_GPU_TELEMETRY_TEST_DIMENSIONS_WATERFALL = """\ +[ + { + 'name': 'chromium.test', + 'machines': { + 'Fake Tester': { + 'swarming_mixins': ['dimension_mixin'], + 'os_type': 'win', + 'browser_config': 'release', + 'test_suites': { + 'gpu_telemetry_tests': 'foo_tests', + }, + }, + }, + }, +] +""" + # Swarming mixins must be a list, a single string is not allowed. FOO_GTESTS_INVALID_LIST_MIXIN_WATERFALL = """\ [ @@ -1466,6 +1484,41 @@ } """ +GPU_DIMENSIONS_WATERFALL_OUTPUT = """\ +{ + "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, + "AAAAA2 See generate_buildbot_json.py to make changes": {}, + "Fake Tester": { + "isolated_scripts": [ + { + "args": [ + "foo_test", + "--show-stdout", + "--browser=release", + "--passthrough", + "-v", + "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc" + ], + "isolate_name": "telemetry_gpu_integration_test", + "name": "foo_test", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "iama": "mixin", + "integrity": "high" + } + ], + "expiration": 120, + "idempotent": false, + "value": "test" + } + } + ] + } +} +""" + LUCI_MILO_CFG = """\ consoles { builders { @@ -2178,6 +2231,16 @@ fbb.check_output_file_consistency(verbose=True) self.assertFalse(fbb.printed_lines) + def test_swarming_mixins_dimension_gpu(self): + fbb = FakeBBGen(FOO_GPU_TELEMETRY_TEST_DIMENSIONS_WATERFALL, + FOO_TEST_SUITE_WITH_MIXIN, + EMPTY_PYL_FILE, + SWARMING_MIXINS, + LUCI_MILO_CFG) + fbb.files['chromium.test.json'] = GPU_DIMENSIONS_WATERFALL_OUTPUT + fbb.check_output_file_consistency(verbose=True) + self.assertFalse(fbb.printed_lines) + def test_swarming_mixins_unreferenced(self): fbb = FakeBBGen(FOO_GTESTS_WATERFALL, FOO_TEST_SUITE_WITH_MIXIN,
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests index b1f2470d..d70ae81 100644 --- a/third_party/WebKit/LayoutTests/NeverFixTests +++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -1917,3 +1917,4 @@ # Tests that work only when LazyImageLoading feature is enabled. crbug.com/846170 http/tests/lazyload/lazy.html [ WontFix ] crbug.com/846170 http/tests/lazyload/attribute.html [ WontFix ] +crbug.com/846170 http/tests/lazyload/fixed-dimension.html [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index e06ff7c1..7017ec0 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -4818,7 +4818,7 @@ # Sheriff 2018-06-07 crbug.com/850395 virtual/gpu/fast/canvas/canvas-filter-stroke-paint-pattern.html [ Pass Failure ] -crbug.com/850358 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Pass Failure ] +crbug.com/850358 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Pass Failure Timeout ] crbug.com/849978 http/tests/devtools/elements/styles-4/stylesheet-source-url-comment.js [ Pass Failure ] # Sheriff 2018-06-08 @@ -5234,3 +5234,6 @@ # Sheriff 2018-09-24 crbug.com/888634 external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure ] crbug.com/888634 virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure ] + +# Sheriff 2018-09-25 +crbug.com/888609 [ Mac ] http/tests/devtools/coverage/gutter-css.js [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-fieldset-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-fieldset-001.html new file mode 100644 index 0000000..f924247 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-fieldset-001.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Containment Test: Size containment on fieldset</title> +<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> +<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size"> +<link rel="match" href="reference/contain-size-fieldset-001-ref.html"> +<meta name=assert content="Size containment does apply to fieldsets, thus their size is the same than if they don't have contents."> +<style> +fieldset { + contain: size; + display: inline-block; + color: transparent; + border: none; + padding: 0; +} +</style> + +<p>This test passes if it has the same output as the reference. You see the word "before", a small space, and then the word "after".</p> +before<fieldset><legend>legend</legend></fieldset>after
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-fieldset-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-fieldset-001-ref.html new file mode 100644 index 0000000..85f5c73 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/reference/contain-size-fieldset-001-ref.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Containment Test: Reference file</title> +<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com"> +<style> +fieldset { + display: inline-block; + color: transparent; + border: none; + padding: 0; +} +</style> + +<p>This test passes if it has the same output as the reference. You see the word "before", a small space, and then the word "after".</p> +before<fieldset></fieldset>after
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt similarity index 83% rename from third_party/WebKit/LayoutTests/platform/win/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt rename to third_party/WebKit/LayoutTests/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt index 35c73a83..d7cfc19 100644 --- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
@@ -1,326 +1,326 @@ This is a testharness.js-based test. -Found 324 tests; 168 PASS, 156 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 324 tests; 180 PASS, 144 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is PASS horizontal-tb ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" +PASS horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels +PASS horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" +PASS horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained PASS horizontal-tb ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is PASS horizontal-tb ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" +PASS horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels +PASS horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" +PASS horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained PASS horizontal-tb ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is PASS horizontal-tb ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px" -FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px" +FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" PASS horizontal-tb ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL horizontal-tb ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is PASS horizontal-tb ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px" -FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px" +FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" PASS horizontal-tb ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL horizontal-tb ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is PASS horizontal-tb ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px" -FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px" +FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" FAIL horizontal-tb ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL horizontal-tb ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL horizontal-tb ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is PASS horizontal-tb ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px" -FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px" +FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" FAIL horizontal-tb ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL horizontal-tb ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL horizontal-tb ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is PASS horizontal-tb rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" +PASS horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels +PASS horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" +PASS horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained PASS horizontal-tb rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is PASS horizontal-tb rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" +PASS horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels +PASS horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" +PASS horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained PASS horizontal-tb rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is PASS horizontal-tb rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px" -FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px" +FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" PASS horizontal-tb rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL horizontal-tb rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is PASS horizontal-tb rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px" -FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px" +FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" PASS horizontal-tb rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL horizontal-tb rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is PASS horizontal-tb rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px" -FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px" +FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" FAIL horizontal-tb rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL horizontal-tb rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL horizontal-tb rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is PASS horizontal-tb rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39063px" -FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39063px" +FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" FAIL horizontal-tb rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL horizontal-tb rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL horizontal-tb rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is PASS vertical-lr ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-lr ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is PASS vertical-lr ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-lr ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is PASS vertical-lr ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is PASS vertical-lr ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is PASS vertical-lr ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-lr ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-lr ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" PASS vertical-lr ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is PASS vertical-lr ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-lr ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-lr ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" PASS vertical-lr ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is PASS vertical-lr rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-lr rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is PASS vertical-lr rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-lr rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is PASS vertical-lr rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is PASS vertical-lr rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is PASS vertical-lr rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-lr rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-lr rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" PASS vertical-lr rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is PASS vertical-lr rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-lr rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-lr rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" PASS vertical-lr rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is PASS vertical-rl ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-rl ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is PASS vertical-rl ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-rl ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is PASS vertical-rl ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-rl ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is PASS vertical-rl ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-rl ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is PASS vertical-rl ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-rl ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-rl ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-rl ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is PASS vertical-rl ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-rl ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-rl ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-rl ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is PASS vertical-rl rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-rl rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is PASS vertical-rl rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-rl rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is PASS vertical-rl rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-rl rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is PASS vertical-rl rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value FAIL vertical-rl rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is PASS vertical-rl rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-rl rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-rl rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-rl rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is PASS vertical-rl rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-rl rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-rl rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-rl rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/picture-in-picture/request-picture-in-picture.html b/third_party/WebKit/LayoutTests/external/wpt/picture-in-picture/request-picture-in-picture.html index a0c3217..403d416c 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/picture-in-picture/request-picture-in-picture.html +++ b/third_party/WebKit/LayoutTests/external/wpt/picture-in-picture/request-picture-in-picture.html
@@ -9,8 +9,8 @@ <script> promise_test(async t => { const video = await loadVideo(); - return requestPictureInPictureWithTrustedClick(video); -}, 'request Picture-in-Picture resolves on user click'); + return promise_rejects(t, 'NotAllowedError', video.requestPictureInPicture()); +}, 'request Picture-in-Picture requires a user gesture'); promise_test(t => { const video = document.createElement('video'); @@ -31,6 +31,6 @@ promise_test(async t => { const video = await loadVideo(); - return promise_rejects(t, 'NotAllowedError', video.requestPictureInPicture()); -}, 'request Picture-in-Picture requires a user gesture'); + return requestPictureInPictureWithTrustedClick(video); +}, 'request Picture-in-Picture resolves on user click'); </script>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt index d6d27674..5b930a3 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt
@@ -1,326 +1,326 @@ This is a testharness.js-based test. -Found 324 tests; 180 PASS, 144 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 324 tests; 192 PASS, 132 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is PASS horizontal-tb ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" +PASS horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels +PASS horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" +PASS horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained PASS horizontal-tb ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is PASS horizontal-tb ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" +PASS horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels +PASS horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" +PASS horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained PASS horizontal-tb ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is PASS horizontal-tb ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" +FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" PASS horizontal-tb ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is PASS horizontal-tb ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" +FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" PASS horizontal-tb ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is PASS horizontal-tb ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" +FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" FAIL horizontal-tb ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL horizontal-tb ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL horizontal-tb ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is PASS horizontal-tb ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" +FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" FAIL horizontal-tb ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL horizontal-tb ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL horizontal-tb ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is PASS horizontal-tb rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" +PASS horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels +PASS horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" +PASS horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained PASS horizontal-tb rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is PASS horizontal-tb rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" +PASS horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels +PASS horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" +PASS horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained PASS horizontal-tb rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is PASS horizontal-tb rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" +FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" PASS horizontal-tb rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is PASS horizontal-tb rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" +FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" PASS horizontal-tb rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS horizontal-tb rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is PASS horizontal-tb rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" +FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" FAIL horizontal-tb rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL horizontal-tb rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL horizontal-tb rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is PASS horizontal-tb rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" +FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'left' expected "150px" but got "75px" +FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'left' expected "148px" but got "73px" PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" +FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'left' expected "600px" but got "300px" FAIL horizontal-tb rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL horizontal-tb rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL horizontal-tb rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is PASS vertical-lr ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is PASS vertical-lr ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is PASS vertical-lr ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is PASS vertical-lr ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is PASS vertical-lr ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-lr ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-lr ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-lr ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is PASS vertical-lr ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-lr ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-lr ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-lr ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is PASS vertical-lr rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is PASS vertical-lr rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is PASS vertical-lr rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is PASS vertical-lr rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-lr rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-lr rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-lr rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is PASS vertical-lr rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-lr rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-lr rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-lr rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is PASS vertical-lr rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-lr rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-lr rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-lr rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is PASS vertical-rl ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-rl ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is PASS vertical-rl ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-rl ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is PASS vertical-rl ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-rl ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is PASS vertical-rl ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-rl ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is PASS vertical-rl ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-rl ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-rl ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-rl ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is PASS vertical-rl ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-rl ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-rl ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-rl ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is PASS vertical-rl rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-rl rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is PASS vertical-rl rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" +FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" +FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-rl rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is PASS vertical-rl rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-rl rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is PASS vertical-rl rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" PASS vertical-rl rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value PASS vertical-rl rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value PASS vertical-rl rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is PASS vertical-rl rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-rl rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-rl rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-rl rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is PASS vertical-rl rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" +FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "60px" +FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "59px" PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" +FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "600px" FAIL vertical-rl rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" FAIL vertical-rl rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" FAIL vertical-rl rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/will-change/composited-layers-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/will-change/composited-layers-expected.txt index affc440..b13515b6 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/will-change/composited-layers-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/will-change/composited-layers-expected.txt
@@ -10,7 +10,6 @@ "name": "LayoutBlockFlow DIV id='willChangeOpacity' class='shouldComposite'", "position": [12, 42], "bounds": [30, 30], - "contentsOpaque": true, "backgroundColor": "#008000" }, { @@ -52,7 +51,6 @@ "name": "LayoutBlockFlow DIV id='willChangeCombinationThatComposites' class='shouldComposite'", "position": [12, 416], "bounds": [30, 30], - "contentsOpaque": true, "backgroundColor": "#008000" } ]
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt new file mode 100644 index 0000000..02ea3eb2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand-expected.txt
@@ -0,0 +1,40 @@ +Tests that console artifacts can be expanded, collapsed via keyboard. + + +Running: testExpandingTraces +Evaluating: console.warn("warning") +Message count: 1 + +Force selecting index 0 +Viewport virtual selection: 0 +Is trace expanded: NO + +ArrowRight: +Viewport virtual selection: 0 +Is trace expanded: YES + +ArrowLeft: +Viewport virtual selection: 0 +Is trace expanded: NO + +Running: testExpandingGroups +Evaluating: console.group("group"); console.log("log child"); +Message count: 2 + +Force selecting index 0 +Viewport virtual selection: 0 +Is group expanded: YES +console-key-expand.js:27 group +console-key-expand.js:27 log child + +ArrowLeft: +Viewport virtual selection: 0 +Is group expanded: NO +console-key-expand.js:27 group + +ArrowRight: +Viewport virtual selection: 0 +Is group expanded: YES +console-key-expand.js:27 group +console-key-expand.js:27 log child +
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand.js new file mode 100644 index 0000000..4ac46ed --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-key-expand.js
@@ -0,0 +1,92 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +(async function() { + TestRunner.addResult(`Tests that console artifacts can be expanded, collapsed via keyboard.\n`); + await TestRunner.loadModule('console_test_runner'); + await TestRunner.showPanel('console'); + ConsoleTestRunner.fixConsoleViewportDimensions(600, 200); + await ConsoleTestRunner.waitUntilConsoleEditorLoaded(); + + const consoleView = Console.ConsoleView.instance(); + const viewport = consoleView._viewport; + const prompt = consoleView._prompt; + + TestRunner.runTestSuite([ + async function testExpandingTraces(next) { + await clearAndLog(`console.warn("warning")`); + forceSelect(0); + + dumpFocus(); + press('ArrowRight'); + dumpFocus(); + press('ArrowLeft'); + dumpFocus(); + + next(); + }, + + async function testExpandingGroups(next) { + await clearAndLog(`console.group("group"); console.log("log child");`, 2); + forceSelect(0); + + dumpFocus(); + ConsoleTestRunner.dumpConsoleMessages(); + press('ArrowLeft'); + dumpFocus(); + ConsoleTestRunner.dumpConsoleMessages(); + press('ArrowRight'); + dumpFocus(); + ConsoleTestRunner.dumpConsoleMessages(); + + next(); + }, + ]); + + + // Utilities. + async function clearAndLog(expression, expectedCount = 1) { + consoleView._consoleCleared(); + TestRunner.addResult(`Evaluating: ${expression}`); + await TestRunner.evaluateInPagePromise(expression); + await ConsoleTestRunner.waitForConsoleMessagesPromise(expectedCount); + await ConsoleTestRunner.waitForPendingViewportUpdates(); + } + + function forceSelect(index) { + TestRunner.addResult(`\nForce selecting index ${index}`); + viewport._virtualSelectedIndex = index; + viewport._contentElement.focus(); + viewport._updateFocusedItem(); + } + + function press(key) { + TestRunner.addResult(`\n${key}:`); + eventSender.keyDown(key); + } + + function dumpFocus() { + const firstMessage = consoleView._visibleViewMessages[0]; + const hasTrace = !!firstMessage.element().querySelector('.console-message-stack-trace-toggle'); + const hasHiddenStackTrace = firstMessage.element().querySelector('.console-message-stack-trace-wrapper > div.hidden'); + const hasCollapsedObject = firstMessage.element().querySelector('.console-view-object-properties-section.hidden'); + const hasExpandedObject = firstMessage.element().querySelector('.console-view-object-properties-section:not(.hidden)'); + + TestRunner.addResult(`Viewport virtual selection: ${viewport._virtualSelectedIndex}`); + + if (hasCollapsedObject) { + TestRunner.addResult(`Has object: collapsed`); + } else if (hasExpandedObject) { + TestRunner.addResult(`Has object: expanded`); + } + + if (hasTrace) { + TestRunner.addResult(`Is trace expanded: ${!hasHiddenStackTrace ? 'YES' : 'NO'}`); + } + if (firstMessage instanceof Console.ConsoleGroupViewMessage) { + const expanded = !firstMessage.collapsed(); + TestRunner.addResult(`Is group expanded: ${expanded ? 'YES' : 'NO'}`); + } + } +})();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits-expected.txt index cec1d3e..5ecfdc22 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits-expected.txt
@@ -5,7 +5,8 @@ -------------- await 0 was processed: -(async () => {return (await 0)})() +(async () => {return (await 0) +})() -------------- async function foo() { await 0; } was ignored. @@ -21,61 +22,98 @@ -------------- var a = await 1 was processed: -(async () => {void (a = await 1)})() +(async () => {void (a = await 1) +})() -------------- let a = await 1 was processed: -(async () => {void (a = await 1)})() +(async () => {void (a = await 1) +})() -------------- const a = await 1 was processed: -(async () => {void (a = await 1)})() +(async () => {void (a = await 1) +})() -------------- for (var i = 0; i < 1; ++i) { await i } was processed: -(async () => {for (void (i = 0); i < 1; ++i) { await i }})() +(async () => {for (void (i = 0); i < 1; ++i) { await i } +})() -------------- for (let i = 0; i < 1; ++i) { await i } was processed: -(async () => {for (let i = 0; i < 1; ++i) { await i }})() +(async () => {for (let i = 0; i < 1; ++i) { await i } +})() -------------- var {a} = {a:1}, [b] = [1], {c:{d}} = {c:{d: await 1}} was processed: -(async () => {void ( ({a} = {a:1}), ([b] = [1]), ({c:{d}} = {c:{d: await 1}}))})() +(async () => {void ( ({a} = {a:1}), ([b] = [1]), ({c:{d}} = {c:{d: await 1}})) +})() -------------- console.log(`${(await {a:1}).a}`) was processed: -(async () => {return (console.log(`${(await {a:1}).a}`))})() +(async () => {return (console.log(`${(await {a:1}).a}`)) +})() -------------- await 0;function foo() {} was processed: -(async () => {await 0;foo=function foo() {}})() +(async () => {await 0;foo=function foo() {} +})() -------------- await 0;class Foo {} was processed: -(async () => {await 0;Foo=class Foo {}})() +(async () => {await 0;Foo=class Foo {} +})() -------------- if (await true) { function foo() {} } was processed: -(async () => {if (await true) { foo=function foo() {} }})() +(async () => {if (await true) { foo=function foo() {} } +})() -------------- if (await true) { class Foo{} } was processed: -(async () => {if (await true) { class Foo{} }})() +(async () => {if (await true) { class Foo{} } +})() -------------- if (await true) { var a = 1; } was processed: -(async () => {if (await true) { void (a = 1); }})() +(async () => {if (await true) { void (a = 1); } +})() -------------- if (await true) { let a = 1; } was processed: -(async () => {if (await true) { let a = 1; }})() +(async () => {if (await true) { let a = 1; } +})() -------------- var a = await 1; let b = 2; const c = 3; was processed: -(async () => {void (a = await 1); void (b = 2); void (c = 3);})() +(async () => {void (a = await 1); void (b = 2); void (c = 3); +})() -------------- let o = await 1, p was processed: -(async () => {void ( (o = await 1), (p=undefined))})() +(async () => {void ( (o = await 1), (p=undefined)) +})() +-------------- +for await (const number of asyncRandomNumbers()) {} +was processed: +(async () => {for await (const number of asyncRandomNumbers()) {} +})() +-------------- +[...(await fetch('url', { method: 'HEAD' })).headers.entries()] +was processed: +(async () => {return ([...(await fetch('url', { method: 'HEAD' })).headers.entries()]) +})() +-------------- +await 1 +//hello +was processed: +(async () => {return (await 1) +//hello +})() +-------------- +var {a = await new Promise(resolve => resolve({a:123}))} = {a : 3} +was processed: +(async () => {void ({a = await new Promise(resolve => resolve({a:123}))} = {a : 3}) +})()
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits.js b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits.js index 76c11dac..805bf57 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/preprocess-top-level-awaits.js
@@ -20,7 +20,11 @@ 'if (await true) { var a = 1; }', 'if (await true) { let a = 1; }', 'var a = await 1; let b = 2; const c = 3;', - 'let o = await 1, p' + 'let o = await 1, p', + 'for await (const number of asyncRandomNumbers()) {}', + '[...(await fetch(\'url\', { method: \'HEAD\' })).headers.entries()]', + 'await 1\n//hello', + 'var {a = await new Promise(resolve => resolve({a:123}))} = {a : 3}' ]; await TestRunner.loadModule("formatter");
diff --git a/third_party/WebKit/LayoutTests/http/tests/lazyload/fixed-dimension.html b/third_party/WebKit/LayoutTests/http/tests/lazyload/fixed-dimension.html new file mode 100644 index 0000000..184ed2f --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/lazyload/fixed-dimension.html
@@ -0,0 +1,48 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="placeholder.js"></script> + +<body> + <div style="height:10000px;"></div> + <img id="fixed_dimension_img" src='../loading/resources/base-image1.png' width="10" height="10"> + <img id="large_dimension_img" src='../loading/resources/base-image2.png' width="100" height="100"> + <img id="percent_dimension_img" src='../loading/resources/base-image3.png' width="10%" height="10%"> + <img id="fixed_width_only_img" src='../loading/resources/dup-image1.png' width="10"> + <img id="fixed_height_only_img" src='../loading/resources/dup-image2.png' height="10"> +</body> + +<script> + async_test(function(t) { + window.addEventListener("load", t.step_func_done()); + }, "Test that document load event is fired"); + + async_test(function(t) { + var fixed_dimension_img = document.getElementById("fixed_dimension_img"); + fixed_dimension_img.addEventListener("load", + t.step_func_done(function() { + assert_true(is_image_fully_loaded(fixed_dimension_img)); + })); + }, "Test that small <img> with fixed height and width is loaded, and not a placeholder"); + + async_test(function(t) { + var large_dimension_img = document.getElementById("large_dimension_img"); + var percent_dimension_img = document.getElementById("percent_dimension_img"); + var fixed_width_only_img = document.getElementById("fixed_width_only_img"); + var fixed_height_only_img = document.getElementById("fixed_height_only_img"); + window.addEventListener("load", t.step_func_done(function() { + assert_false(is_image_fully_loaded(large_dimension_img)); + assert_false(is_image_fully_loaded(percent_dimension_img)); + assert_false(is_image_fully_loaded(fixed_width_only_img)); + assert_false(is_image_fully_loaded(fixed_height_only_img)); + })); + large_dimension_img.addEventListener("load", + t.unreached_func("Load event should not be fired for below viewport image with large fixed dimension")); + percent_dimension_img.addEventListener("load", + t.unreached_func("Load event should not be fired for below viewport image with percentage dimension")); + fixed_width_only_img.addEventListener("load", + t.unreached_func("Load event should not be fired for below viewport image with only fixed width")); + fixed_height_only_img.addEventListener("load", + t.unreached_func("Load event should not be fired for below viewport image with only fixed height")); + }, "Test that <img> with non fixed height and width below the viewport is loaded as placeholder"); +</script>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world-expected.txt new file mode 100644 index 0000000..ff925137 --- /dev/null +++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world-expected.txt
@@ -0,0 +1,14 @@ +Tests that Page.addScriptToEvaluateOnNewDocument is executed in the given world +Adding scripts +world#0 +message from 0 +world#1 +message from 1 +world#2 +message from 2 +world#3 +message from 3 +world#4 +message from 4 +Removing scripts +
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world.js new file mode 100644 index 0000000..436034f --- /dev/null +++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-in-world.js
@@ -0,0 +1,33 @@ +(async function(testRunner) { + const {page, session, dp} = await testRunner.startBlank( + 'Tests that Page.addScriptToEvaluateOnNewDocument is executed in the given world'); + dp.Runtime.enable(); + dp.Page.enable(); + + const scriptIds = []; + dp.Runtime.onConsoleAPICalled(msg => testRunner.log(msg.params.args[0].value)); + dp.Runtime.onExecutionContextCreated(msg => { + if (msg.params.context.name.includes('world')) + testRunner.log(msg.params.context.name); + }); + + testRunner.log('Adding scripts'); + for (let i = 0; i < 5; ++i) { + const result = await dp.Page.addScriptToEvaluateOnNewDocument({source: ` + console.log('message from ${i}');`, worldName: `world#${i}`}); + scriptIds.push(result.result.identifier); + } + + await session.navigate('../resources/blank.html'); + + testRunner.log('Removing scripts'); + for (let identifier of scriptIds) { + const response = await dp.Page.removeScriptToEvaluateOnNewDocument({identifier}); + if (!response.result) + testRunner.log('Failed script removal'); + } + + await session.navigate('../resources/blank.html'); + + testRunner.completeTest(); +})
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load-expected.txt index 1d2fb125..bed3d35 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load-expected.txt
@@ -1,17 +1,9 @@ Tests that Page.addScriptToEvaluateOnLoad is executed in the order of addition +Adding scripts message from 0 message from 1 message from 2 message from 3 message from 4 -message from 5 -message from 6 -message from 7 -message from 8 -message from 9 -message from 10 -message from 11 -message from 12 -message from 13 -message from 14 +Removing scripts
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load.js b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load.js index 024683c7..7cd3114 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load.js +++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/add-script-to-evaluate-on-load.js
@@ -4,13 +4,27 @@ dp.Runtime.enable(); dp.Page.enable(); + const scriptIds = []; dp.Runtime.onConsoleAPICalled(msg => testRunner.log(msg.params.args[0].value)); - for (let i = 0; i < 15; ++i) { - await dp.Page.addScriptToEvaluateOnNewDocument({source: ` + testRunner.log('Adding scripts'); + for (let i = 0; i < 5; ++i) { + const result = await dp.Page.addScriptToEvaluateOnNewDocument({source: ` console.log('message from ${i}'); `}); + scriptIds.push(result.result.identifier); } + await session.navigate('../resources/blank.html'); + + testRunner.log('Removing scripts'); + for (let identifier of scriptIds) { + const response = await dp.Page.removeScriptToEvaluateOnNewDocument({identifier}); + if (!response.result) + testRunner.log('Failed script removal'); + } + + await session.navigate('../resources/blank.html'); + testRunner.completeTest(); })
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt deleted file mode 100644 index 23e57a1..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt +++ /dev/null
@@ -1,328 +0,0 @@ -This is a testharness.js-based test. -Found 324 tests; 168 PASS, 156 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is -PASS horizontal-tb ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" -PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" -PASS horizontal-tb ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value -PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is -PASS horizontal-tb ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" -PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" -PASS horizontal-tb ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value -PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is -PASS horizontal-tb ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -PASS horizontal-tb ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL horizontal-tb ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is -PASS horizontal-tb ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -PASS horizontal-tb ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL horizontal-tb ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" -PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is -PASS horizontal-tb ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -FAIL horizontal-tb ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL horizontal-tb ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL horizontal-tb ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is -PASS horizontal-tb ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -FAIL horizontal-tb ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL horizontal-tb ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL horizontal-tb ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" -PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is -PASS horizontal-tb rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" -PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" -PASS horizontal-tb rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value -PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is -PASS horizontal-tb rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" -PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" -PASS horizontal-tb rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value -PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is -PASS horizontal-tb rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -PASS horizontal-tb rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL horizontal-tb rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is -PASS horizontal-tb rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -PASS horizontal-tb rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL horizontal-tb rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" -PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is -PASS horizontal-tb rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -FAIL horizontal-tb rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL horizontal-tb rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL horizontal-tb rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is -PASS horizontal-tb rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -FAIL horizontal-tb rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL horizontal-tb rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL horizontal-tb rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" -PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is -PASS vertical-lr ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-lr ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-lr ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is -PASS vertical-lr ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-lr ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-lr ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" -PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is -PASS vertical-lr ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-lr ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is -PASS vertical-lr ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-lr ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is -PASS vertical-lr ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-lr ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-lr ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -PASS vertical-lr ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is -PASS vertical-lr ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-lr ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-lr ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -PASS vertical-lr ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is -PASS vertical-lr rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-lr rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-lr rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is -PASS vertical-lr rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-lr rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-lr rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" -PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is -PASS vertical-lr rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-lr rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is -PASS vertical-lr rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-lr rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is -PASS vertical-lr rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-lr rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-lr rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -PASS vertical-lr rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is -PASS vertical-lr rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-lr rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-lr rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -PASS vertical-lr rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value -PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is -PASS vertical-rl ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-rl ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is -PASS vertical-rl ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-rl ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" -PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is -PASS vertical-rl ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-rl ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" -PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is -PASS vertical-rl ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-rl ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" -PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is -PASS vertical-rl ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-rl ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-rl ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL vertical-rl ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" -PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is -PASS vertical-rl ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-rl ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-rl ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL vertical-rl ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" -PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is -PASS vertical-rl rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-rl rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is -PASS vertical-rl rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-rl rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" -PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is -PASS vertical-rl rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-rl rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" -PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is -PASS vertical-rl rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-rl rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" -PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is -PASS vertical-rl rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-rl rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-rl rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL vertical-rl rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" -PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is -PASS vertical-rl rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-rl rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-rl rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL vertical-rl rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png index c240aad9..954d9c3d 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png index cd081b8..a835d920 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png index cd081b8..a835d920 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png index 141a09f..62388e37 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png index 09e6437e..60c33430 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png index 248bfac..5adb1a56 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt deleted file mode 100644 index 23e57a1..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/css/cssom/getComputedStyle-insets-fixed-expected.txt +++ /dev/null
@@ -1,328 +0,0 @@ -This is a testharness.js-based test. -Found 324 tests; 168 PASS, 156 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is -PASS horizontal-tb ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" -PASS horizontal-tb ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" -PASS horizontal-tb ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value -PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is -PASS horizontal-tb ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" -PASS horizontal-tb ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" -PASS horizontal-tb ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value -PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is -PASS horizontal-tb ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -PASS horizontal-tb ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL horizontal-tb ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is -PASS horizontal-tb ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -PASS horizontal-tb ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL horizontal-tb ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" -PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is -PASS horizontal-tb ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -FAIL horizontal-tb ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL horizontal-tb ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL horizontal-tb ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is -PASS horizontal-tb ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -FAIL horizontal-tb ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL horizontal-tb ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL horizontal-tb ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" -PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is -PASS horizontal-tb rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" -PASS horizontal-tb rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" -PASS horizontal-tb rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value -PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is -PASS horizontal-tb rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "17.1875px" -FAIL horizontal-tb rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "16.1875px" -PASS horizontal-tb rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "172px" -PASS horizontal-tb rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value -PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is -PASS horizontal-tb rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -PASS horizontal-tb rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL horizontal-tb rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is -PASS horizontal-tb rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -PASS horizontal-tb rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS horizontal-tb rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL horizontal-tb rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" -PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is -PASS horizontal-tb rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -FAIL horizontal-tb rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL horizontal-tb rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL horizontal-tb rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is -PASS horizontal-tb rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "4.39062px" -FAIL horizontal-tb rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "3.39062px" -PASS horizontal-tb rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL horizontal-tb rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "44px" -FAIL horizontal-tb rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL horizontal-tb rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL horizontal-tb rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "173px" but got "254px" -PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is -PASS vertical-lr ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-lr ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-lr ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-lr ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is -PASS vertical-lr ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-lr ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-lr ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-lr ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" -PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is -PASS vertical-lr ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-lr ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is -PASS vertical-lr ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-lr ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS vertical-lr ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is -PASS vertical-lr ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-lr ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-lr ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -PASS vertical-lr ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is -PASS vertical-lr ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-lr ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-lr ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -PASS vertical-lr ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is -PASS vertical-lr rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-lr rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-lr rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-lr rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is -PASS vertical-lr rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-lr rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-lr rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-lr rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-lr rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" -PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is -PASS vertical-lr rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-lr rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is -PASS vertical-lr rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-lr rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -PASS vertical-lr rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is -PASS vertical-lr rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-lr rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-lr rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -PASS vertical-lr rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value -PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is -PASS vertical-lr rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-lr rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-lr rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-lr rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-lr rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-lr rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-lr rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -PASS vertical-lr rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value -PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is -PASS vertical-rl ltr inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl ltr inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-rl ltr inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-rl ltr inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl ltr inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl ltr inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is -PASS vertical-rl ltr inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl ltr inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-rl ltr inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-rl ltr inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl ltr inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl ltr inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" -PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is -PASS vertical-rl ltr inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl ltr inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-rl ltr inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl ltr inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl ltr inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" -PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is -PASS vertical-rl ltr inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl ltr inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-rl ltr inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl ltr inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl ltr inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" -PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is -PASS vertical-rl ltr inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl ltr inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-rl ltr inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-rl ltr inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL vertical-rl ltr inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" -PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is -PASS vertical-rl ltr inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl ltr inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl ltr inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl ltr inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl ltr inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-rl ltr inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-rl ltr inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL vertical-rl ltr inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" -PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is -PASS vertical-rl rtl inside horizontal-tb ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl rtl inside horizontal-tb ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-rl rtl inside horizontal-tb ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside horizontal-tb ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-rl rtl inside horizontal-tb ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl rtl inside horizontal-tb ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl rtl inside horizontal-tb ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "254px" -PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is -PASS vertical-rl rtl inside horizontal-tb rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "47.1875px" -FAIL vertical-rl rtl inside horizontal-tb rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "46.1875px" -PASS vertical-rl rtl inside horizontal-tb rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside horizontal-tb rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "472px" -PASS vertical-rl rtl inside horizontal-tb rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl rtl inside horizontal-tb rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl rtl inside horizontal-tb rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'top' expected "127px" but got "346px" -PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is -PASS vertical-rl rtl inside vertical-lr ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-lr ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-lr ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl rtl inside vertical-lr ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-lr ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-rl rtl inside vertical-lr ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl rtl inside vertical-lr ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl rtl inside vertical-lr ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" -PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is -PASS vertical-rl rtl inside vertical-lr rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-lr rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-lr rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl rtl inside vertical-lr rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-lr rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -PASS vertical-rl rtl inside vertical-lr rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value -PASS vertical-rl rtl inside vertical-lr rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value -FAIL vertical-rl rtl inside vertical-lr rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "254px" but got "346px" -PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is -PASS vertical-rl rtl inside vertical-rl ltr - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-rl ltr - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-rl ltr - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl rtl inside vertical-rl ltr - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-rl ltr - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-rl rtl inside vertical-rl ltr - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-rl rtl inside vertical-rl ltr - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL vertical-rl rtl inside vertical-rl ltr - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" -PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is -PASS vertical-rl rtl inside vertical-rl rtl - Relative lengths are absolutized into pixels -FAIL vertical-rl rtl inside vertical-rl rtl - Percentages are absolutized into pixels assert_equals: 'top' expected "30px" but got "34.3906px" -FAIL vertical-rl rtl inside vertical-rl rtl - calc() is absolutized into pixels assert_equals: 'top' expected "29px" but got "33.3906px" -PASS vertical-rl rtl inside vertical-rl rtl - Pixels resolve as-is when overconstrained -FAIL vertical-rl rtl inside vertical-rl rtl - Percentages absolutize the computed value when overconstrained assert_equals: 'top' expected "300px" but got "344px" -FAIL vertical-rl rtl inside vertical-rl rtl - If start side is 'auto' and end side is not, 'auto' resolves to used value assert_equals: 'left' expected "596px" but got "4px" -FAIL vertical-rl rtl inside vertical-rl rtl - If end side is 'auto' and start side is not, 'auto' resolves to used value assert_equals: 'right' expected "598px" but got "2px" -FAIL vertical-rl rtl inside vertical-rl rtl - If opposite sides are 'auto', they resolve to used value assert_equals: 'left' expected "346px" but got "254px" -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png new file mode 100644 index 0000000..954d9c3d --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png index 8a49d59..e8a89cc 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png new file mode 100644 index 0000000..a835d920 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png index 33a04bb..c898f21d 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png index c389808..412ad62 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png index c389808..412ad62 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png deleted file mode 100644 index 3c308d6..0000000 --- a/third_party/WebKit/LayoutTests/virtual/scalefactor150/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/WebKit/LayoutTests/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png deleted file mode 100644 index a29dedd3..0000000 --- a/third_party/WebKit/LayoutTests/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 3077647..e322d6f 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -67,10 +67,16 @@ #endif }; -// Freeze non-timer task queues in background, after allowed grace time. Launch -// bug: https://crbug.com/822954. "stop" is a legacy name. -const base::Feature kStopNonTimersInBackground{ - "stop-non-timers-in-background", base::FEATURE_DISABLED_BY_DEFAULT}; +// Freeze non-timer task queues in background, after allowed grace time. +// "stop" is a legacy name. +const base::Feature kStopNonTimersInBackground { + "stop-non-timers-in-background", +#if defined(OS_ANDROID) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; // Writable files and native filesystem access. https://crbug.com/853326 const base::Feature kWritableFilesAPI{"WritableFilesAPI",
diff --git a/third_party/blink/public/mojom/filesystem/file_system.mojom b/third_party/blink/public/mojom/filesystem/file_system.mojom index d33a4ee..d372a8d 100644 --- a/third_party/blink/public/mojom/filesystem/file_system.mojom +++ b/third_party/blink/public/mojom/filesystem/file_system.mojom
@@ -72,6 +72,13 @@ DidReceiveSnapshotFile(); }; +enum ChooseFileSystemEntryType { + kOpenFile, + kOpenMultipleFiles, + kSaveFile, + kOpenDirectory +}; + // Interface provided by the browser to the renderer to carry out filesystem // operations. All [Sync] methods should only be called synchronously on worker // threads (and asynchronously otherwise). @@ -219,7 +226,7 @@ // success. // TODO(https://crbug.com/878581): Add more options to this method to support // multiple files, directories, "open" vs "save" dialogs, etc. - ChooseEntry() => + ChooseEntry(ChooseFileSystemEntryType type) => (mojo_base.mojom.FileError error_code, array<FileSystemEntry> entries); };
diff --git a/third_party/blink/public/web/web_widget.h b/third_party/blink/public/web/web_widget.h index 069c531..025c15bf 100644 --- a/third_party/blink/public/web/web_widget.h +++ b/third_party/blink/public/web/web_widget.h
@@ -84,9 +84,13 @@ // Called to update imperative animation state. This should be called before // paint, although the client can rate-limit these calls. - // |lastFrameTimeMonotonic| is in seconds. + // |last_frame_time| is in seconds. virtual void BeginFrame(base::TimeTicks last_frame_time) {} + // Called when a main frame time metric should be emitted, along with + // any metrics that depend upon the main frame total time. + virtual void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) {} + // Called to run through the entire set of document lifecycle phases needed // to render a frame of the web widget. This MUST be called before Paint, // and it may result in calls to WebWidgetClient::didInvalidateRect.
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc index f74801ce..4252f4a 100644 --- a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc +++ b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
@@ -54,7 +54,7 @@ const PropertyRegistry* registry, const Document& document) : registry_(registry) { - allow_all_animations_ = document.GetFrame()->DeprecatedIsFeatureEnabled( + allow_all_animations_ = document.IsFeatureEnabled( blink::mojom::FeaturePolicyFeature::kAnimations); }
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 7be10e9..58813ca 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -140,6 +140,7 @@ #include "third_party/blink/renderer/core/frame/dom_timer.h" #include "third_party/blink/renderer/core/frame/dom_visual_viewport.h" #include "third_party/blink/renderer/core/frame/event_handler_registry.h" +#include "third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h" #include "third_party/blink/renderer/core/frame/frame_console.h" #include "third_party/blink/renderer/core/frame/history.h" #include "third_party/blink/renderer/core/frame/intervention.h" @@ -148,6 +149,8 @@ #include "third_party/blink/renderer/core/frame/local_frame_client.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/performance_monitor.h" +#include "third_party/blink/renderer/core/frame/report.h" +#include "third_party/blink/renderer/core/frame/reporting_context.h" #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/use_counter.h" #include "third_party/blink/renderer/core/frame/viewport_data.h" @@ -6217,9 +6220,8 @@ if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) { return true; } - if (!frame_ || frame_->DeprecatedIsFeatureEnabled( - mojom::FeaturePolicyFeature::kDocumentWrite, - ReportOptions::kReportOnFailure)) { + if (!frame_ || IsFeatureEnabled(mojom::FeaturePolicyFeature::kDocumentWrite, + ReportOptions::kReportOnFailure)) { return true; } @@ -7604,6 +7606,30 @@ return *lazy_load_image_observer_; } +void Document::ReportFeaturePolicyViolation( + mojom::FeaturePolicyFeature feature) const { + if (!RuntimeEnabledFeatures::FeaturePolicyReportingEnabled()) + return; + if (!GetFrame()) + return; + const String& feature_name = GetNameForFeature(feature); + FeaturePolicyViolationReportBody* body = new FeaturePolicyViolationReportBody( + feature_name, "Feature policy violation", SourceLocation::Capture()); + Report* report = new Report("feature-policy", Url().GetString(), body); + ReportingContext::From(this)->QueueReport(report); + + bool is_null; + int line_number = body->lineNumber(is_null); + line_number = is_null ? 0 : line_number; + int column_number = body->columnNumber(is_null); + column_number = is_null ? 0 : column_number; + + // Send the feature policy violation report to the Reporting API. + GetFrame()->GetReportingService()->QueueFeaturePolicyViolationReport( + Url(), feature_name, "Feature policy violation", body->sourceFile(), + line_number, column_number); +} + template class CORE_TEMPLATE_EXPORT Supplement<Document>; } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index f724fb37..bf0c2368 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -1466,6 +1466,8 @@ return agent_cluster_id_; } + void ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature) const override; + protected: Document(const DocumentInit&, DocumentClassFlags = kDefaultDocumentClass);
diff --git a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc index 0222c99e..db7462a 100644 --- a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc +++ b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
@@ -145,7 +145,7 @@ UseCounter::Count(node_->GetDocument(), WebFeature::kPerformanceEventTimingConstructor); eventTiming = std::make_unique<EventTiming>(frame->DomWindow()); - eventTiming->WillDispatchEvent(event_); + eventTiming->WillDispatchEvent(*event_); } } event_->GetEventPath().EnsureWindowEventContext(); @@ -197,7 +197,7 @@ DispatchEventPostProcess(activation_target, pre_dispatch_event_handler_result); if (eventTiming) - eventTiming->DidDispatchEvent(event_); + eventTiming->DidDispatchEvent(*event_); return EventTarget::GetDispatchEventResult(*event_); }
diff --git a/third_party/blink/renderer/core/execution_context/security_context.cc b/third_party/blink/renderer/core/execution_context/security_context.cc index 1ec0c65..6b0cafc9 100644 --- a/third_party/blink/renderer/core/execution_context/security_context.cc +++ b/third_party/blink/renderer/core/execution_context/security_context.cc
@@ -120,4 +120,17 @@ feature_policy_->SetHeaderPolicy(parsed_header); } +bool SecurityContext::IsFeatureEnabled(mojom::FeaturePolicyFeature feature, + ReportOptions report_on_failure) const { + // The policy should always be initialized before checking it to ensure we + // properly inherit the parent policy. + DCHECK(feature_policy_); + + if (feature_policy_->IsFeatureEnabled(feature)) + return true; + if (report_on_failure == ReportOptions::kReportOnFailure) + ReportFeaturePolicyViolation(feature); + return false; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/execution_context/security_context.h b/third_party/blink/renderer/core/execution_context/security_context.h index 195a58d..f5c4ae9 100644 --- a/third_party/blink/renderer/core/execution_context/security_context.h +++ b/third_party/blink/renderer/core/execution_context/security_context.h
@@ -29,6 +29,7 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" +#include "third_party/blink/public/common/feature_policy/feature_policy.h" #include "third_party/blink/public/platform/web_insecure_request_policy.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/frame/sandbox_flags.h" @@ -47,6 +48,10 @@ using ParsedFeaturePolicy = std::vector<ParsedFeaturePolicyDeclaration>; +// Whether to report policy violations when checking whether a feature is +// enabled. +enum class ReportOptions { kReportOnFailure, kDoNotReport }; + namespace mojom { enum class IPAddressSpace : int32_t; } @@ -123,6 +128,16 @@ const ParsedFeaturePolicy& container_policy, const FeaturePolicy* parent_feature_policy); + // Tests whether the policy-controlled feature is enabled in this frame. + // Optionally sends a report to any registered reporting observers or + // Report-To endpoints, via ReportFeaturePolicyViolation(), if the feature is + // disabled. + bool IsFeatureEnabled( + mojom::FeaturePolicyFeature, + ReportOptions report_on_failure = ReportOptions::kDoNotReport) const; + virtual void ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature) const { + } + // Apply the sandbox flag. In addition, if the origin is not already opaque, // the origin is updated to a newly created unique opaque origin, setting the // potentially trustworthy bit from |is_potentially_trustworthy|.
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index f23aeb9f..c6c7154 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1570,6 +1570,14 @@ PageWidgetDelegate::Animate(*page_, last_frame_time); } +void WebViewImpl::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) { + if (!MainFrameImpl()) + return; + + MainFrameImpl()->GetFrame()->View()->RecordEndOfFrameMetrics( + frame_begin_time); +} + void WebViewImpl::UpdateLifecycle(LifecycleUpdate requested_update) { TRACE_EVENT0("blink", "WebViewImpl::updateAllLifecyclePhases"); if (!MainFrameImpl())
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h index 42be0ae..b1399b1 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.h +++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -116,6 +116,7 @@ void SetSuppressFrameRequestsWorkaroundFor704763Only(bool) override; void BeginFrame(base::TimeTicks last_frame_time) override; + void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override; void UpdateLifecycle(LifecycleUpdate requested_update) override; void UpdateAllLifecyclePhasesAndCompositeForTesting() override;
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn index 8b0e7cc..3bd04766 100644 --- a/third_party/blink/renderer/core/frame/BUILD.gn +++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -88,6 +88,8 @@ "local_frame.cc", "local_frame.h", "local_frame_client.h", + "local_frame_ukm_aggregator.cc", + "local_frame_ukm_aggregator.h", "local_frame_view.cc", "local_frame_view.h", "location.cc",
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc index 2ecc05c..c5a5b1b 100644 --- a/third_party/blink/renderer/core/frame/deprecation.cc +++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -746,7 +746,7 @@ return; // If the feature is allowed, don't log a warning. - if (frame->DeprecatedIsFeatureEnabled(feature)) + if (document.IsFeatureEnabled(feature)) return; // If the feature is disabled, log a warning but only if the request is from a
diff --git a/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc b/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc index 5fd0ecc..75ede52 100644 --- a/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc +++ b/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc
@@ -93,12 +93,10 @@ bool DeviceSingleWindowEventController::CheckPolicyFeatures( const Vector<mojom::FeaturePolicyFeature>& features) const { - LocalFrame* frame = GetDocument().GetFrame(); - if (!frame) - return false; + const Document& document = GetDocument(); return std::all_of(features.begin(), features.end(), - [frame](mojom::FeaturePolicyFeature feature) { - return frame->DeprecatedIsFeatureEnabled(feature); + [&document](mojom::FeaturePolicyFeature feature) { + return document.IsFeatureEnabled(feature); }); }
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc index 6e74b71..6d0f0ea 100644 --- a/third_party/blink/renderer/core/frame/frame.cc +++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -256,18 +256,15 @@ : UserGestureIndicator::ConsumeUserGesture(); } +bool Frame::DeprecatedIsFeatureEnabled( + mojom::FeaturePolicyFeature feature) const { + return GetSecurityContext()->IsFeatureEnabled(feature, + ReportOptions::kDoNotReport); +} + bool Frame::DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature feature, ReportOptions report_on_failure) const { - FeaturePolicy* feature_policy = GetSecurityContext()->GetFeaturePolicy(); - // The policy should always be initialized before checking it to ensure we - // properly inherit the parent policy. - DCHECK(feature_policy); - - if (feature_policy->IsFeatureEnabled(feature)) - return true; - if (report_on_failure == ReportOptions::kReportOnFailure) - DeprecatedReportFeaturePolicyViolation(feature); - return false; + return GetSecurityContext()->IsFeatureEnabled(feature, report_on_failure); } void Frame::SetOwner(FrameOwner* owner) {
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h index 9e2e1bf..ac602f8 100644 --- a/third_party/blink/renderer/core/frame/frame.h +++ b/third_party/blink/renderer/core/frame/frame.h
@@ -64,6 +64,7 @@ class Settings; class WindowProxy; class WindowProxyManager; +enum class ReportOptions; struct FrameLoadRequest; enum class FrameDetachType { kRemove, kSwap }; @@ -71,9 +72,6 @@ // Status of user gesture. enum class UserGestureStatus { kActive, kNone }; -// Whether to report policy violations when checking whether a feature is -// enabled. -enum class ReportOptions { kReportOnFailure, kDoNotReport }; // Frame is the base class of LocalFrame and RemoteFrame and should only contain // functionality shared between both. In particular, any method related to @@ -231,9 +229,9 @@ // Report-To endpoints, via ReportFeaturePolicyViolation(), if the feature is // disabled. // TODO(iclelland): Replace these with methods on SecurityContext/Document - bool DeprecatedIsFeatureEnabled( - mojom::FeaturePolicyFeature, - ReportOptions report_on_failure = ReportOptions::kDoNotReport) const; + bool DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature) const; + bool DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature, + ReportOptions report_on_failure) const; virtual void DeprecatedReportFeaturePolicyViolation( mojom::FeaturePolicyFeature) const {}
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 345caf6..c46f76f 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -62,7 +62,6 @@ #include "third_party/blink/renderer/core/frame/ad_tracker.h" #include "third_party/blink/renderer/core/frame/content_settings_client.h" #include "third_party/blink/renderer/core/frame/event_handler_registry.h" -#include "third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h" #include "third_party/blink/renderer/core/frame/frame_console.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" @@ -1443,25 +1442,7 @@ void LocalFrame::DeprecatedReportFeaturePolicyViolation( mojom::FeaturePolicyFeature feature) const { - if (!RuntimeEnabledFeatures::FeaturePolicyReportingEnabled()) - return; - const String& feature_name = GetNameForFeature(feature); - FeaturePolicyViolationReportBody* body = new FeaturePolicyViolationReportBody( - feature_name, "Feature policy violation", SourceLocation::Capture()); - Report* report = - new Report("feature-policy", GetDocument()->Url().GetString(), body); - ReportingContext::From(GetDocument())->QueueReport(report); - - bool is_null; - int line_number = body->lineNumber(is_null); - line_number = is_null ? 0 : line_number; - int column_number = body->columnNumber(is_null); - column_number = is_null ? 0 : column_number; - - // Send the feature policy violation report to the Reporting API. - GetReportingService()->QueueFeaturePolicyViolationReport( - GetDocument()->Url(), feature_name, "Feature policy violation", - body->sourceFile(), line_number, column_number); + GetSecurityContext()->ReportFeaturePolicyViolation(feature); } } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h index ef70673..f83a473d 100644 --- a/third_party/blink/renderer/core/frame/local_frame.h +++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -376,6 +376,8 @@ void DeprecatedReportFeaturePolicyViolation( mojom::FeaturePolicyFeature) const override; + const mojom::blink::ReportingServiceProxyPtr& GetReportingService() const; + private: friend class FrameNavigationDisabler; @@ -411,8 +413,6 @@ ukm::UkmRecorder* GetUkmRecorder() override; ukm::SourceId GetUkmSourceId() override; - const mojom::blink::ReportingServiceProxyPtr& GetReportingService() const; - std::unique_ptr<FrameScheduler> frame_scheduler_; // Holds all PauseSubresourceLoadingHandles allowing either |this| to delete
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc new file mode 100644 index 0000000..d967442 --- /dev/null +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.cc
@@ -0,0 +1,230 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h" + +#include "services/metrics/public/cpp/ukm_entry_builder.h" +#include "services/metrics/public/cpp/ukm_recorder.h" +#include "third_party/blink/renderer/platform/histogram.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +#include "third_party/blink/renderer/platform/wtf/time.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" + +namespace blink { + +LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer::ScopedUkmHierarchicalTimer( + LocalFrameUkmAggregator* aggregator, + size_t metric_index) + : aggregator_(aggregator), + metric_index_(metric_index), + start_time_(CurrentTimeTicks()) {} + +LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer::ScopedUkmHierarchicalTimer( + ScopedUkmHierarchicalTimer&& other) + : aggregator_(other.aggregator_), + metric_index_(other.metric_index_), + start_time_(other.start_time_) { + other.aggregator_ = nullptr; +} + +LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer:: + ~ScopedUkmHierarchicalTimer() { + if (aggregator_ && base::TimeTicks::IsHighResolution()) { + aggregator_->RecordSample(metric_index_, start_time_, CurrentTimeTicks()); + } +} + +LocalFrameUkmAggregator::LocalFrameUkmAggregator(int64_t source_id, + ukm::UkmRecorder* recorder) + : source_id_(source_id), + recorder_(recorder), + event_name_("Blink.UpdateTime"), + event_frequency_(TimeDelta::FromSeconds(30)), + last_flushed_time_(CurrentTimeTicks()) { + // Record average and worst case for the primary metric. + primary_metric_.worst_case_metric_name = "MainFrame.WorstCase"; + primary_metric_.average_metric_name = "MainFrame.Average"; + + // Define the UMA for the primary metric. + primary_metric_.uma_counter.reset( + new CustomCountHistogram("Blink.MainFrame.UpdateTime", 0, 10000000, 50)); + + // Set up the substrings to create the UMA names + const String uma_preamble = "Blink."; + const String uma_postscript = ".UpdateTime"; + const String uma_ratio_preamble = "Blink.MainFrame."; + const String uma_ratio_postscript = "Ratio"; + + // Set up sub-strings for the bucketed UMA metrics + Vector<String> threshold_substrings; + if (!bucket_thresholds_.size()) { + threshold_substrings.push_back(".All"); + } else { + threshold_substrings.push_back( + String::Format(".LessThan%lums", + (unsigned long)bucket_thresholds_[0].InMilliseconds())); + for (wtf_size_t i = 1; i < bucket_thresholds_.size(); ++i) { + threshold_substrings.push_back(String::Format( + ".%lumsTo%lums", + (unsigned long)bucket_thresholds_[i - 1].InMilliseconds(), + (unsigned long)bucket_thresholds_[i].InMilliseconds())); + } + threshold_substrings.push_back(String::Format( + ".MoreThan%lums", + (unsigned long)bucket_thresholds_[bucket_thresholds_.size() - 1] + .InMilliseconds())); + } + + // Populate all the sub-metrics. + absolute_metric_records_.ReserveInitialCapacity(kCount); + ratio_metric_records_.ReserveInitialCapacity(kCount); + for (unsigned i = 0; i < (unsigned)kCount; ++i) { + const auto& metric_name = metric_strings_[i]; + + // Absolute records report the absolute time for each metric, both + // average and worst case. They have an associated UMA too that we + // own and allocate here. + auto& absolute_record = absolute_metric_records_.emplace_back(); + absolute_record.worst_case_metric_name = metric_name; + absolute_record.worst_case_metric_name.append(".WorstCase"); + absolute_record.average_metric_name = metric_name; + absolute_record.average_metric_name.append(".Average"); + auto uma_name = uma_preamble; + uma_name.append(metric_name); + uma_name.append(uma_postscript); + absolute_record.uma_counter.reset( + new CustomCountHistogram(uma_name.Utf8().data(), 0, 10000000, 50)); + + // Ratio records report the ratio of each metric to the primary metric, + // average and worst case. UMA counters are also associated with the + // ratios and we allocate and own them here. + auto& ratio_record = ratio_metric_records_.emplace_back(); + ratio_record.worst_case_metric_name = metric_name; + ratio_record.worst_case_metric_name.append(".WorstCaseRatio"); + ratio_record.average_metric_name = metric_name; + ratio_record.average_metric_name.append(".AverageRatio"); + for (auto bucket_substring : threshold_substrings) { + String uma_name = uma_ratio_preamble; + uma_name.append(metric_name); + uma_name.append(uma_ratio_postscript); + uma_name.append(bucket_substring); + ratio_record.uma_counters_per_bucket.push_back( + std::make_unique<CustomCountHistogram>(uma_name.Utf8().data(), 0, + 10000000, 50)); + } + } +} + +LocalFrameUkmAggregator::~LocalFrameUkmAggregator() { + Flush(TimeTicks()); +} + +LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer +LocalFrameUkmAggregator::GetScopedTimer(size_t metric_index) { + return ScopedUkmHierarchicalTimer(this, metric_index); +} + +void LocalFrameUkmAggregator::RecordSample(size_t metric_index, + TimeTicks start, + TimeTicks end) { + TimeDelta duration = end - start; + + // Append the duration to the appropriate metrics record. + DCHECK_LT(metric_index, absolute_metric_records_.size()); + auto& record = absolute_metric_records_[metric_index]; + if (duration > record.worst_case_duration) + record.worst_case_duration = duration; + record.total_duration += duration; + ++record.sample_count; + + // Record the UMA + record.uma_counter->CountMicroseconds(duration); + + // Just record the duration for ratios. We compute the ratio later + // when we know the frame time. + ratio_metric_records_[metric_index].interval_duration += duration; +} + +void LocalFrameUkmAggregator::RecordPrimarySample(TimeTicks start, + TimeTicks end) { + FlushIfNeeded(end); + + TimeDelta duration = end - start; + + // Record UMA + primary_metric_.uma_counter->CountMicroseconds(duration); + + if (duration.is_zero()) + return; + + // Record primary time information + if (duration > primary_metric_.worst_case_duration) + primary_metric_.worst_case_duration = duration; + primary_metric_.total_duration += duration; + ++primary_metric_.sample_count; + + // Compute all the dependent metrics, after finding which bucket we're in + // for UMA data. + size_t bucket_index = bucket_thresholds_.size(); + for (size_t i = 0; i < bucket_index; ++i) { + if (duration < bucket_thresholds_[i]) { + bucket_index = i; + } + } + + for (auto& record : ratio_metric_records_) { + double ratio = + record.interval_duration.InMicrosecondsF() / duration.InMicrosecondsF(); + if (ratio > record.worst_case_ratio) + record.worst_case_ratio = ratio; + record.total_ratio += ratio; + ++record.sample_count; + record.uma_counters_per_bucket[bucket_index]->Count(floor(ratio * 100.0)); + record.interval_duration = TimeDelta(); + } + + has_data_ = true; +} + +void LocalFrameUkmAggregator::FlushIfNeeded(TimeTicks current_time) { + if (current_time >= last_flushed_time_ + event_frequency_) + Flush(current_time); +} + +void LocalFrameUkmAggregator::Flush(TimeTicks current_time) { + last_flushed_time_ = current_time; + if (!has_data_) + return; + DCHECK(primary_metric_.sample_count); + + ukm::UkmEntryBuilder builder(source_id_, event_name_.Utf8().data()); + builder.SetMetric(primary_metric_.worst_case_metric_name.Utf8().data(), + primary_metric_.worst_case_duration.InMicroseconds()); + builder.SetMetric(primary_metric_.average_metric_name.Utf8().data(), + primary_metric_.total_duration.InMicroseconds() / + static_cast<int64_t>(primary_metric_.sample_count)); + for (auto& record : absolute_metric_records_) { + if (record.sample_count == 0) + continue; + builder.SetMetric(record.worst_case_metric_name.Utf8().data(), + record.worst_case_duration.InMicroseconds()); + builder.SetMetric(record.average_metric_name.Utf8().data(), + record.total_duration.InMicroseconds() / + static_cast<int64_t>(record.sample_count)); + } + for (auto& record : ratio_metric_records_) { + if (record.sample_count == 0) + continue; + builder.SetMetric(record.worst_case_metric_name.Utf8().data(), + record.worst_case_ratio); + builder.SetMetric( + record.average_metric_name.Utf8().data(), + record.total_ratio / static_cast<float>(record.sample_count)); + record.reset(); + } + builder.Record(recorder_); + has_data_ = false; +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h new file mode 100644 index 0000000..546b61a5 --- /dev/null +++ b/third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h
@@ -0,0 +1,216 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LOCAL_FRAME_UKM_AGGREGATOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LOCAL_FRAME_UKM_AGGREGATOR_H_ + +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +#include "third_party/blink/renderer/platform/wtf/time.h" + +namespace ukm { +class UkmRecorder; +} + +namespace blink { +class CustomCountHistogram; + +// This class aggregaties and records time based UKM and UMA metrics +// for LocalFrameView. The simplest way to use it is via the +// SCOPED_UMA_AND_UKM_HIERARCHICAL_TIMER macro in LocalFrameView combined +// with LocalFrameView::RecordEndOfFrameMetrics. +// +// It takes the following constructor parameters: +// - source_id: UKM Source ID associated with the events. +// - recorder: UkmRecorder which will handle the events +// +// The aggregator manages all of the UKM and UMA names for LocalFrameView. +// It constructs and takes ownership the UMA counters when constructed +// itself. We do this to localize all UMA and UKM metrics in one place, so +// that adding a metric is localized to the cc file of this class, protected +// from errors that might arise when adding names in multiple places. +// +// After the aggregator is created, one can create ScopedUkmHierarchicalTimer +// objects that will measure the time, in microseconds, from creation until +// the object is destroyed for sub-metrics. When destroyed, it will record +// a sample into the aggregator and the current frame's accumulated time for +// that metric, and report UMA values. +// +// See the MetricNames enum below for the set of metrics recorded. Add an +// entry to that enum to add a new metric. +// +// When the primary timed execution completes, this aggregator stores the +// primary time and computes metrics that depend on it. The results are +// aggregated. UMA metrics are updated at this time. A UKM event is +// generated in one of two situations: +// - If a sample is added that lies in the next event frequency interval (this +// will generate an event for the previous interval) +// - If the aggregator is destroyed (this will generate an event for any +// remaining samples in the aggregator) +// +// Note that no event is generated if there were no primary samples in an +// interval. +// +// Sample usage (see also SCOPED_UMA_AND_UKM_HIERARCHICAL_TIMER): +// std::unique_ptr<UkmHierarchicalTimeAggregator> aggregator( +// new UkmHierarchicalTimeAggregator( +// GetSourceId(), +// GetUkmRecorder()); +// +// ... +// { +// auto timer = +// aggregator->GetScopedTimer(static_cast<size_t>( +// LocalFrameUkmAggregator::MetricNames::kMetric2)); +// ... +// } +// // At this point an sample for kMetric2 is recorded. +// ... +// // When the primary time completes +// aggregator->RecordPrimaryMetric(time_delta); +// // This records a primary sample and the sub-metrics that depend on it. +// // It may generate an event. +// ... +// // Destroying an aggregator will generate an event as well if there were +// // samples. +// aggregator.reset(); +// +// In the example above, the event name is "my_event". It will measure 14 +// metrics: +// "primary_metric.Average", "primary_metric.WorstCase", +// "sub_metric1.Average", "sub_metric1.WorstCase", +// "sub_metric2.Average", "sub_metric2.WorstCase", +// "sub_metric3.Average", "sub_metric3.WorstCase" +// "sub_metric1.AverageRatio", "sub_metric1.WorstCaseRatio", +// "sub_metric2.AverageRatio", "sub_metric2.WorstCaseRatio", +// "sub_metric3.AverageRatio", "sub_metric3.WorstCaseRation" +// +// It will report 13 UMA values: +// "primary_uma_counter", +// "sub_uma_metric1", "sub_uma_metric2", "sub_uma_metric3", +// "sub_uma_ratio1.LessThan1ms", "sub_uma_ratio1.1msTo5ms", +// "sub_uma_ratio1.MoreThan5ms", "sub_uma_ratio2.LessThan1ms", +// "sub_uma_ratio2.1msTo5ms", "sub_uma_ratio2.MoreThan5ms", +// "sub_uma_ratio3.LessThan1ms", "sub_uma_ratio3.1msTo5ms", +// "sub_uma_ratio3.MoreThan5ms" +// +// Note that these have to be specified in the appropriate ukm.xml file +// and histograms.xml file. Runtime errors indicate missing or mis-named +// metrics. +// +// If the source_id/recorder changes then a new +// UkmHierarchicalTimeAggregator has to be created. +class LocalFrameUkmAggregator { + public: + // Changing these values requires changing the names of metrics specified + // below. For every metric name added here, add an entry in the + // metric_strings_ array below. + enum { + kCompositing, + kCompositingCommit, + kIntersectionObservation, + kPaint, + kPrePaint, + kStyleAndLayout, + kCount + }; + + private: + // Add an entry in this arrray every time a new metric is added. + const String metric_strings_[kCount] = { + "Compositing", "CompositingCommit", "IntersectionObservation", + "Paint", "PrePaint", "StyleAndLayout"}; + + // Modify this array if the UMA ratio metrics should be bucketed in a + // different way. + const Vector<TimeDelta> bucket_thresholds_ = {TimeDelta::FromMilliseconds(1), + TimeDelta::FromMilliseconds(5)}; + + public: + // This class will start a timer upon creation, which will end when the + // object is destroyed. Upon destruction it will record a sample into the + // aggregator that created the scoped timer. It will also record an event + // into the histogram counter. + class ScopedUkmHierarchicalTimer { + public: + ScopedUkmHierarchicalTimer(ScopedUkmHierarchicalTimer&&); + ~ScopedUkmHierarchicalTimer(); + + private: + friend class LocalFrameUkmAggregator; + + ScopedUkmHierarchicalTimer(LocalFrameUkmAggregator*, size_t metric_index); + + LocalFrameUkmAggregator* aggregator_; + const size_t metric_index_; + const TimeTicks start_time_; + + DISALLOW_COPY_AND_ASSIGN(ScopedUkmHierarchicalTimer); + }; + + LocalFrameUkmAggregator(int64_t source_id, ukm::UkmRecorder*); + ~LocalFrameUkmAggregator(); + + // Create a scoped timer with the index of the metric. Note the index must + // correspond to the matching index in metric_names. + ScopedUkmHierarchicalTimer GetScopedTimer(size_t metric_index); + + // Record a primary sample, that also computes the ratios for the + // sub-metrics and may generate an event. + void RecordPrimarySample(TimeTicks start, TimeTicks end); + + private: + struct AbsoluteMetricRecord { + String worst_case_metric_name; + String average_metric_name; + std::unique_ptr<CustomCountHistogram> uma_counter; + TimeDelta total_duration; + TimeDelta worst_case_duration; + size_t sample_count = 0u; + + void reset() { + total_duration = TimeDelta(); + worst_case_duration = TimeDelta(); + sample_count = 0u; + } + }; + + struct RatioMetricRecord { + String worst_case_metric_name; + String average_metric_name; + Vector<std::unique_ptr<CustomCountHistogram>> uma_counters_per_bucket; + TimeDelta interval_duration; + double total_ratio; + double worst_case_ratio; + size_t sample_count; + + void reset() { + interval_duration = TimeDelta(); + total_ratio = 0; + worst_case_ratio = 0; + sample_count = 0u; + } + }; + + void RecordSample(size_t metric_index, TimeTicks start, TimeTicks end); + void FlushIfNeeded(TimeTicks current_time); + void Flush(TimeTicks current_time); + + const int64_t source_id_; + ukm::UkmRecorder* const recorder_; + const String event_name_; + const TimeDelta event_frequency_; + AbsoluteMetricRecord primary_metric_; + Vector<AbsoluteMetricRecord> absolute_metric_records_; + Vector<RatioMetricRecord> ratio_metric_records_; + TimeTicks last_flushed_time_; + + bool has_data_ = false; + + DISALLOW_COPY_AND_ASSIGN(LocalFrameUkmAggregator); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_LOCAL_FRAME_UKM_AGGREGATOR_H_
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 3101fa06..7f5033b 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -55,6 +55,7 @@ #include "third_party/blink/renderer/core/frame/link_highlights.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" +#include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h" #include "third_party/blink/renderer/core/frame/location.h" #include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h" #include "third_party/blink/renderer/core/frame/remote_frame.h" @@ -141,7 +142,6 @@ #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/scroll/scroll_alignment.h" #include "third_party/blink/renderer/platform/transforms/transform_state.h" -#include "third_party/blink/renderer/platform/ukm_time_aggregator.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/blink/renderer/platform/wtf/time.h" @@ -170,37 +170,23 @@ constexpr size_t kCssFragmentIdentifierPrefixLength = base::size(kCssFragmentIdentifierPrefix); -// Changing these values requires changing the names generated in -// EnsureUkmTimeAggregator(). -enum class UkmMetricNames { - kCompositing, - kCompositingCommit, - kIntersectionObservation, - kPaint, - kPrePaint, - kStyleAndLayout, - kCount -}; - } // namespace -// Defines an UMA and a UKM, recorded in microseconds equal to the duration of -// the current lexical scope after declaration of the macro. Example usage: +// Defines a UKM that is part of a hierarchical ukm, recorded in +// microseconds equal to the duration of the current lexical scope after +// declaration of the macro. Example usage: // // void LocalFrameView::DoExpensiveThing() { -// SCOPED_UMA_AND_UKM_TIMER(UmaName, kUkmEnumName); +// SCOPED_UMA_AND_UKM_TIMER(kUkmEnumName); // // Do computation of expensive thing // // } // -// |uma_name| should be the full name of an UMA defined -// in histograms.xml. |ukm_enum| should be an entry in UkmMetricNames -// (which in turn come from ukm.xml). -#define SCOPED_UMA_AND_UKM_TIMER(uma_name, ukm_enum) \ - DEFINE_STATIC_LOCAL_IMPL(CustomCountHistogram, scoped_uma_counter, \ - (uma_name, 0, 10000000, 50), false); \ - auto scoped_ukm_uma_timer = EnsureUkmTimeAggregator().GetScopedTimer( \ - static_cast<size_t>(ukm_enum), &scoped_uma_counter); +// |ukm_enum| should be an entry in LocalFrameUkmAggregator's enum of +// metric names (which in turn corresponds to names in from ukm.xml). +#define SCOPED_UMA_AND_UKM_TIMER(ukm_enum) \ + auto scoped_ukm_hierarchical_timer = \ + EnsureUkmAggregator().GetScopedTimer(static_cast<size_t>(ukm_enum)); using namespace HTMLNames; @@ -407,7 +393,7 @@ ClearPrintContext(); - ukm_time_aggregator_.reset(); + ukm_aggregator_.reset(); jank_tracker_->Dispose(); #if DCHECK_IS_ON() @@ -2263,6 +2249,11 @@ DocumentLifecycle::kLayoutClean); } +void LocalFrameView::RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) { + LocalFrameUkmAggregator& ukm_aggregator = EnsureUkmAggregator(); + ukm_aggregator.RecordPrimarySample(frame_begin_time, CurrentTimeTicks()); +} + void LocalFrameView::ScheduleVisualUpdateForPaintInvalidationIfNeeded() { LocalFrame& local_frame_root = GetFrame().LocalFrameRoot(); if (local_frame_root.View()->current_update_lifecycle_phases_target_state_ < @@ -2415,8 +2406,7 @@ if (target_state == DocumentLifecycle::kPaintClean) { TRACE_EVENT0("blink,benchmark", "LocalFrameView::UpdateViewportIntersectionsForSubtree"); - SCOPED_UMA_AND_UKM_TIMER("Blink.IntersectionObservation.UpdateTime", - UkmMetricNames::kIntersectionObservation); + SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kIntersectionObservation); UpdateViewportIntersectionsForSubtree(); } @@ -2533,8 +2523,7 @@ DCHECK(layout_view); if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) { - SCOPED_UMA_AND_UKM_TIMER("Blink.Compositing.UpdateTime", - UkmMetricNames::kCompositing); + SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kCompositing); layout_view->Compositor()->UpdateIfNeededRecursive(target_state); } else { ForAllNonThrottledLocalFrameViews([](LocalFrameView& frame_view) { @@ -2578,8 +2567,7 @@ }); { - SCOPED_UMA_AND_UKM_TIMER("Blink.PrePaint.UpdateTime", - UkmMetricNames::kPrePaint); + SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kPrePaint); PrePaintTreeWalk().WalkTree(*this); } @@ -2794,7 +2782,7 @@ void LocalFrameView::PaintTree() { TRACE_EVENT0("blink,benchmark", "LocalFrameView::paintTree"); - SCOPED_UMA_AND_UKM_TIMER("Blink.Paint.UpdateTime", UkmMetricNames::kPaint); + SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kPaint); DCHECK(GetFrame().IsLocalRoot()); @@ -2934,8 +2922,7 @@ paint_artifact_compositor_->RootLayer(), &GetFrame()); } - SCOPED_UMA_AND_UKM_TIMER("Blink.CompositingCommit.UpdateTime", - UkmMetricNames::kCompositingCommit); + SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kCompositingCommit); paint_artifact_compositor_->Update( paint_controller_->GetPaintArtifactShared(), composited_element_ids, @@ -2951,8 +2938,7 @@ } void LocalFrameView::UpdateStyleAndLayoutIfNeededRecursive() { - SCOPED_UMA_AND_UKM_TIMER("Blink.StyleAndLayout.UpdateTime", - UkmMetricNames::kStyleAndLayout); + SCOPED_UMA_AND_UKM_TIMER(LocalFrameUkmAggregator::kStyleAndLayout); UpdateStyleAndLayoutIfNeededRecursiveInternal(); } @@ -4443,18 +4429,13 @@ std::max<float>(1.0, GetChromeClient()->WindowToViewportScalar(1))); } -UkmTimeAggregator& LocalFrameView::EnsureUkmTimeAggregator() { - if (!ukm_time_aggregator_) { - ukm_time_aggregator_.reset(new UkmTimeAggregator( - "Blink.UpdateTime", frame_->GetDocument()->UkmSourceID(), - frame_->GetDocument()->UkmRecorder(), - // Note that changing the order or values of the following vector - // requires changing the UkmMetricNames enum. - {"Compositing", "CompositingCommit", "IntersectionObservation", "Paint", - "PrePaint", "StyleAndLayout"}, - TimeDelta::FromSeconds(30))); +LocalFrameUkmAggregator& LocalFrameView::EnsureUkmAggregator() { + if (!ukm_aggregator_) { + ukm_aggregator_.reset( + new LocalFrameUkmAggregator(frame_->GetDocument()->UkmSourceID(), + frame_->GetDocument()->UkmRecorder())); } - return *ukm_time_aggregator_; + return *ukm_aggregator_; } } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h index 75ef8d7..ee208c45 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.h +++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -86,7 +86,7 @@ class ScrollingCoordinatorContext; class TracedValue; class TransformState; -class UkmTimeAggregator; +class LocalFrameUkmAggregator; class WebPluginContainerImpl; struct AnnotatedRegionValue; struct IntrinsicSizingInfo; @@ -349,6 +349,9 @@ // desired state. bool UpdateLifecycleToLayoutClean(); + // Record any UMA and UKM metrics that depend on the end of a main frame. + void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time); + void ScheduleVisualUpdateForPaintInvalidationIfNeeded(); bool InvalidateViewportConstrainedObjects(); @@ -824,7 +827,7 @@ void LayoutFromRootObject(LayoutObject& root); - UkmTimeAggregator& EnsureUkmTimeAggregator(); + LocalFrameUkmAggregator& EnsureUkmAggregator(); LayoutSize size_; @@ -959,7 +962,7 @@ MainThreadScrollingReasons main_thread_scrolling_reasons_; - std::unique_ptr<UkmTimeAggregator> ukm_time_aggregator_; + std::unique_ptr<LocalFrameUkmAggregator> ukm_aggregator_; Member<PrintContext> print_context_;
diff --git a/third_party/blink/renderer/core/frame/reporting_context.h b/third_party/blink/renderer/core/frame/reporting_context.h index c60b9d77..9332439b 100644 --- a/third_party/blink/renderer/core/frame/reporting_context.h +++ b/third_party/blink/renderer/core/frame/reporting_context.h
@@ -29,6 +29,9 @@ // Returns the ReportingContext for an ExecutionContext. If one does not // already exist for the given context, one is created. static ReportingContext* From(ExecutionContext*); + static ReportingContext* From(const ExecutionContext* context) { + return ReportingContext::From(const_cast<ExecutionContext*>(context)); + } // Queues a report in all registered observers. void QueueReport(Report*);
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc index 16207dde..27558a3 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
@@ -38,32 +38,37 @@ } void WebViewFrameWidget::Resize(const WebSize& size) { - return web_view_->Resize(size); + web_view_->Resize(size); } void WebViewFrameWidget::ResizeVisualViewport(const WebSize& size) { - return web_view_->ResizeVisualViewport(size); + web_view_->ResizeVisualViewport(size); } void WebViewFrameWidget::DidEnterFullscreen() { - return web_view_->DidEnterFullscreen(); + web_view_->DidEnterFullscreen(); } void WebViewFrameWidget::DidExitFullscreen() { - return web_view_->DidExitFullscreen(); + web_view_->DidExitFullscreen(); } void WebViewFrameWidget::SetSuppressFrameRequestsWorkaroundFor704763Only( bool suppress_frame_requests) { - return web_view_->SetSuppressFrameRequestsWorkaroundFor704763Only( + web_view_->SetSuppressFrameRequestsWorkaroundFor704763Only( suppress_frame_requests); } void WebViewFrameWidget::BeginFrame(base::TimeTicks last_frame_time) { - return web_view_->BeginFrame(last_frame_time); + web_view_->BeginFrame(last_frame_time); +} + +void WebViewFrameWidget::RecordEndOfFrameMetrics( + base::TimeTicks frame_begin_time) { + web_view_->RecordEndOfFrameMetrics(frame_begin_time); } void WebViewFrameWidget::UpdateLifecycle(LifecycleUpdate requested_update) { - return web_view_->UpdateLifecycle(requested_update); + web_view_->UpdateLifecycle(requested_update); } void WebViewFrameWidget::UpdateAllLifecyclePhasesAndCompositeForTesting() { @@ -72,20 +77,20 @@ void WebViewFrameWidget::PaintContent(cc::PaintCanvas* canvas, const WebRect& view_port) { - return web_view_->PaintContent(canvas, view_port); + web_view_->PaintContent(canvas, view_port); } void WebViewFrameWidget::LayoutAndPaintAsync(base::OnceClosure callback) { - return web_view_->LayoutAndPaintAsync(std::move(callback)); + web_view_->LayoutAndPaintAsync(std::move(callback)); } void WebViewFrameWidget::CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) { - return web_view_->CompositeAndReadbackAsync(std::move(callback)); + web_view_->CompositeAndReadbackAsync(std::move(callback)); } void WebViewFrameWidget::ThemeChanged() { - return web_view_->ThemeChanged(); + web_view_->ThemeChanged(); } WebInputEventResult WebViewFrameWidget::HandleInputEvent( @@ -98,7 +103,7 @@ } void WebViewFrameWidget::SetCursorVisibilityState(bool is_visible) { - return web_view_->SetCursorVisibilityState(is_visible); + web_view_->SetCursorVisibilityState(is_visible); } void WebViewFrameWidget::ApplyViewportDeltas( @@ -107,24 +112,24 @@ const WebFloatSize& elastic_overscroll_delta, float scale_factor, float browser_controls_shown_ratio_delta) { - return web_view_->ApplyViewportDeltas( - visual_viewport_delta, layout_viewport_delta, elastic_overscroll_delta, - scale_factor, browser_controls_shown_ratio_delta); + web_view_->ApplyViewportDeltas(visual_viewport_delta, layout_viewport_delta, + elastic_overscroll_delta, scale_factor, + browser_controls_shown_ratio_delta); } void WebViewFrameWidget::RecordWheelAndTouchScrollingCount( bool has_scrolled_by_wheel, bool has_scrolled_by_touch) { - return web_view_->RecordWheelAndTouchScrollingCount(has_scrolled_by_wheel, - has_scrolled_by_touch); + web_view_->RecordWheelAndTouchScrollingCount(has_scrolled_by_wheel, + has_scrolled_by_touch); } void WebViewFrameWidget::MouseCaptureLost() { - return web_view_->MouseCaptureLost(); + web_view_->MouseCaptureLost(); } void WebViewFrameWidget::SetFocus(bool enable) { - return web_view_->SetFocus(enable); + web_view_->SetFocus(enable); } bool WebViewFrameWidget::SelectionBounds(WebRect& anchor, @@ -137,7 +142,7 @@ } void WebViewFrameWidget::WillCloseLayerTreeView() { - return web_view_->WillCloseLayerTreeView(); + web_view_->WillCloseLayerTreeView(); } SkColor WebViewFrameWidget::BackgroundColor() const { @@ -152,12 +157,12 @@ cc::BrowserControlsState constraints, cc::BrowserControlsState current, bool animate) { - return web_view_->UpdateBrowserControlsState(constraints, current, animate); + web_view_->UpdateBrowserControlsState(constraints, current, animate); } void WebViewFrameWidget::SetVisibilityState( mojom::PageVisibilityState visibility_state) { - return web_view_->SetVisibilityState(visibility_state, false); + web_view_->SetVisibilityState(visibility_state, false); } void WebViewFrameWidget::SetBackgroundColorOverride(SkColor color) { @@ -165,7 +170,7 @@ } void WebViewFrameWidget::ClearBackgroundColorOverride() { - return web_view_->ClearBackgroundColorOverride(); + web_view_->ClearBackgroundColorOverride(); } void WebViewFrameWidget::SetBaseBackgroundColorOverride(SkColor color) { @@ -173,7 +178,7 @@ } void WebViewFrameWidget::ClearBaseBackgroundColorOverride() { - return web_view_->ClearBaseBackgroundColorOverride(); + web_view_->ClearBaseBackgroundColorOverride(); } void WebViewFrameWidget::SetBaseBackgroundColor(SkColor color) {
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.h b/third_party/blink/renderer/core/frame/web_view_frame_widget.h index 16ee4b60..1659cf7e 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.h +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.h
@@ -48,6 +48,7 @@ void DidExitFullscreen() override; void SetSuppressFrameRequestsWorkaroundFor704763Only(bool) final; void BeginFrame(base::TimeTicks last_frame_time) override; + void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override; void UpdateLifecycle(LifecycleUpdate requested_update) override; void UpdateAllLifecyclePhasesAndCompositeForTesting() override; void PaintContent(cc::PaintCanvas*, const WebRect& view_port) override;
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc index c9c29c2..f3c1555 100644 --- a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc +++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
@@ -39,6 +39,7 @@ #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/viewport_data.h" #include "third_party/blink/renderer/core/html/cross_origin_attribute.h" +#include "third_party/blink/renderer/core/html/html_dimension.h" #include "third_party/blink/renderer/core/html/html_image_element.h" #include "third_party/blink/renderer/core/html/html_meta_element.h" #include "third_party/blink/renderer/core/html/link_rel_attribute.h" @@ -115,6 +116,15 @@ return media_query_evaluator.Eval(*media_queries); } +static bool IsDimensionSmallAndAbsoluteForLazyLoad( + const String& attribute_value) { + // Minimum height or width of the image to start lazyloading. + const unsigned kMinDimensionToLazyLoad = 10; + HTMLDimension dimension; + return ParseDimensionValue(attribute_value, dimension) && + dimension.IsAbsolute() && dimension.Value() <= kMinDimensionToLazyLoad; +} + class TokenPreloadScanner::StartTagScanner { STACK_ALLOCATED(); @@ -144,6 +154,8 @@ integrity_attr_set_(false), integrity_features_(features), lazyload_attr_set_to_off_(false), + width_attr_small_absolute_(false), + height_attr_small_absolute_(false), scanner_type_(scanner_type) { if (Match(tag_impl_, imgTag) || Match(tag_impl_, sourceTag)) { source_size_ = SizesAttributeParser(media_values_, String()).length(); @@ -273,7 +285,11 @@ request->SetNonce(nonce_); request->SetCharset(Charset()); request->SetDefer(defer_); - request->SetIsLazyloadAttrOff(lazyload_attr_set_to_off_); + + if (lazyload_attr_set_to_off_ || + (width_attr_small_absolute_ && height_attr_small_absolute_)) { + request->SetIsLazyloadImageDisabled(true); + } // The only link tags that should keep the integrity metadata are // stylesheets until crbug.com/677022 is resolved. @@ -343,6 +359,16 @@ RuntimeEnabledFeatures::LazyImageLoadingEnabled() && EqualIgnoringASCIICase(attribute_value, "off")) { lazyload_attr_set_to_off_ = true; + } else if (!width_attr_small_absolute_ && + Match(attribute_name, widthAttr) && + RuntimeEnabledFeatures::LazyImageLoadingEnabled()) { + width_attr_small_absolute_ = + IsDimensionSmallAndAbsoluteForLazyLoad(attribute_value); + } else if (!height_attr_small_absolute_ && + Match(attribute_name, heightAttr) && + RuntimeEnabledFeatures::LazyImageLoadingEnabled()) { + height_attr_small_absolute_ = + IsDimensionSmallAndAbsoluteForLazyLoad(attribute_value); } } @@ -637,6 +663,8 @@ IntegrityMetadataSet integrity_metadata_; SubresourceIntegrity::IntegrityFeatures integrity_features_; bool lazyload_attr_set_to_off_; + bool width_attr_small_absolute_; + bool height_attr_small_absolute_; TokenPreloadScanner::ScannerType scanner_type_; };
diff --git a/third_party/blink/renderer/core/html/parser/preload_request.cc b/third_party/blink/renderer/core/html/parser/preload_request.cc index d7c894a1..359310e5 100644 --- a/third_party/blink/renderer/core/html/parser/preload_request.cc +++ b/third_party/blink/renderer/core/html/parser/preload_request.cc
@@ -105,7 +105,8 @@ if (const auto* frame = document->Loader()->GetFrame()) { if (frame->IsClientLoFiAllowed(params.GetResourceRequest())) { params.SetClientLoFiPlaceholder(); - } else if (!is_lazyload_attr_off_ && frame->IsLazyLoadingImageAllowed()) { + } else if (!is_lazyload_image_disabled_ && + frame->IsLazyLoadingImageAllowed()) { params.SetAllowImagePlaceholder(); } }
diff --git a/third_party/blink/renderer/core/html/parser/preload_request.h b/third_party/blink/renderer/core/html/parser/preload_request.h index 28152a6..0bd0956 100644 --- a/third_party/blink/renderer/core/html/parser/preload_request.h +++ b/third_party/blink/renderer/core/html/parser/preload_request.h
@@ -121,8 +121,8 @@ return is_image_set_ == ResourceFetcher::kImageIsImageSet; } - void SetIsLazyloadAttrOff(bool is_lazyload_attr_off) { - is_lazyload_attr_off_ = is_lazyload_attr_off; + void SetIsLazyloadImageDisabled(bool is_lazyload_image_disable) { + is_lazyload_image_disabled_ = is_lazyload_image_disable; } private: @@ -153,7 +153,7 @@ referrer_source_(referrer_source), from_insertion_scanner_(false), is_image_set_(is_image_set), - is_lazyload_attr_off_(false) {} + is_lazyload_image_disabled_(false) {} KURL CompleteURL(Document*); @@ -176,7 +176,7 @@ IntegrityMetadataSet integrity_metadata_; bool from_insertion_scanner_; ResourceFetcher::IsImageSet is_image_set_; - bool is_lazyload_attr_off_; + bool is_lazyload_image_disabled_; }; typedef Vector<std::unique_ptr<PreloadRequest>> PreloadRequestStream;
diff --git a/third_party/blink/renderer/core/html/track/cue_timeline.h b/third_party/blink/renderer/core/html/track/cue_timeline.h index c7579cd..18869dd4 100644 --- a/third_party/blink/renderer/core/html/track/cue_timeline.h +++ b/third_party/blink/renderer/core/html/track/cue_timeline.h
@@ -8,7 +8,7 @@ #include "third_party/blink/renderer/core/html/track/text_track_cue.h" #include "third_party/blink/renderer/core/html/track/vtt/vtt_cue.h" #include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/pod_interval_tree.h" +#include "third_party/blink/renderer/platform/wtf/pod_interval_tree.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { @@ -22,7 +22,7 @@ // safe because CueTimeline and TextTrackCue are guaranteed to die at the same // time when the owner HTMLMediaElement dies. Thus the raw TextTrackCue* cannot // become stale pointers. -typedef PODIntervalTree<double, TextTrackCue*> CueIntervalTree; +typedef WTF::PODIntervalTree<double, TextTrackCue*> CueIntervalTree; typedef CueIntervalTree::IntervalType CueInterval; typedef Vector<CueInterval> CueList; @@ -82,19 +82,18 @@ Member<CueTimeline> cue_timeline_; }; +} // namespace blink + +namespace WTF { #ifndef NDEBUG // Template specializations required by PodIntervalTree in debug mode. template <> -struct ValueToString<double> { - static String ToString(const double value) { return String::Number(value); } -}; - -template <> -struct ValueToString<TextTrackCue*> { - static String ToString(TextTrackCue* const& cue) { return cue->ToString(); } +struct ValueToString<blink::TextTrackCue*> { + static String ToString(blink::TextTrackCue* const& cue) { + return cue->ToString(); + } }; #endif - -} // namespace blink +} #endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_TRACK_CUE_TIMELINE_H_
diff --git a/third_party/blink/renderer/core/input/mouse_event_manager.cc b/third_party/blink/renderer/core/input/mouse_event_manager.cc index a158527..7f030d4 100644 --- a/third_party/blink/renderer/core/input/mouse_event_manager.cc +++ b/third_party/blink/renderer/core/input/mouse_event_manager.cc
@@ -614,7 +614,7 @@ if (RuntimeEnabledFeatures::NoHoverAfterLayoutChangeEnabled() && update_hover_reason == MouseEventManager::UpdateHoverReason::kLayoutOrStyleChanged) { - frame_->GetEventHandler().ScheduleCursorUpdate(); + frame_->LocalFrameRoot().GetEventHandler().ScheduleCursorUpdate(); return; }
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl index a5a10da7..4d09e6d 100644 --- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl +++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -4870,6 +4870,10 @@ command addScriptToEvaluateOnNewDocument parameters string source + # If specified, creates an isolated world with the given name and evaluates given script in it. + # This world name will be used as the ExecutionContextDescription::name when the corresponding + # event is emitted. + experimental optional string worldName returns # Identifier of the added script. ScriptIdentifier identifier
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc index 2d55dfb5..d90a3946 100644 --- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -70,6 +70,8 @@ #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h" +#include "third_party/blink/renderer/platform/json/json_parser.h" +#include "third_party/blink/renderer/platform/json/json_values.h" #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h" #include "third_party/blink/renderer/platform/loader/fetch/resource.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" @@ -548,23 +550,29 @@ return Response::OK(); } -Response InspectorPageAgent::addScriptToEvaluateOnLoad(const String& source, - String* identifier) { +Response InspectorPageAgent::addScriptToEvaluateOnNewDocument( + const String& source, + Maybe<String> world_name, + String* identifier) { std::vector<WTF::String> keys = scripts_to_evaluate_on_load_.Keys(); auto result = std::max_element( keys.begin(), keys.end(), [](const WTF::String& a, const WTF::String& b) { return Decimal::FromString(a) < Decimal::FromString(b); }); if (result == keys.end()) { - scripts_to_evaluate_on_load_.Set(String::Number(1), source); + *identifier = String::Number(1); } else { - scripts_to_evaluate_on_load_.Set( - String::Number(Decimal::FromString(*result).ToDouble() + 1), source); + *identifier = String::Number(Decimal::FromString(*result).ToDouble() + 1); } + + std::unique_ptr<JSONObject> script = JSONObject::Create(); + script->SetString("source", source); + script->SetString("world_name", world_name.fromMaybe("")); + scripts_to_evaluate_on_load_.Set(*identifier, script->ToJSONString()); return Response::OK(); } -Response InspectorPageAgent::removeScriptToEvaluateOnLoad( +Response InspectorPageAgent::removeScriptToEvaluateOnNewDocument( const String& identifier) { if (scripts_to_evaluate_on_load_.Get(identifier).IsNull()) return Response::Error("Script not found"); @@ -572,15 +580,15 @@ return Response::OK(); } -Response InspectorPageAgent::addScriptToEvaluateOnNewDocument( - const String& source, - String* identifier) { - return addScriptToEvaluateOnLoad(source, identifier); +Response InspectorPageAgent::addScriptToEvaluateOnLoad(const String& source, + String* identifier) { + return addScriptToEvaluateOnNewDocument(source, Maybe<String>(""), + identifier); } -Response InspectorPageAgent::removeScriptToEvaluateOnNewDocument( +Response InspectorPageAgent::removeScriptToEvaluateOnLoad( const String& identifier) { - return removeScriptToEvaluateOnLoad(identifier); + return removeScriptToEvaluateOnNewDocument(identifier); } Response InspectorPageAgent::setLifecycleEventsEnabled(bool enabled) { @@ -843,10 +851,45 @@ return Decimal::FromString(a) < Decimal::FromString(b); }); + HashMap<String, int> world_id_by_name; for (const WTF::String& key : keys) { - const WTF::String& script = scripts_to_evaluate_on_load_.Get(key); - frame->GetScriptController().ExecuteScriptInMainWorld(script); + const String script = scripts_to_evaluate_on_load_.Get(key); + std::unique_ptr<JSONObject> object = JSONObject::From(ParseJSON(script)); + String source; + DCHECK(object->GetString("source", &source)); + String world_name; + DCHECK(object->GetString("world_name", &world_name)); + + if (world_name.IsEmpty()) { + frame->GetScriptController().ExecuteScriptInMainWorld(source); + continue; + } + + auto it = world_id_by_name.find(world_name); + int world_id = 0; + if (it != world_id_by_name.end()) { + world_id = it->value; + } else { + scoped_refptr<DOMWrapperWorld> world = + frame->GetScriptController().CreateNewInspectorIsolatedWorld( + world_name); + if (!world) + continue; + world_id = world->GetWorldId(); + world_id_by_name.Set(world_name, world_id); + + scoped_refptr<SecurityOrigin> security_origin = + frame->GetSecurityContext()->GetSecurityOrigin()->IsolatedCopy(); + security_origin->GrantUniversalAccess(); + DOMWrapperWorld::SetIsolatedWorldSecurityOrigin(world_id, + security_origin); + } + + v8::HandleScope handle_scope(V8PerIsolateData::MainThreadIsolate()); + frame->GetScriptController().ExecuteScriptInIsolatedWorld( + world_id, source, KURL(), kNotSharableCrossOrigin); } + if (!script_to_evaluate_on_load_once_.IsEmpty()) { frame->GetScriptController().ExecuteScriptInMainWorld( script_to_evaluate_on_load_once_);
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.h b/third_party/blink/renderer/core/inspector/inspector_page_agent.h index 7348b4d..f099ed6 100644 --- a/third_party/blink/renderer/core/inspector/inspector_page_agent.h +++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
@@ -115,6 +115,7 @@ const String& identifier) override; protocol::Response addScriptToEvaluateOnNewDocument( const String& source, + Maybe<String> world_name, String* identifier) override; protocol::Response removeScriptToEvaluateOnNewDocument( const String& identifier) override;
diff --git a/third_party/blink/renderer/core/layout/floating_objects.cc b/third_party/blink/renderer/core/layout/floating_objects.cc index befe3dd..2395bd9a 100644 --- a/third_party/blink/renderer/core/layout/floating_objects.cc +++ b/third_party/blink/renderer/core/layout/floating_objects.cc
@@ -323,7 +323,7 @@ FloatingObjects::FloatingObjects(const LayoutBlockFlow* layout_object, bool horizontal_writing_mode) - : placed_floats_tree_(kUninitializedTree), + : placed_floats_tree_(WTF::kUninitializedTree), left_objects_count_(0), right_objects_count_(0), horizontal_writing_mode_(horizontal_writing_mode), @@ -760,14 +760,18 @@ return false; } +} // namespace blink + +namespace WTF { #ifndef NDEBUG // These helpers are only used by the PODIntervalTree for debugging purposes. -String ValueToString<LayoutUnit>::ToString(const LayoutUnit value) { +String ValueToString<blink::LayoutUnit>::ToString( + const blink::LayoutUnit value) { return String::Number(value.ToFloat()); } -String ValueToString<FloatingObject*>::ToString( - const FloatingObject* floating_object) { +String ValueToString<blink::FloatingObject*>::ToString( + const blink::FloatingObject* floating_object) { return String::Format("%p (%gx%g %gx%g)", floating_object, floating_object->FrameRect().X().ToFloat(), floating_object->FrameRect().Y().ToFloat(), @@ -775,5 +779,4 @@ floating_object->FrameRect().MaxY().ToFloat()); } #endif - -} // namespace blink +} // namespace WTF
diff --git a/third_party/blink/renderer/core/layout/floating_objects.h b/third_party/blink/renderer/core/layout/floating_objects.h index 52afcd2..0eaa0ded 100644 --- a/third_party/blink/renderer/core/layout/floating_objects.h +++ b/third_party/blink/renderer/core/layout/floating_objects.h
@@ -28,9 +28,10 @@ #include <memory> #include "base/macros.h" #include "third_party/blink/renderer/platform/geometry/layout_rect.h" -#include "third_party/blink/renderer/platform/pod_free_list_arena.h" -#include "third_party/blink/renderer/platform/pod_interval_tree.h" +#include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/list_hash_set.h" +#include "third_party/blink/renderer/platform/wtf/pod_free_list_arena.h" +#include "third_party/blink/renderer/platform/wtf/pod_interval_tree.h" namespace blink { @@ -45,7 +46,7 @@ #ifndef NDEBUG // Used by the PODIntervalTree for debugging the FloatingObject. template <class> - friend struct ValueToString; + friend struct WTF::ValueToString; #endif // Note that Type uses bits so you can use FloatLeftRight as a mask to query @@ -186,9 +187,10 @@ FloatingObjectHashFunctions> FloatingObjectSet; typedef FloatingObjectSet::const_iterator FloatingObjectSetIterator; -typedef PODInterval<LayoutUnit, FloatingObject*> FloatingObjectInterval; -typedef PODIntervalTree<LayoutUnit, FloatingObject*> FloatingObjectTree; -typedef PODFreeListArena<PODRedBlackTree<FloatingObjectInterval>::Node> +typedef WTF::PODInterval<LayoutUnit, FloatingObject*> FloatingObjectInterval; +typedef WTF::PODIntervalTree<LayoutUnit, FloatingObject*> FloatingObjectTree; +typedef WTF::PODFreeListArena< + WTF::PODRedBlackTree<FloatingObjectInterval>::Node> IntervalArena; typedef HashMap<LayoutBox*, std::unique_ptr<FloatingObject>> LayoutBoxToFloatInfoMap; @@ -279,18 +281,20 @@ DISALLOW_COPY_AND_ASSIGN(FloatingObjects); }; +} // namespace blink + +namespace WTF { #ifndef NDEBUG // These structures are used by PODIntervalTree for debugging purposes. template <> -struct ValueToString<LayoutUnit> { - static String ToString(const LayoutUnit value); +struct ValueToString<blink::LayoutUnit> { + static String ToString(const blink::LayoutUnit value); }; template <> -struct ValueToString<FloatingObject*> { - static String ToString(const FloatingObject*); +struct ValueToString<blink::FloatingObject*> { + static String ToString(const blink::FloatingObject*); }; #endif - -} // namespace blink +} // namespace WTF #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_FLOATING_OBJECTS_H_
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index a978ab44..fc2c1af 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2113,7 +2113,7 @@ LayoutBoxModelObject* cb = ToLayoutBoxModelObject(Container()); LayoutUnit height = ContainingBlockLogicalHeightForPositioned(cb); - if (StyleRef().GetPosition() != EPosition::kAbsolute) + if (IsInFlowPositioned()) height -= cb->PaddingLogicalHeight(); return height; }
diff --git a/third_party/blink/renderer/core/layout/layout_fieldset.cc b/third_party/blink/renderer/core/layout/layout_fieldset.cc index d4089429..9209773 100644 --- a/third_party/blink/renderer/core/layout/layout_fieldset.cc +++ b/third_party/blink/renderer/core/layout/layout_fieldset.cc
@@ -37,6 +37,10 @@ void LayoutFieldset::ComputePreferredLogicalWidths() { LayoutBlockFlow::ComputePreferredLogicalWidths(); + // Size-contained elements don't consider their contents for preferred sizing. + if (ShouldApplySizeContainment()) + return; + if (LayoutBox* legend = FindInFlowLegend()) { int legend_min_width = legend->MinPreferredLogicalWidth().ToInt();
diff --git a/third_party/blink/renderer/core/layout/layout_flow_thread.h b/third_party/blink/renderer/core/layout/layout_flow_thread.h index 7a4c1d1..08d9403 100644 --- a/third_party/blink/renderer/core/layout/layout_flow_thread.h +++ b/third_party/blink/renderer/core/layout/layout_flow_thread.h
@@ -191,8 +191,9 @@ LayoutMultiColumnSetList multi_column_set_list_; - typedef PODInterval<LayoutUnit, LayoutMultiColumnSet*> MultiColumnSetInterval; - typedef PODIntervalTree<LayoutUnit, LayoutMultiColumnSet*> + typedef WTF::PODInterval<LayoutUnit, LayoutMultiColumnSet*> + MultiColumnSetInterval; + typedef WTF::PODIntervalTree<LayoutUnit, LayoutMultiColumnSet*> MultiColumnSetIntervalTree; class MultiColumnSetSearchAdapter { @@ -219,16 +220,18 @@ DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutFlowThread, IsLayoutFlowThread()); +} // namespace blink + +namespace WTF { // These structures are used by PODIntervalTree for debugging. #ifndef NDEBUG template <> -struct ValueToString<LayoutMultiColumnSet*> { - static String ToString(const LayoutMultiColumnSet* value) { +struct ValueToString<blink::LayoutMultiColumnSet*> { + static String ToString(const blink::LayoutMultiColumnSet* value) { return String::Format("%p", value); } }; #endif - -} // namespace blink +} // namespace WTF #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_FLOW_THREAD_H_
diff --git a/third_party/blink/renderer/core/layout/layout_view.h b/third_party/blink/renderer/core/layout/layout_view.h index 26deb9f..cf85e07 100644 --- a/third_party/blink/renderer/core/layout/layout_view.h +++ b/third_party/blink/renderer/core/layout/layout_view.h
@@ -30,7 +30,6 @@ #include "third_party/blink/renderer/core/layout/layout_state.h" #include "third_party/blink/renderer/core/scroll/scrollable_area.h" #include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/pod_free_list_arena.h" namespace blink {
diff --git a/third_party/blink/renderer/core/loader/image_loader.cc b/third_party/blink/renderer/core/loader/image_loader.cc index 5fdaf34..f7550a5 100644 --- a/third_party/blink/renderer/core/loader/image_loader.cc +++ b/third_party/blink/renderer/core/loader/image_loader.cc
@@ -38,6 +38,7 @@ #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/use_counter.h" #include "third_party/blink/renderer/core/html/cross_origin_attribute.h" +#include "third_party/blink/renderer/core/html/html_dimension.h" #include "third_party/blink/renderer/core/html/html_image_element.h" #include "third_party/blink/renderer/core/html/lazy_load_image_observer.h" #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h" @@ -61,6 +62,47 @@ namespace blink { +namespace { + +bool GetAbsoluteDimensionValue(const AtomicString& attribute_value, + double* value) { + HTMLDimension dimension; + if (ParseDimensionValue(attribute_value, dimension) && + dimension.IsAbsolute()) { + *value = dimension.Value(); + return true; + } + return false; +} + +bool IsLazyLoadingImageAllowed(const LocalFrame* frame, + HTMLImageElement* html_image) { + // Minimum width or height attribute of the image to start lazyloading. + const unsigned kMinDimensionToLazyLoad = 10; + + // Do not lazyload image elements created from javascript. + if (!html_image->ElementCreatedByParser()) + return false; + + if (EqualIgnoringASCIICase( + html_image->FastGetAttribute(HTMLNames::lazyloadAttr), "off")) + return false; + + // Avoid lazyloading if width and height attributes are small. This + // heuristic helps avoid double fetching tracking pixels. + double width, height; + if (GetAbsoluteDimensionValue(html_image->getAttribute(HTMLNames::widthAttr), + &width) && + GetAbsoluteDimensionValue(html_image->getAttribute(HTMLNames::heightAttr), + &height) && + width <= kMinDimensionToLazyLoad && height <= kMinDimensionToLazyLoad) { + return false; + } + return frame->IsLazyLoadingImageAllowed(); +} + +} // namespace + static ImageLoader::BypassMainWorldBehavior ShouldBypassMainWorldCSP( ImageLoader* loader) { DCHECK(loader); @@ -451,10 +493,7 @@ if (frame->IsClientLoFiAllowed(params.GetResourceRequest())) { params.SetClientLoFiPlaceholder(); } else if (auto* html_image = ToHTMLImageElementOrNull(GetElement())) { - if (html_image->ElementCreatedByParser() && - !EqualIgnoringASCIICase( - html_image->FastGetAttribute(HTMLNames::lazyloadAttr), "off") && - frame->IsLazyLoadingImageAllowed()) { + if (IsLazyLoadingImageAllowed(frame, html_image)) { params.SetAllowImagePlaceholder(); lazy_image_load_state_ = LazyImageLoadState::kDeferred; }
diff --git a/third_party/blink/renderer/core/loader/interactive_detector.h b/third_party/blink/renderer/core/loader/interactive_detector.h index 0347110..ce88419 100644 --- a/third_party/blink/renderer/core/loader/interactive_detector.h +++ b/third_party/blink/renderer/core/loader/interactive_detector.h
@@ -15,9 +15,9 @@ #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/pod_interval.h" #include "third_party/blink/renderer/platform/supplementable.h" #include "third_party/blink/renderer/platform/timer.h" +#include "third_party/blink/renderer/platform/wtf/pod_interval.h" namespace blink { @@ -140,8 +140,8 @@ }; // Stores sufficiently long quiet windows on main thread and network. - std::vector<PODInterval<TimeTicks>> main_thread_quiet_windows_; - std::vector<PODInterval<TimeTicks>> network_quiet_windows_; + std::vector<WTF::PODInterval<TimeTicks>> main_thread_quiet_windows_; + std::vector<WTF::PODInterval<TimeTicks>> network_quiet_windows_; // Start times of currently active main thread and network quiet windows. // Null TimeTicks values indicate main thread or network is not quiet at the
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc index 0eaab63..6f5f27e 100644 --- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc +++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.cc
@@ -24,9 +24,6 @@ } // namespace -constexpr TimeDelta FirstMeaningfulPaintDetector::kNetwork2QuietWindowTimeout; -constexpr TimeDelta FirstMeaningfulPaintDetector::kNetwork0QuietWindowTimeout; - FirstMeaningfulPaintDetector& FirstMeaningfulPaintDetector::From( Document& document) { return PaintTiming::From(document).GetFirstMeaningfulPaintDetector();
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h index 8c1c48d7..43af429 100644 --- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h +++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
@@ -57,13 +57,6 @@ kDeferFirstContentfulPaintNotSet }; - // The page is n-quiet if there are no more than n active network requests for - // this duration of time. - static constexpr TimeDelta kNetwork2QuietWindowTimeout = - TimeDelta::FromSecondsD(0.5); - static constexpr TimeDelta kNetwork0QuietWindowTimeout = - TimeDelta::FromSecondsD(0.5); - Document* GetDocument(); int ActiveConnections(); void ReportHistograms(); @@ -80,8 +73,6 @@ TimeTicks provisional_first_meaningful_paint_swap_; double max_significance_so_far_ = 0.0; double accumulated_significance_while_having_blank_text_ = 0.0; - TimeDelta network2_quiet_window_timeout_ = kNetwork2QuietWindowTimeout; - TimeDelta network0_quiet_window_timeout_ = kNetwork0QuietWindowTimeout; unsigned prev_layout_object_count_ = 0; bool seen_first_meaningful_paint_candidate_ = false; bool network0_quiet_reached_ = false;
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc index a4bd180..888ceb2 100644 --- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc +++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector_test.cc
@@ -103,13 +103,6 @@ protected: ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler> platform_; - - TimeDelta GetNetwork0QuietWindowTimeout() { - return FirstMeaningfulPaintDetector::kNetwork0QuietWindowTimeout; - } - TimeDelta GetNetwork2QuietWindowTimeout() { - return FirstMeaningfulPaintDetector::kNetwork2QuietWindowTimeout; - } }; TEST_F(FirstMeaningfulPaintDetectorTest, NoFirstPaint) {
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 1db6d50..9a2f9ce7 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
@@ -689,8 +689,7 @@ if (blend_mode != SkBlendMode::kSrcOver) return true; - float opacity = style.Opacity(); - if (opacity != 1.0f) + if (style.Opacity() != 1.0f || style.HasWillChangeOpacityHint()) return true; if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(style))
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc index 196a6985..de451e17 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -6302,4 +6302,24 @@ inner_properties->StickyTranslation()->GetStickyConstraint().is_sticky); } +TEST_P(PaintPropertyTreeBuilderTest, WillChangeOpacityInducesAnEffectNode) { + SetBodyInnerHTML(R"HTML( + <style>.transluscent { opacity: 0.5; }</style> + <div id="div" style="width:10px; height:10px; will-change: opacity;"></div> + )HTML"); + + const auto* properties = PaintPropertiesForElement("div"); + ASSERT_TRUE(properties); + ASSERT_TRUE(properties->Effect()); + EXPECT_FLOAT_EQ(properties->Effect()->Opacity(), 1.f); + + auto* div = GetDocument().getElementById("div"); + div->setAttribute(HTMLNames::classAttr, "transluscent"); + GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(); + EXPECT_FALSE(ToLayoutBox(div->GetLayoutObject())->Layer()->NeedsRepaint()); + + ASSERT_TRUE(properties->Effect()); + EXPECT_FLOAT_EQ(properties->Effect()->Opacity(), 0.5f); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/replaced_painter.cc b/third_party/blink/renderer/core/paint/replaced_painter.cc index 71ca4b9..e9e153f70 100644 --- a/third_party/blink/renderer/core/paint/replaced_painter.cc +++ b/third_party/blink/renderer/core/paint/replaced_painter.cc
@@ -12,7 +12,6 @@ #include "third_party/blink/renderer/core/paint/object_painter.h" #include "third_party/blink/renderer/core/paint/paint_info.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" -#include "third_party/blink/renderer/core/paint/rounded_inner_rect_clipper.h" #include "third_party/blink/renderer/core/paint/scoped_paint_state.h" #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h" #include "third_party/blink/renderer/core/paint/selection_painting_utils.h"
diff --git a/third_party/blink/renderer/core/timing/event_timing.cc b/third_party/blink/renderer/core/timing/event_timing.cc index 5918016..589c2fa 100644 --- a/third_party/blink/renderer/core/timing/event_timing.cc +++ b/third_party/blink/renderer/core/timing/event_timing.cc
@@ -17,15 +17,15 @@ performance_ = DOMWindowPerformance::performance(*window); } -bool EventTiming::ShouldReportForEventTiming(const Event* event) const { - return (event->IsMouseEvent() || event->IsPointerEvent() || - event->IsTouchEvent() || event->IsKeyboardEvent() || - event->IsWheelEvent() || event->IsInputEvent() || - event->IsCompositionEvent()) && - event->isTrusted(); +bool EventTiming::ShouldReportForEventTiming(const Event& event) const { + return (event.IsMouseEvent() || event.IsPointerEvent() || + event.IsTouchEvent() || event.IsKeyboardEvent() || + event.IsWheelEvent() || event.IsInputEvent() || + event.IsCompositionEvent()) && + event.isTrusted(); } -void EventTiming::WillDispatchEvent(const Event* event) { +void EventTiming::WillDispatchEvent(const Event& event) { // Assume each event can be dispatched only once. DCHECK(!finished_will_dispatch_event_); if (!performance_ || !ShouldReportForEventTiming(event)) @@ -43,21 +43,20 @@ } } -void EventTiming::DidDispatchEvent(const Event* event) { +void EventTiming::DidDispatchEvent(const Event& event) { if (!finished_will_dispatch_event_ || - (!event->executedListenerOrDefaultAction() && !event->DefaultHandled())) { + (!event.executedListenerOrDefaultAction() && !event.DefaultHandled())) { return; } TimeTicks start_time; - if (event->IsPointerEvent()) - start_time = ToPointerEvent(event)->OldestPlatformTimeStamp(); + if (event.IsPointerEvent()) + start_time = ToPointerEvent(&event)->OldestPlatformTimeStamp(); else - start_time = event->PlatformTimeStamp(); + start_time = event.PlatformTimeStamp(); - performance_->RegisterEventTiming(event->type(), start_time, - processing_start_, CurrentTimeTicks(), - event->cancelable()); + performance_->RegisterEventTiming(event.type(), start_time, processing_start_, + CurrentTimeTicks(), event.cancelable()); } } // namespace blink
diff --git a/third_party/blink/renderer/core/timing/event_timing.h b/third_party/blink/renderer/core/timing/event_timing.h index 21216c94..59bacd8 100644 --- a/third_party/blink/renderer/core/timing/event_timing.h +++ b/third_party/blink/renderer/core/timing/event_timing.h
@@ -22,11 +22,11 @@ public: explicit EventTiming(LocalDOMWindow*); - void WillDispatchEvent(const Event*); - void DidDispatchEvent(const Event*); + void WillDispatchEvent(const Event&); + void DidDispatchEvent(const Event&); private: - bool ShouldReportForEventTiming(const Event* event) const; + bool ShouldReportForEventTiming(const Event& event) const; // The time the first event handler or default action started to execute. TimeTicks processing_start_; bool finished_will_dispatch_event_ = false;
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc index cf2477e..85abc9d 100644 --- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc +++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -746,9 +746,8 @@ if (!async_) { if (GetExecutionContext()->IsDocument() && - !GetDocument()->GetFrame()->DeprecatedIsFeatureEnabled( - mojom::FeaturePolicyFeature::kSyncXHR, - ReportOptions::kReportOnFailure)) { + !GetDocument()->IsFeatureEnabled(mojom::FeaturePolicyFeature::kSyncXHR, + ReportOptions::kReportOnFailure)) { LogConsoleError(GetExecutionContext(), "Synchronous requests are disabled by Feature Policy."); HandleNetworkError();
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js index 5cbd9bf2..21f7e5751 100644 --- a/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js +++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
@@ -629,7 +629,8 @@ return new Console.ConsoleCommandResult(message, this._linkifier, this._badgePool, nestingLevel); case SDK.ConsoleMessage.MessageType.StartGroupCollapsed: case SDK.ConsoleMessage.MessageType.StartGroup: - return new Console.ConsoleGroupViewMessage(message, this._linkifier, this._badgePool, nestingLevel); + return new Console.ConsoleGroupViewMessage( + message, this._linkifier, this._badgePool, nestingLevel, this._updateMessageList.bind(this)); default: return new Console.ConsoleViewMessage(message, this._linkifier, this._badgePool, nestingLevel); } @@ -869,13 +870,6 @@ this.focus(); } } - // TODO: fix this. - const groupMessage = event.target.enclosingNodeOrSelfWithClass('console-group-title'); - if (!groupMessage) - return; - const consoleGroupViewMessage = groupMessage.message; - consoleGroupViewMessage.setCollapsed(!consoleGroupViewMessage.collapsed()); - this._updateMessageList(); } /**
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js index dff95d6..22236b1 100644 --- a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js +++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
@@ -52,6 +52,9 @@ this._searchRegex = null; /** @type {?UI.Icon} */ this._messageLevelIcon = null; + this._traceExpanded = false; + /** @type {?function(boolean)} */ + this._expandTrace = null; } /** @@ -377,30 +380,28 @@ this._message.runtimeModel().target(), this._linkifier, this._message.stackTrace); stackTraceElement.appendChild(stackTracePreview); stackTraceElement.classList.add('hidden'); - - /** - * @param {boolean} expand - */ - function expandStackTrace(expand) { + this._expandTrace = expand => { icon.setIconType(expand ? 'smallicon-triangle-down' : 'smallicon-triangle-right'); stackTraceElement.classList.toggle('hidden', !expand); - } + this._traceExpanded = expand; + }; /** + * @this {!Console.ConsoleViewMessage} * @param {?Event} event */ function toggleStackTrace(event) { if (UI.isEditing() || contentElement.hasSelection()) return; - expandStackTrace(stackTraceElement.classList.contains('hidden')); + this._expandTrace(stackTraceElement.classList.contains('hidden')); event.consume(); } - clickableElement.addEventListener('click', toggleStackTrace, false); + clickableElement.addEventListener('click', toggleStackTrace.bind(this), false); if (this._message.type === SDK.ConsoleMessage.MessageType.Trace) - expandStackTrace(true); + this._expandTrace(true); - toggleElement._expandStackTraceForTest = expandStackTrace.bind(null, true); + toggleElement._expandStackTraceForTest = this._expandTrace.bind(this, true); return toggleElement; } @@ -1034,6 +1035,31 @@ } /** + * @param {!Event} event + */ + _onKeyDown(event) { + if (UI.isEditing() || !this._element.hasFocus() || this._element.hasSelection()) + return; + if (this.maybeHandleOnKeyDown(event)) + event.consume(true); + } + + /** + * @protected + * @param {!Event} event + */ + maybeHandleOnKeyDown(event) { + // Handle trace expansion. + if (this._expandTrace) { + if ((event.key === 'ArrowLeft' && this._traceExpanded) || (event.key === 'ArrowRight' && !this._traceExpanded)) { + this._expandTrace(!this._traceExpanded); + return true; + } + } + return false; + } + + /** * @return {!Element} */ contentElement() { @@ -1072,8 +1098,10 @@ return this._element; this._element = createElement('div'); - if (Runtime.experiments.isEnabled('consoleKeyboardNavigation')) + if (Runtime.experiments.isEnabled('consoleKeyboardNavigation')) { this._element.tabIndex = -1; + this._element.addEventListener('keydown', this._onKeyDown.bind(this)); + } this.updateMessageElement(); return this._element; } @@ -1496,22 +1524,25 @@ * @param {!Components.Linkifier} linkifier * @param {!ProductRegistry.BadgePool} badgePool * @param {number} nestingLevel + * @param {function()} onToggle */ - constructor(consoleMessage, linkifier, badgePool, nestingLevel) { + constructor(consoleMessage, linkifier, badgePool, nestingLevel, onToggle) { console.assert(consoleMessage.isGroupStartMessage()); super(consoleMessage, linkifier, badgePool, nestingLevel); this._collapsed = consoleMessage.type === SDK.ConsoleMessage.MessageType.StartGroupCollapsed; /** @type {?UI.Icon} */ this._expandGroupIcon = null; + this._onToggle = onToggle; } /** * @param {boolean} collapsed */ - setCollapsed(collapsed) { + _setCollapsed(collapsed) { this._collapsed = collapsed; if (this._expandGroupIcon) this._expandGroupIcon.setIconType(this._collapsed ? 'smallicon-triangle-right' : 'smallicon-triangle-down'); + this._onToggle.call(null); } /** @@ -1523,19 +1554,32 @@ /** * @override + * @param {!Event} event + */ + maybeHandleOnKeyDown(event) { + if ((event.key === 'ArrowLeft' && !this._collapsed) || (event.key === 'ArrowRight' && this._collapsed)) { + this._setCollapsed(!this._collapsed); + return true; + } + return super.maybeHandleOnKeyDown(event); + } + + /** + * @override * @return {!Element} */ toMessageElement() { if (!this._element) { super.toMessageElement(); - this._expandGroupIcon = UI.Icon.create('', 'expand-group-icon'); + const iconType = this._collapsed ? 'smallicon-triangle-right' : 'smallicon-triangle-down'; + this._expandGroupIcon = UI.Icon.create(iconType, 'expand-group-icon'); // Intercept focus to avoid highlight on click. this._contentElement.tabIndex = -1; if (this._repeatCountElement) this._repeatCountElement.insertBefore(this._expandGroupIcon, this._repeatCountElement.firstChild); else this._element.insertBefore(this._expandGroupIcon, this._contentElement); - this.setCollapsed(this._collapsed); + this._element.addEventListener('click', () => this._setCollapsed(!this._collapsed)); } return this._element; }
diff --git a/third_party/blink/renderer/devtools/front_end/console/consoleView.css b/third_party/blink/renderer/devtools/front_end/console/consoleView.css index 6116572..58ba943 100644 --- a/third_party/blink/renderer/devtools/front_end/console/consoleView.css +++ b/third_party/blink/renderer/devtools/front_end/console/consoleView.css
@@ -271,6 +271,7 @@ border-right: 1px solid #a5a5a5; position: relative; margin-bottom: -1px; + margin-top: -1px; } .console-message-wrapper:last-child .nesting-level-marker::before,
diff --git a/third_party/blink/renderer/devtools/front_end/externs.js b/third_party/blink/renderer/devtools/front_end/externs.js index 52658203..6f7fcbc3 100644 --- a/third_party/blink/renderer/devtools/front_end/externs.js +++ b/third_party/blink/renderer/devtools/front_end/externs.js
@@ -714,13 +714,6 @@ /** * @param {string} text * @param {Object.<string, boolean>} options - * @return {!ESTree.Node} - */ - parse_dammit: function(text, options) {}, - - /** - * @param {string} text - * @param {Object.<string, boolean>} options * @return {!Acorn.Tokenizer} */ tokenizer: function(text, options) {}, @@ -737,6 +730,15 @@ } }; +acorn.loose = {}; + +/** + * @param {string} text + * @param {Object.<string, boolean>} options + * @return {!ESTree.Node} + */ +acorn.loose.parse = function(text, options) {}; + const Acorn = {}; /** * @constructor
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/ESTreeWalker.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/ESTreeWalker.js index b33d334..6116972 100644 --- a/third_party/blink/renderer/devtools/front_end/formatter_worker/ESTreeWalker.js +++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/ESTreeWalker.js
@@ -96,6 +96,7 @@ 'ArrayPattern': ['elements'], 'ArrowFunctionExpression': ['params', 'body'], 'AssignmentExpression': ['left', 'right'], + 'AssignmentPattern': ['left', 'right'], 'BinaryExpression': ['left', 'right'], 'BlockStatement': ['body'], 'BreakStatement': ['label'], @@ -130,6 +131,7 @@ 'Property': ['key', 'value'], 'ReturnStatement': ['argument'], 'SequenceExpression': ['expressions'], + 'SpreadElement': ['argument'], 'Super': [], 'SwitchCase': ['test', 'consequent'], 'SwitchStatement': ['discriminant', 'cases'],
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js index 064e04c..d192c24 100644 --- a/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js +++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/FormatterWorker.js
@@ -151,11 +151,11 @@ * @param {string} content */ FormatterWorker.preprocessTopLevelAwaitExpressions = function(content) { - let wrapped = '(async () => {' + content + '})()'; + let wrapped = '(async () => {' + content + '\n})()'; let root; let body; try { - root = acorn.parse(wrapped, {ecmaVersion: 9}); + root = acorn.parse(wrapped, {ecmaVersion: 10}); body = root.body[0].expression.callee.body; } catch (e) { postMessage(''); @@ -185,6 +185,10 @@ AwaitExpression(node) { containsAwait = true; } + ForOfStatement(node) { + if (node.await) + containsAwait = true; + } ReturnStatement(node) { containsReturn = true; }
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js index 7648a92..7c45d38 100644 --- a/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js +++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/JavaScriptOutline.js
@@ -13,7 +13,7 @@ try { ast = acorn.parse(content, {ranges: false, ecmaVersion: 8}); } catch (e) { - ast = acorn.parse_dammit(content, {ranges: false, ecmaVersion: 8}); + ast = acorn.loose.parse(content, {ranges: false, ecmaVersion: 8}); } const textCursor = new TextUtils.TextCursor(content.computeLineEndings());
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn.js index b8e0efe..189c222 100644 --- a/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn.js +++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn.js
@@ -34,8 +34,8 @@ // code point above 128. // Generated by `bin/generate-identifier-regex.js`. -var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u08a0-\u08b4\u08b6-\u08bd\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312e\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fea\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ae\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"; -var nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d4-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1cf7-\u1cf9\u1dc0-\u1df9\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f"; +var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u08a0-\u08b4\u08b6-\u08bd\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fef\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7b9\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab65\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"; +var nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08d3-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1cf7-\u1cf9\u1dc0-\u1df9\u1dfb-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f"; var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); @@ -49,10 +49,10 @@ // generated by bin/generate-identifier-regex.js // eslint-disable-next-line comma-spacing -var astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,26,45,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,785,52,76,44,33,24,27,35,42,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,25,391,63,32,0,257,0,11,39,8,0,22,0,12,39,3,3,55,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,698,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,881,68,12,0,67,12,65,1,31,6124,20,754,9486,286,82,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,60,67,1213,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,15,7472,3104,541]; +var astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,477,28,11,0,9,21,190,52,76,44,33,24,27,35,30,0,12,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,26,230,43,117,63,32,0,257,0,11,39,8,0,22,0,12,39,3,3,20,0,35,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,270,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,689,63,129,68,12,0,67,12,65,1,31,6129,15,754,9486,286,82,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,60,67,1213,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,15,7472,3104,541]; // eslint-disable-next-line comma-spacing -var astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,1306,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,52,0,13,2,49,13,10,2,4,9,83,11,7,0,161,11,6,9,7,3,57,0,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,87,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,423,9,280,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,19719,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239]; +var astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,525,10,176,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,4,9,83,11,7,0,161,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,243,14,166,9,280,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,19306,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239]; // This has a complexity linear to the value of the code. The // assumption is that looking up astral identifier characters is @@ -251,8 +251,8 @@ var lineBreak = /\r\n?|\n|\u2028|\u2029/; var lineBreakG = new RegExp(lineBreak.source, "g"); -function isNewLine(code) { - return code === 10 || code === 13 || code === 0x2028 || code === 0x2029 +function isNewLine(code, ecma2019String) { + return code === 10 || code === 13 || (!ecma2019String && (code === 0x2028 || code === 0x2029)) } var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; @@ -314,11 +314,12 @@ // the parser process. These options are recognized: var defaultOptions = { - // `ecmaVersion` indicates the ECMAScript version to parse. Must - // be either 3, 5, 6 (2015), 7 (2016), or 8 (2017). This influences support - // for strict mode, the set of reserved words, and support for - // new syntax features. The default is 7. - ecmaVersion: 7, + // `ecmaVersion` indicates the ECMAScript version to parse. Must be + // either 3, 5, 6 (2015), 7 (2016), 8 (2017), 9 (2018), or 10 + // (2019). This influences support for strict mode, the set of + // reserved words, and support for new syntax features. The default + // is 9. + ecmaVersion: 9, // `sourceType` indicates the mode the code should be parsed in. // Can be either `"script"` or `"module"`. This influences global // strict mode and parsing of `import` and `export` declarations. @@ -343,6 +344,9 @@ // When enabled, import/export statements are not constrained to // appearing at the top of the program. allowImportExportEverywhere: false, + // When enabled, await identifiers are allowed to appear at the top-level scope, + // but they are still not allowed in non-async functions. + allowAwaitOutsideFunction: false, // When enabled, hashbang directive in the beginning of file // is allowed and treated as a line comment. allowHashBang: false, @@ -391,8 +395,7 @@ directSourceFile: null, // When enabled, parenthesized expressions are represented by // (non-standard) ParenthesizedExpression nodes - preserveParens: false, - plugins: {} + preserveParens: false }; // Interpret and default an options object @@ -435,8 +438,26 @@ } } -// Registered plugins -var plugins = {}; +// Each scope gets a bitset that may contain these flags +var SCOPE_TOP = 1; +var SCOPE_FUNCTION = 2; +var SCOPE_VAR = SCOPE_TOP | SCOPE_FUNCTION; +var SCOPE_ASYNC = 4; +var SCOPE_GENERATOR = 8; +var SCOPE_ARROW = 16; +var SCOPE_SIMPLE_CATCH = 32; + +function functionFlags(async, generator) { + return SCOPE_FUNCTION | (async ? SCOPE_ASYNC : 0) | (generator ? SCOPE_GENERATOR : 0) +} + +// Used in checkLVal and declareName to determine the type of a binding +var BIND_NONE = 0; +var BIND_VAR = 1; +var BIND_LEXICAL = 2; +var BIND_FUNCTION = 3; +var BIND_SIMPLE_CATCH = 4; +var BIND_OUTSIDE = 5; // Special case for function names as bound inside the function function keywordRegexp(words) { return new RegExp("^(?:" + words.replace(/ /g, "|") + ")$") @@ -450,7 +471,7 @@ if (!options.allowReserved) { for (var v = options.ecmaVersion;; v--) { if (reserved = reservedWords[v]) { break } } - if (options.sourceType == "module") { reserved += " await"; } + if (options.sourceType === "module") { reserved += " await"; } } this.reservedWords = keywordRegexp(reserved); var reservedStrict = (reserved ? reserved + " " : "") + reservedWords.strict; @@ -463,9 +484,6 @@ // escape sequences must not be interpreted as keywords. this.containsEsc = false; - // Load plugins - this.loadPlugins(options.plugins); - // Set up token state // The current position of the tokenizer in the input. @@ -506,8 +524,6 @@ // Used to signify the start of a potential arrow function this.potentialArrowAt = -1; - // Flags to track whether we are in a function, a generator, an async function. - this.inFunction = this.inGenerator = this.inAsync = false; // Positions to delayed-check that yield/await does not exist in default parameters. this.yieldPos = this.awaitPos = 0; // Labels in scope. @@ -519,29 +535,13 @@ // Scope tracking for duplicate variable names (see scope.js) this.scopeStack = []; - this.enterFunctionScope(); + this.enterScope(SCOPE_TOP); // For RegExp validation this.regexpState = null; }; -// DEPRECATED Kept for backwards compatibility until 3.0 in case a plugin uses them -Parser.prototype.isKeyword = function isKeyword (word) { return this.keywords.test(word) }; -Parser.prototype.isReservedWord = function isReservedWord (word) { return this.reservedWords.test(word) }; - -Parser.prototype.extend = function extend (name, f) { - this[name] = f(this[name]); -}; - -Parser.prototype.loadPlugins = function loadPlugins (pluginConfigs) { - var this$1 = this; - - for (var name in pluginConfigs) { - var plugin = plugins[name]; - if (!plugin) { throw new Error("Plugin '" + name + "' not found") } - plugin(this$1, pluginConfigs[name]); - } -}; +var prototypeAccessors = { inFunction: { configurable: true },inGenerator: { configurable: true },inAsync: { configurable: true } }; Parser.prototype.parse = function parse () { var node = this.options.program || this.startNode(); @@ -549,6 +549,35 @@ return this.parseTopLevel(node) }; +prototypeAccessors.inFunction.get = function () { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 }; +prototypeAccessors.inGenerator.get = function () { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 }; +prototypeAccessors.inAsync.get = function () { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 }; + +Parser.extend = function extend () { + var plugins = [], len = arguments.length; + while ( len-- ) plugins[ len ] = arguments[ len ]; + + var cls = this; + for (var i = 0; i < plugins.length; i++) { cls = plugins[i](cls); } + return cls +}; + +Parser.parse = function parse (input, options) { + return new this(options, input).parse() +}; + +Parser.parseExpressionAt = function parseExpressionAt (input, pos, options) { + var parser = new this(options, input, pos); + parser.nextToken(); + return parser.parseExpression() +}; + +Parser.tokenizer = function tokenizer (input, options) { + return new this(options, input) +}; + +Object.defineProperties( Parser.prototype, prototypeAccessors ); + var pp = Parser.prototype; // ## Parser utilities @@ -562,7 +591,7 @@ start += skipWhiteSpace.exec(this$1.input)[0].length; var match = literal.exec(this$1.input.slice(start)); if (!match) { return false } - if ((match[1] || match[2]) == "use strict") { return true } + if ((match[1] || match[2]) === "use strict") { return true } start += match[0].length; } }; @@ -623,7 +652,7 @@ }; pp.afterTrailingComma = function(tokType, notNext) { - if (this.type == tokType) { + if (this.type === tokType) { if (this.options.onTrailingComma) { this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc); } if (!notNext) @@ -701,7 +730,7 @@ var exports = {}; if (!node.body) { node.body = []; } while (this.type !== types.eof) { - var stmt = this$1.parseStatement(true, true, exports); + var stmt = this$1.parseStatement(null, true, exports); node.body.push(stmt); } this.adaptDirectivePrologue(node.body); @@ -720,7 +749,7 @@ skipWhiteSpace.lastIndex = this.pos; var skip = skipWhiteSpace.exec(this.input); var next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next); - if (nextCh === 91 || nextCh == 123) { return true } // '{' and '[' + if (nextCh === 91 || nextCh === 123) { return true } // '{' and '[' if (isIdentifierStart(nextCh, true)) { var pos = next + 1; while (isIdentifierChar(this.input.charCodeAt(pos), true)) { ++pos; } @@ -742,7 +771,7 @@ var next = this.pos + skip[0].length; return !lineBreak.test(this.input.slice(this.pos, next)) && this.input.slice(next, next + 8) === "function" && - (next + 8 == this.input.length || !isIdentifierChar(this.input.charAt(next + 8))) + (next + 8 === this.input.length || !isIdentifierChar(this.input.charAt(next + 8))) }; // Parse a single statement. @@ -752,7 +781,7 @@ // `if (foo) /blah/.exec(foo)`, where looking at the previous token // does not help. -pp$1.parseStatement = function(declaration, topLevel, exports) { +pp$1.parseStatement = function(context, topLevel, exports) { var starttype = this.type, node = this.startNode(), kind; if (this.isLet()) { @@ -770,10 +799,10 @@ case types._do: return this.parseDoStatement(node) case types._for: return this.parseForStatement(node) case types._function: - if (!declaration && this.options.ecmaVersion >= 6) { this.unexpected(); } - return this.parseFunctionStatement(node, false) + if ((context && (this.strict || context !== "if")) && this.options.ecmaVersion >= 6) { this.unexpected(); } + return this.parseFunctionStatement(node, false, !context) case types._class: - if (!declaration) { this.unexpected(); } + if (context) { this.unexpected(); } return this.parseClass(node, true) case types._if: return this.parseIfStatement(node) case types._return: return this.parseReturnStatement(node) @@ -782,11 +811,11 @@ case types._try: return this.parseTryStatement(node) case types._const: case types._var: kind = kind || this.value; - if (!declaration && kind != "var") { this.unexpected(); } + if (context && kind !== "var") { this.unexpected(); } return this.parseVarStatement(node, kind) case types._while: return this.parseWhileStatement(node) case types._with: return this.parseWithStatement(node) - case types.braceL: return this.parseBlock() + case types.braceL: return this.parseBlock(true, node) case types.semi: return this.parseEmptyStatement(node) case types._export: case types._import: @@ -805,14 +834,14 @@ // Identifier node, we switch to interpreting it as a label. default: if (this.isAsyncFunction()) { - if (!declaration) { this.unexpected(); } + if (context) { this.unexpected(); } this.next(); - return this.parseFunctionStatement(node, true) + return this.parseFunctionStatement(node, true, !context) } var maybeName = this.value, expr = this.parseExpression(); if (starttype === types.name && expr.type === "Identifier" && this.eat(types.colon)) - { return this.parseLabeledStatement(node, maybeName, expr) } + { return this.parseLabeledStatement(node, maybeName, expr, context) } else { return this.parseExpressionStatement(node, expr) } } }; @@ -820,7 +849,7 @@ pp$1.parseBreakContinueStatement = function(node, keyword) { var this$1 = this; - var isBreak = keyword == "break"; + var isBreak = keyword === "break"; this.next(); if (this.eat(types.semi) || this.insertSemicolon()) { node.label = null; } else if (this.type !== types.name) { this.unexpected(); } @@ -852,7 +881,7 @@ pp$1.parseDoStatement = function(node) { this.next(); this.labels.push(loopLabel); - node.body = this.parseStatement(false); + node.body = this.parseStatement("do"); this.labels.pop(); this.expect(types._while); node.test = this.parseParenExpression(); @@ -873,9 +902,9 @@ pp$1.parseForStatement = function(node) { this.next(); - var awaitAt = (this.options.ecmaVersion >= 9 && this.inAsync && this.eatContextual("await")) ? this.lastTokStart : -1; + var awaitAt = (this.options.ecmaVersion >= 9 && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction)) && this.eatContextual("await")) ? this.lastTokStart : -1; this.labels.push(loopLabel); - this.enterLexicalScope(); + this.enterScope(0); this.expect(types.parenL); if (this.type === types.semi) { if (awaitAt > -1) { this.unexpected(awaitAt); } @@ -917,17 +946,17 @@ return this.parseFor(node, init) }; -pp$1.parseFunctionStatement = function(node, isAsync) { +pp$1.parseFunctionStatement = function(node, isAsync, declarationPosition) { this.next(); - return this.parseFunction(node, true, false, isAsync) + return this.parseFunction(node, FUNC_STATEMENT | (declarationPosition ? 0 : FUNC_HANGING_STATEMENT), false, isAsync) }; pp$1.parseIfStatement = function(node) { this.next(); node.test = this.parseParenExpression(); // allow function declarations in branches, but only in non-strict mode - node.consequent = this.parseStatement(!this.strict && this.type == types._function); - node.alternate = this.eat(types._else) ? this.parseStatement(!this.strict && this.type == types._function) : null; + node.consequent = this.parseStatement("if"); + node.alternate = this.eat(types._else) ? this.parseStatement("if") : null; return this.finishNode(node, "IfStatement") }; @@ -953,14 +982,14 @@ node.cases = []; this.expect(types.braceL); this.labels.push(switchLabel); - this.enterLexicalScope(); + this.enterScope(0); // Statements under must be grouped (by label) in SwitchCase // nodes. `cur` is used to keep the node that we are currently // adding statements to. var cur; - for (var sawDefault = false; this.type != types.braceR;) { + for (var sawDefault = false; this.type !== types.braceR;) { if (this$1.type === types._case || this$1.type === types._default) { var isCase = this$1.type === types._case; if (cur) { this$1.finishNode(cur, "SwitchCase"); } @@ -977,10 +1006,10 @@ this$1.expect(types.colon); } else { if (!cur) { this$1.unexpected(); } - cur.consequent.push(this$1.parseStatement(true)); + cur.consequent.push(this$1.parseStatement(null)); } } - this.exitLexicalScope(); + this.exitScope(); if (cur) { this.finishNode(cur, "SwitchCase"); } this.next(); // Closing brace this.labels.pop(); @@ -1007,13 +1036,19 @@ if (this.type === types._catch) { var clause = this.startNode(); this.next(); - this.expect(types.parenL); - clause.param = this.parseBindingAtom(); - this.enterLexicalScope(); - this.checkLVal(clause.param, "let"); - this.expect(types.parenR); + if (this.eat(types.parenL)) { + clause.param = this.parseBindingAtom(); + var simple = clause.param.type === "Identifier"; + this.enterScope(simple ? SCOPE_SIMPLE_CATCH : 0); + this.checkLVal(clause.param, simple ? BIND_SIMPLE_CATCH : BIND_LEXICAL); + this.expect(types.parenR); + } else { + if (this.options.ecmaVersion < 10) { this.unexpected(); } + clause.param = null; + this.enterScope(0); + } clause.body = this.parseBlock(false); - this.exitLexicalScope(); + this.exitScope(); node.handler = this.finishNode(clause, "CatchClause"); } node.finalizer = this.eat(types._finally) ? this.parseBlock() : null; @@ -1033,7 +1068,7 @@ this.next(); node.test = this.parseParenExpression(); this.labels.push(loopLabel); - node.body = this.parseStatement(false); + node.body = this.parseStatement("while"); this.labels.pop(); return this.finishNode(node, "WhileStatement") }; @@ -1042,7 +1077,7 @@ if (this.strict) { this.raise(this.start, "'with' in strict mode"); } this.next(); node.object = this.parseParenExpression(); - node.body = this.parseStatement(false); + node.body = this.parseStatement("with"); return this.finishNode(node, "WithStatement") }; @@ -1051,7 +1086,7 @@ return this.finishNode(node, "EmptyStatement") }; -pp$1.parseLabeledStatement = function(node, maybeName, expr) { +pp$1.parseLabeledStatement = function(node, maybeName, expr, context) { var this$1 = this; for (var i$1 = 0, list = this$1.labels; i$1 < list.length; i$1 += 1) @@ -1064,17 +1099,17 @@ var kind = this.type.isLoop ? "loop" : this.type === types._switch ? "switch" : null; for (var i = this.labels.length - 1; i >= 0; i--) { var label$1 = this$1.labels[i]; - if (label$1.statementStart == node.start) { + if (label$1.statementStart === node.start) { // Update information about previous labels on this node label$1.statementStart = this$1.start; label$1.kind = kind; } else { break } } this.labels.push({name: maybeName, kind: kind, statementStart: this.start}); - node.body = this.parseStatement(true); - if (node.body.type == "ClassDeclaration" || - node.body.type == "VariableDeclaration" && node.body.kind != "var" || - node.body.type == "FunctionDeclaration" && (this.strict || node.body.generator)) + node.body = this.parseStatement(context); + if (node.body.type === "ClassDeclaration" || + node.body.type === "VariableDeclaration" && node.body.kind !== "var" || + node.body.type === "FunctionDeclaration" && (this.strict || node.body.generator || node.body.async)) { this.raiseRecoverable(node.body.start, "Invalid labeled declaration"); } this.labels.pop(); node.label = expr; @@ -1091,23 +1126,19 @@ // strict"` declarations when `allowStrict` is true (used for // function bodies). -pp$1.parseBlock = function(createNewLexicalScope) { +pp$1.parseBlock = function(createNewLexicalScope, node) { var this$1 = this; if ( createNewLexicalScope === void 0 ) createNewLexicalScope = true; + if ( node === void 0 ) node = this.startNode(); - var node = this.startNode(); node.body = []; this.expect(types.braceL); - if (createNewLexicalScope) { - this.enterLexicalScope(); - } + if (createNewLexicalScope) { this.enterScope(0); } while (!this.eat(types.braceR)) { - var stmt = this$1.parseStatement(true); + var stmt = this$1.parseStatement(null); node.body.push(stmt); } - if (createNewLexicalScope) { - this.exitLexicalScope(); - } + if (createNewLexicalScope) { this.exitScope(); } return this.finishNode(node, "BlockStatement") }; @@ -1122,8 +1153,8 @@ this.expect(types.semi); node.update = this.type === types.parenR ? null : this.parseExpression(); this.expect(types.parenR); - this.exitLexicalScope(); - node.body = this.parseStatement(false); + this.exitScope(); + node.body = this.parseStatement("for"); this.labels.pop(); return this.finishNode(node, "ForStatement") }; @@ -1134,17 +1165,17 @@ pp$1.parseForIn = function(node, init) { var type = this.type === types._in ? "ForInStatement" : "ForOfStatement"; this.next(); - if (type == "ForInStatement") { + if (type === "ForInStatement") { if (init.type === "AssignmentPattern" || (init.type === "VariableDeclaration" && init.declarations[0].init != null && (this.strict || init.declarations[0].id.type !== "Identifier"))) { this.raise(init.start, "Invalid assignment in for-in loop head"); } } node.left = init; - node.right = type == "ForInStatement" ? this.parseExpression() : this.parseMaybeAssign(); + node.right = type === "ForInStatement" ? this.parseExpression() : this.parseMaybeAssign(); this.expect(types.parenR); - this.exitLexicalScope(); - node.body = this.parseStatement(false); + this.exitScope(); + node.body = this.parseStatement("for"); this.labels.pop(); return this.finishNode(node, type) }; @@ -1163,7 +1194,7 @@ decl.init = this$1.parseMaybeAssign(isFor); } else if (kind === "const" && !(this$1.type === types._in || (this$1.options.ecmaVersion >= 6 && this$1.isContextual("of")))) { this$1.unexpected(); - } else if (decl.id.type != "Identifier" && !(isFor && (this$1.type === types._in || this$1.isContextual("of")))) { + } else if (decl.id.type !== "Identifier" && !(isFor && (this$1.type === types._in || this$1.isContextual("of")))) { this$1.raise(this$1.lastTokEnd, "Complex binding patterns require an initialization value"); } else { decl.init = null; @@ -1176,47 +1207,43 @@ pp$1.parseVarId = function(decl, kind) { decl.id = this.parseBindingAtom(kind); - this.checkLVal(decl.id, kind, false); + this.checkLVal(decl.id, kind === "var" ? BIND_VAR : BIND_LEXICAL, false); }; +var FUNC_STATEMENT = 1; +var FUNC_HANGING_STATEMENT = 2; +var FUNC_NULLABLE_ID = 4; + // Parse a function declaration or literal (depending on the // `isStatement` parameter). -pp$1.parseFunction = function(node, isStatement, allowExpressionBody, isAsync) { +pp$1.parseFunction = function(node, statement, allowExpressionBody, isAsync) { this.initFunction(node); if (this.options.ecmaVersion >= 9 || this.options.ecmaVersion >= 6 && !isAsync) { node.generator = this.eat(types.star); } if (this.options.ecmaVersion >= 8) { node.async = !!isAsync; } - if (isStatement) { - node.id = isStatement === "nullableID" && this.type != types.name ? null : this.parseIdent(); - if (node.id) { - this.checkLVal(node.id, "var"); - } + if (statement & FUNC_STATEMENT) { + node.id = (statement & FUNC_NULLABLE_ID) && this.type !== types.name ? null : this.parseIdent(); + if (node.id && !(statement & FUNC_HANGING_STATEMENT)) + { this.checkLVal(node.id, this.inModule && !this.inFunction ? BIND_LEXICAL : BIND_FUNCTION); } } - var oldInGen = this.inGenerator, oldInAsync = this.inAsync, - oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction; - this.inGenerator = node.generator; - this.inAsync = node.async; + var oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos; this.yieldPos = 0; this.awaitPos = 0; - this.inFunction = true; - this.enterFunctionScope(); + this.enterScope(functionFlags(node.async, node.generator)); - if (!isStatement) - { node.id = this.type == types.name ? this.parseIdent() : null; } + if (!(statement & FUNC_STATEMENT)) + { node.id = this.type === types.name ? this.parseIdent() : null; } this.parseFunctionParams(node); this.parseFunctionBody(node, allowExpressionBody); - this.inGenerator = oldInGen; - this.inAsync = oldInAsync; this.yieldPos = oldYieldPos; this.awaitPos = oldAwaitPos; - this.inFunction = oldInFunc; - return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression") + return this.finishNode(node, (statement & FUNC_STATEMENT) ? "FunctionDeclaration" : "FunctionExpression") }; pp$1.parseFunctionParams = function(node) { @@ -1240,17 +1267,20 @@ classBody.body = []; this.expect(types.braceL); while (!this.eat(types.braceR)) { - var member = this$1.parseClassMember(classBody); - if (member && member.type === "MethodDefinition" && member.kind === "constructor") { - if (hadConstructor) { this$1.raise(member.start, "Duplicate constructor in the same class"); } - hadConstructor = true; + var element = this$1.parseClassElement(); + if (element) { + classBody.body.push(element); + if (element.type === "MethodDefinition" && element.kind === "constructor") { + if (hadConstructor) { this$1.raise(element.start, "Duplicate constructor in the same class"); } + hadConstructor = true; + } } } node.body = this.finishNode(classBody, "ClassBody"); return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") }; -pp$1.parseClassMember = function(classBody) { +pp$1.parseClassElement = function() { var this$1 = this; if (this.eat(types.semi)) { return null } @@ -1295,7 +1325,7 @@ } else if (method.static && key.type === "Identifier" && key.name === "prototype") { this.raise(key.start, "Classes may not have a static property named prototype"); } - this.parseClassMethod(classBody, method, isGenerator, isAsync); + this.parseClassMethod(method, isGenerator, isAsync); if (method.kind === "get" && method.value.params.length !== 0) { this.raiseRecoverable(method.value.start, "getter should have no params"); } if (method.kind === "set" && method.value.params.length !== 1) @@ -1305,9 +1335,9 @@ return method }; -pp$1.parseClassMethod = function(classBody, method, isGenerator, isAsync) { +pp$1.parseClassMethod = function(method, isGenerator, isAsync) { method.value = this.parseMethod(isGenerator, isAsync); - classBody.body.push(this.finishNode(method, "MethodDefinition")); + return this.finishNode(method, "MethodDefinition") }; pp$1.parseClassId = function(node, isStatement) { @@ -1339,7 +1369,7 @@ var fNode = this.startNode(); this.next(); if (isAsync) { this.next(); } - node.declaration = this.parseFunction(fNode, "nullableID", false, isAsync); + node.declaration = this.parseFunction(fNode, FUNC_STATEMENT | FUNC_NULLABLE_ID, false, isAsync, true); } else if (this.type === types._class) { var cNode = this.startNode(); node.declaration = this.parseClass(cNode, "nullableID"); @@ -1351,7 +1381,7 @@ } // export var|const|let|function|class ... if (this.shouldParseExportStatement()) { - node.declaration = this.parseStatement(true); + node.declaration = this.parseStatement(null); if (node.declaration.type === "VariableDeclaration") { this.checkVariableExport(exports, node.declaration.declarations); } else @@ -1390,28 +1420,28 @@ var this$1 = this; var type = pat.type; - if (type == "Identifier") + if (type === "Identifier") { this.checkExport(exports, pat.name, pat.start); } - else if (type == "ObjectPattern") + else if (type === "ObjectPattern") { for (var i = 0, list = pat.properties; i < list.length; i += 1) { var prop = list[i]; this$1.checkPatternExport(exports, prop); } } - else if (type == "ArrayPattern") + else if (type === "ArrayPattern") { for (var i$1 = 0, list$1 = pat.elements; i$1 < list$1.length; i$1 += 1) { var elt = list$1[i$1]; if (elt) { this$1.checkPatternExport(exports, elt); } } } - else if (type == "Property") + else if (type === "Property") { this.checkPatternExport(exports, pat.value); } - else if (type == "AssignmentPattern") + else if (type === "AssignmentPattern") { this.checkPatternExport(exports, pat.left); } - else if (type == "RestElement") + else if (type === "RestElement") { this.checkPatternExport(exports, pat.argument); } - else if (type == "ParenthesizedExpression") + else if (type === "ParenthesizedExpression") { this.checkPatternExport(exports, pat.expression); } }; @@ -1486,7 +1516,7 @@ // import defaultObj, { x, y as z } from '...' var node = this.startNode(); node.local = this.parseIdent(); - this.checkLVal(node.local, "let"); + this.checkLVal(node.local, BIND_LEXICAL); nodes.push(this.finishNode(node, "ImportDefaultSpecifier")); if (!this.eat(types.comma)) { return nodes } } @@ -1495,7 +1525,7 @@ this.next(); this.expectContextual("as"); node$1.local = this.parseIdent(); - this.checkLVal(node$1.local, "let"); + this.checkLVal(node$1.local, BIND_LEXICAL); nodes.push(this.finishNode(node$1, "ImportNamespaceSpecifier")); return nodes } @@ -1514,7 +1544,7 @@ this$1.checkUnreserved(node$2.imported); node$2.local = node$2.imported; } - this$1.checkLVal(node$2.local, "let"); + this$1.checkLVal(node$2.local, BIND_LEXICAL); nodes.push(this$1.finishNode(node$2, "ImportSpecifier")); } return nodes @@ -1578,7 +1608,7 @@ break case "Property": - // AssignmentProperty has type == "Property" + // AssignmentProperty has type === "Property" if (node.kind !== "init") { this.raise(node.key.start, "Object pattern can't contain getter or setter"); } this.toAssignable(node.value, isBinding); break @@ -1729,6 +1759,7 @@ pp$2.checkLVal = function(expr, bindingType, checkClashes) { var this$1 = this; + if ( bindingType === void 0 ) bindingType = BIND_NONE; switch (expr.type) { case "Identifier": @@ -1739,19 +1770,7 @@ { this.raiseRecoverable(expr.start, "Argument name clash"); } checkClashes[expr.name] = true; } - if (bindingType && bindingType !== "none") { - if ( - bindingType === "var" && !this.canDeclareVarName(expr.name) || - bindingType !== "var" && !this.canDeclareLexicalName(expr.name) - ) { - this.raiseRecoverable(expr.start, ("Identifier '" + (expr.name) + "' has already been declared")); - } - if (bindingType === "var") { - this.declareVarName(expr.name); - } else { - this.declareLexicalName(expr.name); - } - } + if (bindingType !== BIND_NONE && bindingType !== BIND_OUTSIDE) { this.declareName(expr.name, bindingType, expr.start); } break case "MemberExpression": @@ -1768,7 +1787,7 @@ break case "Property": - // AssignmentProperty has type == "Property" + // AssignmentProperty has type === "Property" this.checkLVal(expr.value, bindingType, checkClashes); break @@ -1900,7 +1919,12 @@ // operators like `+=`. pp$3.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) { - if (this.inGenerator && this.isContextual("yield")) { return this.parseYield() } + if (this.isContextual("yield")) { + if (this.inGenerator) { return this.parseYield() } + // The tokenizer will assume an expression is allowed after + // `yield`, but this isn't that kind of yield + else { this.exprAllowed = false; } + } var ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1; if (refDestructuringErrors) { @@ -1913,7 +1937,7 @@ } var startPos = this.start, startLoc = this.startLoc; - if (this.type == types.parenL || this.type == types.name) + if (this.type === types.parenL || this.type === types.name) { this.potentialArrowAt = this.start; } var left = this.parseMaybeConditional(noIn, refDestructuringErrors); if (afterLeftParse) { left = afterLeftParse.call(this, left, startPos, startLoc); } @@ -1958,7 +1982,7 @@ var startPos = this.start, startLoc = this.startLoc; var expr = this.parseMaybeUnary(refDestructuringErrors, false); if (this.checkExpressionErrors(refDestructuringErrors)) { return expr } - return expr.start == startPos && expr.type === "ArrowFunctionExpression" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, noIn) + return expr.start === startPos && expr.type === "ArrowFunctionExpression" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, noIn) }; // Parse binary operators with the operator precedence parsing @@ -1997,7 +2021,7 @@ var this$1 = this; var startPos = this.start, startLoc = this.startLoc, expr; - if (this.inAsync && this.isContextual("await")) { + if (this.isContextual("await") && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction))) { expr = this.parseAwait(); sawUnary = true; } else if (this.type.prefix) { @@ -2052,7 +2076,7 @@ var this$1 = this; var maybeAsyncArrow = this.options.ecmaVersion >= 8 && base.type === "Identifier" && base.name === "async" && - this.lastTokEnd == base.end && !this.canInsertSemicolon() && this.input.slice(base.start, base.end) === "async"; + this.lastTokEnd === base.end && !this.canInsertSemicolon() && this.input.slice(base.start, base.end) === "async"; for (var computed = (void 0);;) { if ((computed = this$1.eat(types.bracketL)) || this$1.eat(types.dot)) { var node = this$1.startNodeAt(startPos, startLoc); @@ -2097,7 +2121,7 @@ // or `{}`. pp$3.parseExprAtom = function(refDestructuringErrors) { - var node, canBeArrow = this.potentialArrowAt == this.start; + var node, canBeArrow = this.potentialArrowAt === this.start; switch (this.type) { case types._super: if (!this.inFunction) @@ -2123,7 +2147,7 @@ var startPos = this.start, startLoc = this.startLoc, containsEsc = this.containsEsc; var id = this.parseIdent(this.type !== types.name); if (this.options.ecmaVersion >= 8 && !containsEsc && id.name === "async" && !this.canInsertSemicolon() && this.eat(types._function)) - { return this.parseFunction(this.startNodeAt(startPos, startLoc), false, false, true) } + { return this.parseFunction(this.startNodeAt(startPos, startLoc), 0, false, true) } if (canBeArrow && !this.canInsertSemicolon()) { if (this.eat(types.arrow)) { return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false) } @@ -2174,7 +2198,7 @@ case types._function: node = this.startNode(); this.next(); - return this.parseFunction(node, false) + return this.parseFunction(node, 0) case types._class: return this.parseClass(this.startNode(), false) @@ -2293,7 +2317,7 @@ node.property = this.parseIdent(true); if (node.property.name !== "target" || containsEsc) { this.raiseRecoverable(node.property.start, "The only valid meta property for new is new.target"); } - if (!this.inFunction) + if (!this.inNonArrowFunction()) { this.raiseRecoverable(node.start, "new.target can only be used in functions"); } return this.finishNode(node, "MetaProperty") } @@ -2340,6 +2364,7 @@ var curElt = this.parseTemplateElement({isTagged: isTagged}); node.quasis = [curElt]; while (!curElt.tail) { + if (this$1.type === types.eof) { this$1.raise(this$1.pos, "Unterminated template literal"); } this$1.expect(types.dollarBraceL); node.expressions.push(this$1.parseExpression()); this$1.expect(types.braceR); @@ -2442,7 +2467,7 @@ } else if (!isPattern && !containsEsc && this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" && (prop.key.name === "get" || prop.key.name === "set") && - (this.type != types.comma && this.type != types.braceR)) { + (this.type !== types.comma && this.type !== types.braceR)) { if (isGenerator || isAsync) { this.unexpected(); } prop.kind = prop.key.name; this.parsePropertyName(prop); @@ -2492,19 +2517,14 @@ pp$3.initFunction = function(node) { node.id = null; - if (this.options.ecmaVersion >= 6) { - node.generator = false; - node.expression = false; - } - if (this.options.ecmaVersion >= 8) - { node.async = false; } + if (this.options.ecmaVersion >= 6) { node.generator = node.expression = false; } + if (this.options.ecmaVersion >= 8) { node.async = false; } }; // Parse object or class method. pp$3.parseMethod = function(isGenerator, isAsync) { - var node = this.startNode(), oldInGen = this.inGenerator, oldInAsync = this.inAsync, - oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction; + var node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos; this.initFunction(node); if (this.options.ecmaVersion >= 6) @@ -2512,51 +2532,37 @@ if (this.options.ecmaVersion >= 8) { node.async = !!isAsync; } - this.inGenerator = node.generator; - this.inAsync = node.async; this.yieldPos = 0; this.awaitPos = 0; - this.inFunction = true; - this.enterFunctionScope(); + this.enterScope(functionFlags(isAsync, node.generator)); this.expect(types.parenL); node.params = this.parseBindingList(types.parenR, false, this.options.ecmaVersion >= 8); this.checkYieldAwaitInDefaultParams(); this.parseFunctionBody(node, false); - this.inGenerator = oldInGen; - this.inAsync = oldInAsync; this.yieldPos = oldYieldPos; this.awaitPos = oldAwaitPos; - this.inFunction = oldInFunc; return this.finishNode(node, "FunctionExpression") }; // Parse arrow function expression with given parameters. pp$3.parseArrowExpression = function(node, params, isAsync) { - var oldInGen = this.inGenerator, oldInAsync = this.inAsync, - oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction; + var oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos; - this.enterFunctionScope(); + this.enterScope(functionFlags(isAsync, false) | SCOPE_ARROW); this.initFunction(node); - if (this.options.ecmaVersion >= 8) - { node.async = !!isAsync; } + if (this.options.ecmaVersion >= 8) { node.async = !!isAsync; } - this.inGenerator = false; - this.inAsync = node.async; this.yieldPos = 0; this.awaitPos = 0; - this.inFunction = true; node.params = this.toAssignableList(params, true); this.parseFunctionBody(node, true); - this.inGenerator = oldInGen; - this.inAsync = oldInAsync; this.yieldPos = oldYieldPos; this.awaitPos = oldAwaitPos; - this.inFunction = oldInFunc; return this.finishNode(node, "ArrowFunctionExpression") }; @@ -2594,12 +2600,10 @@ this.adaptDirectivePrologue(node.body.body); this.labels = oldLabels; } - this.exitFunctionScope(); + this.exitScope(); - if (this.strict && node.id) { - // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval' - this.checkLVal(node.id, "none"); - } + // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval' + if (this.strict && node.id) { this.checkLVal(node.id, BIND_OUTSIDE); } this.strict = oldStrict; }; @@ -2624,7 +2628,7 @@ { var param = list[i]; - this$1.checkLVal(param, "var", allowDuplicates ? null : nameHash); + this$1.checkLVal(param, BIND_VAR, allowDuplicates ? null : nameHash); } }; @@ -2668,10 +2672,10 @@ { this.raiseRecoverable(start, "Can not use 'yield' as identifier inside a generator"); } if (this.inAsync && name === "await") { this.raiseRecoverable(start, "Can not use 'await' as identifier inside an async function"); } - if (this.isKeyword(name)) + if (this.keywords.test(name)) { this.raise(start, ("Unexpected keyword '" + name + "'")); } if (this.options.ecmaVersion < 6 && - this.input.slice(start, end).indexOf("\\") != -1) { return } + this.input.slice(start, end).indexOf("\\") !== -1) { return } var re = this.strict ? this.reservedWordsStrict : this.reservedWords; if (re.test(name)) { if (!this.inAsync && name === "await") @@ -2686,7 +2690,7 @@ pp$3.parseIdent = function(liberal, isBinding) { var node = this.startNode(); - if (liberal && this.options.allowReserved == "never") { liberal = false; } + if (liberal && this.options.allowReserved === "never") { liberal = false; } if (this.type === types.name) { node.name = this.value; } else if (this.type.keyword) { @@ -2716,7 +2720,7 @@ var node = this.startNode(); this.next(); - if (this.type == types.semi || this.canInsertSemicolon() || (this.type != types.star && !this.type.startsExpr)) { + if (this.type === types.semi || this.canInsertSemicolon() || (this.type !== types.star && !this.type.startsExpr)) { node.delegate = false; node.argument = null; } else { @@ -2761,79 +2765,69 @@ var pp$5 = Parser.prototype; -// Object.assign polyfill -var assign = Object.assign || function(target) { - var sources = [], len = arguments.length - 1; - while ( len-- > 0 ) sources[ len ] = arguments[ len + 1 ]; - - for (var i = 0, list = sources; i < list.length; i += 1) { - var source = list[i]; - - for (var key in source) { - if (has(source, key)) { - target[key] = source[key]; - } - } - } - return target +var Scope = function Scope(flags) { + this.flags = flags; + // A list of var-declared names in the current lexical scope + this.var = []; + // A list of lexically-declared names in the current lexical scope + this.lexical = []; }; // The functions in this module keep track of declared variables in the current scope in order to detect duplicate variable names. -pp$5.enterFunctionScope = function() { - // var: a hash of var-declared names in the current lexical scope - // lexical: a hash of lexically-declared names in the current lexical scope - // childVar: a hash of var-declared names in all child lexical scopes of the current lexical scope (within the current function scope) - // parentLexical: a hash of lexically-declared names in all parent lexical scopes of the current lexical scope (within the current function scope) - this.scopeStack.push({var: {}, lexical: {}, childVar: {}, parentLexical: {}}); +pp$5.enterScope = function(flags) { + this.scopeStack.push(new Scope(flags)); }; -pp$5.exitFunctionScope = function() { +pp$5.exitScope = function() { this.scopeStack.pop(); }; -pp$5.enterLexicalScope = function() { - var parentScope = this.scopeStack[this.scopeStack.length - 1]; - var childScope = {var: {}, lexical: {}, childVar: {}, parentLexical: {}}; +pp$5.declareName = function(name, bindingType, pos) { + var this$1 = this; - this.scopeStack.push(childScope); - assign(childScope.parentLexical, parentScope.lexical, parentScope.parentLexical); + var redeclared = false; + if (bindingType === BIND_LEXICAL) { + var scope = this.currentScope(); + redeclared = scope.lexical.indexOf(name) > -1 || scope.var.indexOf(name) > -1; + scope.lexical.push(name); + } else if (bindingType === BIND_SIMPLE_CATCH) { + var scope$1 = this.currentScope(); + scope$1.lexical.push(name); + } else if (bindingType === BIND_FUNCTION) { + var scope$2 = this.currentScope(); + redeclared = scope$2.lexical.indexOf(name) > -1; + scope$2.var.push(name); + } else { + for (var i = this.scopeStack.length - 1; i >= 0; --i) { + var scope$3 = this$1.scopeStack[i]; + if (scope$3.lexical.indexOf(name) > -1 && !(scope$3.flags & SCOPE_SIMPLE_CATCH) && scope$3.lexical[0] === name) { redeclared = true; } + scope$3.var.push(name); + if (scope$3.flags & SCOPE_VAR) { break } + } + } + if (redeclared) { this.raiseRecoverable(pos, ("Identifier '" + name + "' has already been declared")); } }; -pp$5.exitLexicalScope = function() { - var childScope = this.scopeStack.pop(); - var parentScope = this.scopeStack[this.scopeStack.length - 1]; - - assign(parentScope.childVar, childScope.var, childScope.childVar); +pp$5.currentScope = function() { + return this.scopeStack[this.scopeStack.length - 1] }; -/** - * A name can be declared with `var` if there are no variables with the same name declared with `let`/`const` - * in the current lexical scope or any of the parent lexical scopes in this function. - */ -pp$5.canDeclareVarName = function(name) { - var currentScope = this.scopeStack[this.scopeStack.length - 1]; +pp$5.currentVarScope = function() { + var this$1 = this; - return !has(currentScope.lexical, name) && !has(currentScope.parentLexical, name) + for (var i = this.scopeStack.length - 1;; i--) { + var scope = this$1.scopeStack[i]; + if (scope.flags & SCOPE_VAR) { return scope } + } }; -/** - * A name can be declared with `let`/`const` if there are no variables with the same name declared with `let`/`const` - * in the current scope, and there are no variables with the same name declared with `var` in the current scope or in - * any child lexical scopes in this function. - */ -pp$5.canDeclareLexicalName = function(name) { - var currentScope = this.scopeStack[this.scopeStack.length - 1]; +pp$5.inNonArrowFunction = function() { + var this$1 = this; - return !has(currentScope.lexical, name) && !has(currentScope.var, name) && !has(currentScope.childVar, name) -}; - -pp$5.declareVarName = function(name) { - this.scopeStack[this.scopeStack.length - 1].var[name] = true; -}; - -pp$5.declareLexicalName = function(name) { - this.scopeStack[this.scopeStack.length - 1].lexical[name] = true; + for (var i = this.scopeStack.length - 1; i >= 0; i--) + { if (this$1.scopeStack[i].flags & SCOPE_FUNCTION && !(this$1.scopeStack[i].flags & SCOPE_ARROW)) { return true } } + return false }; var Node = function Node(parser, pos, loc) { @@ -2923,13 +2917,13 @@ // The check for `tt.name && exprAllowed` detects whether we are // after a `yield` or `of` construct. See the `updateContext` for // `tt.name`. - if (prevType === types._return || prevType == types.name && this.exprAllowed) + if (prevType === types._return || prevType === types.name && this.exprAllowed) { return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) } - if (prevType === types._else || prevType === types.semi || prevType === types.eof || prevType === types.parenR || prevType == types.arrow) + if (prevType === types._else || prevType === types.semi || prevType === types.eof || prevType === types.parenR || prevType === types.arrow) { return true } - if (prevType == types.braceL) + if (prevType === types.braceL) { return parent === types$1.b_stat } - if (prevType == types._var || prevType == types.name) + if (prevType === types._var || prevType === types.name) { return false } return !this.exprAllowed }; @@ -2947,7 +2941,7 @@ pp$7.updateContext = function(prevType) { var update, type = this.type; - if (type.keyword && prevType == types.dot) + if (type.keyword && prevType === types.dot) { this.exprAllowed = false; } else if (update = type.updateContext) { update.call(this, prevType); } @@ -2958,7 +2952,7 @@ // Token-specific context update code types.parenR.updateContext = types.braceR.updateContext = function() { - if (this.context.length == 1) { + if (this.context.length === 1) { this.exprAllowed = true; return } @@ -3007,7 +3001,7 @@ }; types.star.updateContext = function(prevType) { - if (prevType == types._function) { + if (prevType === types._function) { var index = this.context.length - 1; if (this.context[index] === types$1.f_expr) { this.context[index] = types$1.f_expr_gen; } @@ -3019,9 +3013,9 @@ types.name.updateContext = function(prevType) { var allowed = false; - if (this.options.ecmaVersion >= 6) { - if (this.value == "of" && !this.exprAllowed || - this.value == "yield" && this.inGeneratorContext()) + if (this.options.ecmaVersion >= 6 && prevType !== types.dot) { + if (this.value === "of" && !this.exprAllowed || + this.value === "yield" && this.inGeneratorContext()) { allowed = true; } } this.exprAllowed = allowed; @@ -3590,7 +3584,7 @@ for (var i = 0; i < flags.length; i++) { var flag = flags.charAt(i); - if (validFlags.indexOf(flag) == -1) { + if (validFlags.indexOf(flag) === -1) { this$1.raise(state.start, "Invalid regular expression flag"); } if (flags.indexOf(flag, i + 1) > -1) { @@ -4756,7 +4750,7 @@ var tokentype = code === 42 ? types.star : types.modulo; // exponentiation operator ** and **= - if (this.options.ecmaVersion >= 7 && code == 42 && next === 42) { + if (this.options.ecmaVersion >= 7 && code === 42 && next === 42) { ++size; tokentype = types.starstar; next = this.input.charCodeAt(this.pos + 2); @@ -4782,7 +4776,7 @@ pp$8.readToken_plus_min = function(code) { // '+-' var next = this.input.charCodeAt(this.pos + 1); if (next === code) { - if (next == 45 && !this.inModule && this.input.charCodeAt(this.pos + 2) == 62 && + if (next === 45 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 62 && (this.lastTokEnd === 0 || lineBreak.test(this.input.slice(this.lastTokEnd, this.pos)))) { // A `-->` line comment this.skipLineComment(3); @@ -4803,8 +4797,8 @@ if (this.input.charCodeAt(this.pos + size) === 61) { return this.finishOp(types.assign, size + 1) } return this.finishOp(types.bitShift, size) } - if (next == 33 && code == 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) == 45 && - this.input.charCodeAt(this.pos + 3) == 45) { + if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 && + this.input.charCodeAt(this.pos + 3) === 45) { // `<!--`, an XML-style comment that should be interpreted as a line comment this.skipLineComment(4); this.skipSpace(); @@ -5038,7 +5032,7 @@ out += this$1.readEscapedChar(false); chunkStart = this$1.pos; } else { - if (isNewLine(ch)) { this$1.raise(this$1.start, "Unterminated string constant"); } + if (isNewLine(ch, this$1.options.ecmaVersion >= 10)) { this$1.raise(this$1.start, "Unterminated string constant"); } ++this$1.pos; } } @@ -5174,7 +5168,7 @@ } this.pos += octalStr.length - 1; ch = this.input.charCodeAt(this.pos); - if ((octalStr !== "0" || ch == 56 || ch == 57) && (this.strict || inTemplate)) { + if ((octalStr !== "0" || ch === 56 || ch === 57) && (this.strict || inTemplate)) { this.invalidStringToken( this.pos - 1 - octalStr.length, inTemplate @@ -5217,7 +5211,7 @@ this$1.containsEsc = true; word += this$1.input.slice(chunkStart, this$1.pos); var escStart = this$1.pos; - if (this$1.input.charCodeAt(++this$1.pos) != 117) // "u" + if (this$1.input.charCodeAt(++this$1.pos) !== 117) // "u" { this$1.invalidStringToken(this$1.pos, "Expecting Unicode escape sequence \\uXXXX"); } ++this$1.pos; var esc = this$1.readCodePoint(); @@ -5260,14 +5254,9 @@ // // [ghbt]: https://github.com/acornjs/acorn/issues // -// This file defines the main parser interface. The library also comes -// with a [error-tolerant parser][dammit] and an -// [abstract syntax tree walker][walk], defined in other files. -// -// [dammit]: acorn_loose.js // [walk]: util/walk.js -var version = "5.5.3"; +var version = "6.0.1"; // The main exported interface (under `self.acorn` when in the // browser) is a `parse` function that takes a code string and @@ -5277,7 +5266,7 @@ // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API function parse(input, options) { - return new Parser(options, input).parse() + return Parser.parse(input, options) } // This function tries to parse a single expression at a given @@ -5285,35 +5274,21 @@ // that embed JavaScript expressions. function parseExpressionAt(input, pos, options) { - var p = new Parser(options, input, pos); - p.nextToken(); - return p.parseExpression() + return Parser.parseExpressionAt(input, pos, options) } // Acorn is organized as a tokenizer and a recursive-descent parser. // The `tokenizer` export provides an interface to the tokenizer. function tokenizer(input, options) { - return new Parser(options, input) -} - -// This is a terrible kludge to support the existing, pre-ES6 -// interface where the loose parser module retroactively adds exports -// to this module. - // eslint-disable-line camelcase -function addLooseExports(parse, Parser$$1, plugins$$1) { - exports.parse_dammit = parse; // eslint-disable-line camelcase - exports.LooseParser = Parser$$1; - exports.pluginsLoose = plugins$$1; + return Parser.tokenizer(input, options) } exports.version = version; exports.parse = parse; exports.parseExpressionAt = parseExpressionAt; exports.tokenizer = tokenizer; -exports.addLooseExports = addLooseExports; exports.Parser = Parser; -exports.plugins = plugins; exports.defaultOptions = defaultOptions; exports.Position = Position; exports.SourceLocation = SourceLocation; @@ -5335,3 +5310,4 @@ Object.defineProperty(exports, '__esModule', { value: true }); }))); +// clang-format on
diff --git a/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn_loose.js b/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn_loose.js index 6f372da..5038bc17 100644 --- a/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn_loose.js +++ b/third_party/blink/renderer/devtools/front_end/formatter_worker/acorn/acorn_loose.js
@@ -1,37 +1,36 @@ // clang-format off (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./acorn')) : - typeof define === 'function' && define.amd ? define(['exports', './acorn'], factory) : - (factory((global.acorn = global.acorn || {}, global.acorn.loose = global.acorn.loose || {}),global.acorn)); -}(this, (function (exports,__acorn) { 'use strict'; + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('acorn')) : + typeof define === 'function' && define.amd ? define(['exports', 'acorn'], factory) : + (factory((global.acorn = global.acorn || {}, global.acorn.loose = {}),global.acorn)); +}(this, (function (exports,acorn) { 'use strict'; -// Registered plugins -var pluginsLoose = {} +function noop() {} var LooseParser = function LooseParser(input, options) { if ( options === void 0 ) options = {}; - this.toks = __acorn.tokenizer(input, options) - this.options = this.toks.options - this.input = this.toks.input - this.tok = this.last = {type: __acorn.tokTypes.eof, start: 0, end: 0} + this.toks = this.constructor.BaseParser.tokenizer(input, options); + this.options = this.toks.options; + this.input = this.toks.input; + this.tok = this.last = {type: acorn.tokTypes.eof, start: 0, end: 0}; + this.tok.validateRegExpFlags = noop; + this.tok.validateRegExpPattern = noop; if (this.options.locations) { - var here = this.toks.curPosition() - this.tok.loc = new __acorn.SourceLocation(this.toks, here, here) + var here = this.toks.curPosition(); + this.tok.loc = new acorn.SourceLocation(this.toks, here, here); } - this.ahead = [] // Tokens ahead - this.context = [] // Indentation contexted - this.curIndent = 0 - this.curLineStart = 0 - this.nextLineStart = this.lineEnd(this.curLineStart) + 1 - this.inAsync = false - // Load plugins - this.options.pluginsLoose = options.pluginsLoose || {} - this.loadPlugins(this.options.pluginsLoose) + this.ahead = []; // Tokens ahead + this.context = []; // Indentation contexted + this.curIndent = 0; + this.curLineStart = 0; + this.nextLineStart = this.lineEnd(this.curLineStart) + 1; + this.inAsync = false; + this.inFunction = false; }; LooseParser.prototype.startNode = function startNode () { - return new __acorn.Node(this.toks, this.tok.start, this.options.locations ? this.tok.loc.start : null) + return new acorn.Node(this.toks, this.tok.start, this.options.locations ? this.tok.loc.start : null) }; LooseParser.prototype.storeCurrentPos = function storeCurrentPos () { @@ -40,49 +39,49 @@ LooseParser.prototype.startNodeAt = function startNodeAt (pos) { if (this.options.locations) { - return new __acorn.Node(this.toks, pos[0], pos[1]) + return new acorn.Node(this.toks, pos[0], pos[1]) } else { - return new __acorn.Node(this.toks, pos) + return new acorn.Node(this.toks, pos) } }; LooseParser.prototype.finishNode = function finishNode (node, type) { - node.type = type - node.end = this.last.end + node.type = type; + node.end = this.last.end; if (this.options.locations) - node.loc.end = this.last.loc.end + { node.loc.end = this.last.loc.end; } if (this.options.ranges) - node.range[1] = this.last.end + { node.range[1] = this.last.end; } return node }; LooseParser.prototype.dummyNode = function dummyNode (type) { - var dummy = this.startNode() - dummy.type = type - dummy.end = dummy.start + var dummy = this.startNode(); + dummy.type = type; + dummy.end = dummy.start; if (this.options.locations) - dummy.loc.end = dummy.loc.start + { dummy.loc.end = dummy.loc.start; } if (this.options.ranges) - dummy.range[1] = dummy.start - this.last = {type: __acorn.tokTypes.name, start: dummy.start, end: dummy.start, loc: dummy.loc} + { dummy.range[1] = dummy.start; } + this.last = {type: acorn.tokTypes.name, start: dummy.start, end: dummy.start, loc: dummy.loc}; return dummy }; LooseParser.prototype.dummyIdent = function dummyIdent () { - var dummy = this.dummyNode("Identifier") - dummy.name = "✖" + var dummy = this.dummyNode("Identifier"); + dummy.name = "✖"; return dummy }; LooseParser.prototype.dummyString = function dummyString () { - var dummy = this.dummyNode("Literal") - dummy.value = dummy.raw = "✖" + var dummy = this.dummyNode("Literal"); + dummy.value = dummy.raw = "✖"; return dummy }; LooseParser.prototype.eat = function eat (type) { if (this.tok.type === type) { - this.next() + this.next(); return true } else { return false @@ -90,44 +89,44 @@ }; LooseParser.prototype.isContextual = function isContextual (name) { - return this.tok.type === __acorn.tokTypes.name && this.tok.value === name + return this.tok.type === acorn.tokTypes.name && this.tok.value === name }; LooseParser.prototype.eatContextual = function eatContextual (name) { - return this.tok.value === name && this.eat(__acorn.tokTypes.name) + return this.tok.value === name && this.eat(acorn.tokTypes.name) }; LooseParser.prototype.canInsertSemicolon = function canInsertSemicolon () { - return this.tok.type === __acorn.tokTypes.eof || this.tok.type === __acorn.tokTypes.braceR || - __acorn.lineBreak.test(this.input.slice(this.last.end, this.tok.start)) + return this.tok.type === acorn.tokTypes.eof || this.tok.type === acorn.tokTypes.braceR || + acorn.lineBreak.test(this.input.slice(this.last.end, this.tok.start)) }; LooseParser.prototype.semicolon = function semicolon () { - return this.eat(__acorn.tokTypes.semi) + return this.eat(acorn.tokTypes.semi) }; LooseParser.prototype.expect = function expect (type) { var this$1 = this; - if (this.eat(type)) return true + if (this.eat(type)) { return true } for (var i = 1; i <= 2; i++) { - if (this$1.lookAhead(i).type == type) { - for (var j = 0; j < i; j++) this$1.next() + if (this$1.lookAhead(i).type === type) { + for (var j = 0; j < i; j++) { this$1.next(); } return true } } }; LooseParser.prototype.pushCx = function pushCx () { - this.context.push(this.curIndent) + this.context.push(this.curIndent); }; LooseParser.prototype.popCx = function popCx () { - this.curIndent = this.context.pop() + this.curIndent = this.context.pop(); }; LooseParser.prototype.lineEnd = function lineEnd (pos) { - while (pos < this.input.length && !__acorn.isNewLine(this.input.charCodeAt(pos))) ++pos + while (pos < this.input.length && !acorn.isNewLine(this.input.charCodeAt(pos))) { ++pos; } return pos }; @@ -135,16 +134,16 @@ var this$1 = this; for (var count = 0;; ++pos) { - var ch = this$1.input.charCodeAt(pos) - if (ch === 32) ++count - else if (ch === 9) count += this$1.options.tabSize - else return count + var ch = this$1.input.charCodeAt(pos); + if (ch === 32) { ++count; } + else if (ch === 9) { count += this$1.options.tabSize; } + else { return count } } }; LooseParser.prototype.closes = function closes (closeTok, indent, line, blockHeuristic) { - if (this.tok.type === closeTok || this.tok.type === __acorn.tokTypes.eof) return true - return line != this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && + if (this.tok.type === closeTok || this.tok.type === acorn.tokTypes.eof) { return true } + return line !== this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && (!blockHeuristic || this.nextLineStart >= this.input.length || this.indentationAfter(this.nextLineStart) < indent) }; @@ -153,1068 +152,1110 @@ var this$1 = this; for (var p = this.tok.start - 1; p >= this.curLineStart; --p) { - var ch = this$1.input.charCodeAt(p) - if (ch !== 9 && ch !== 32) return false + var ch = this$1.input.charCodeAt(p); + if (ch !== 9 && ch !== 32) { return false } } return true }; LooseParser.prototype.extend = function extend (name, f) { - this[name] = f(this[name]) + this[name] = f(this[name]); }; -LooseParser.prototype.loadPlugins = function loadPlugins (pluginConfigs) { - var this$1 = this; - - for (var name in pluginConfigs) { - var plugin = pluginsLoose[name] - if (!plugin) throw new Error("Plugin '" + name + "' not found") - plugin(this$1, pluginConfigs[name]) - } +LooseParser.prototype.parse = function parse () { + this.next(); + return this.parseTopLevel() }; -var lp = LooseParser.prototype +LooseParser.extend = function extend () { + var plugins = [], len = arguments.length; + while ( len-- ) plugins[ len ] = arguments[ len ]; + + var cls = this; + for (var i = 0; i < plugins.length; i++) { cls = plugins[i](cls); } + return cls +}; + +LooseParser.parse = function parse (input, options) { + return new this(input, options).parse() +}; + +// Allows plugins to extend the base parser / tokenizer used +LooseParser.BaseParser = acorn.Parser; + +var lp = LooseParser.prototype; function isSpace(ch) { - return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || __acorn.isNewLine(ch) + return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || acorn.isNewLine(ch) } lp.next = function() { var this$1 = this; - this.last = this.tok + this.last = this.tok; if (this.ahead.length) - this.tok = this.ahead.shift() + { this.tok = this.ahead.shift(); } else - this.tok = this.readToken() + { this.tok = this.readToken(); } if (this.tok.start >= this.nextLineStart) { while (this.tok.start >= this.nextLineStart) { - this$1.curLineStart = this$1.nextLineStart - this$1.nextLineStart = this$1.lineEnd(this$1.curLineStart) + 1 + this$1.curLineStart = this$1.nextLineStart; + this$1.nextLineStart = this$1.lineEnd(this$1.curLineStart) + 1; } - this.curIndent = this.indentationAfter(this.curLineStart) + this.curIndent = this.indentationAfter(this.curLineStart); } -} +}; lp.readToken = function() { var this$1 = this; for (;;) { try { - this$1.toks.next() - if (this$1.toks.type === __acorn.tokTypes.dot && + this$1.toks.next(); + if (this$1.toks.type === acorn.tokTypes.dot && this$1.input.substr(this$1.toks.end, 1) === "." && this$1.options.ecmaVersion >= 6) { - this$1.toks.end++ - this$1.toks.type = __acorn.tokTypes.ellipsis + this$1.toks.end++; + this$1.toks.type = acorn.tokTypes.ellipsis; } - return new __acorn.Token(this$1.toks) + return new acorn.Token(this$1.toks) } catch (e) { - if (!(e instanceof SyntaxError)) throw e + if (!(e instanceof SyntaxError)) { throw e } // Try to skip some text, based on the error message, and then continue - var msg = e.message, pos = e.raisedAt, replace = true + var msg = e.message, pos = e.raisedAt, replace = true; if (/unterminated/i.test(msg)) { - pos = this$1.lineEnd(e.pos + 1) + pos = this$1.lineEnd(e.pos + 1); if (/string/.test(msg)) { - replace = {start: e.pos, end: pos, type: __acorn.tokTypes.string, value: this$1.input.slice(e.pos + 1, pos)} + replace = {start: e.pos, end: pos, type: acorn.tokTypes.string, value: this$1.input.slice(e.pos + 1, pos)}; } else if (/regular expr/i.test(msg)) { - var re = this$1.input.slice(e.pos, pos) - try { re = new RegExp(re) } catch (e) { /* ignore compilation error due to new syntax */ } - replace = {start: e.pos, end: pos, type: __acorn.tokTypes.regexp, value: re} + var re = this$1.input.slice(e.pos, pos); + try { re = new RegExp(re); } catch (e) { /* ignore compilation error due to new syntax */ } + replace = {start: e.pos, end: pos, type: acorn.tokTypes.regexp, value: re}; } else if (/template/.test(msg)) { replace = { start: e.pos, end: pos, - type: __acorn.tokTypes.template, + type: acorn.tokTypes.template, value: this$1.input.slice(e.pos, pos) - } + }; } else { - replace = false + replace = false; } } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number|expected number in radix/i.test(msg)) { - while (pos < this.input.length && !isSpace(this.input.charCodeAt(pos))) ++pos + while (pos < this.input.length && !isSpace(this.input.charCodeAt(pos))) { ++pos; } } else if (/character escape|expected hexadecimal/i.test(msg)) { while (pos < this.input.length) { - var ch = this$1.input.charCodeAt(pos++) - if (ch === 34 || ch === 39 || __acorn.isNewLine(ch)) break + var ch = this$1.input.charCodeAt(pos++); + if (ch === 34 || ch === 39 || acorn.isNewLine(ch)) { break } } } else if (/unexpected character/i.test(msg)) { - pos++ - replace = false + pos++; + replace = false; } else if (/regular expression/i.test(msg)) { - replace = true + replace = true; } else { throw e } - this$1.resetTo(pos) - if (replace === true) replace = {start: pos, end: pos, type: __acorn.tokTypes.name, value: "✖"} + this$1.resetTo(pos); + if (replace === true) { replace = {start: pos, end: pos, type: acorn.tokTypes.name, value: "✖"}; } if (replace) { if (this$1.options.locations) - replace.loc = new __acorn.SourceLocation( + { replace.loc = new acorn.SourceLocation( this$1.toks, - __acorn.getLineInfo(this$1.input, replace.start), - __acorn.getLineInfo(this$1.input, replace.end)) + acorn.getLineInfo(this$1.input, replace.start), + acorn.getLineInfo(this$1.input, replace.end)); } return replace } } } -} +}; lp.resetTo = function(pos) { var this$1 = this; - this.toks.pos = pos - var ch = this.input.charAt(pos - 1) + this.toks.pos = pos; + var ch = this.input.charAt(pos - 1); this.toks.exprAllowed = !ch || /[[{(,;:?/*=+\-~!|&%^<>]/.test(ch) || /[enwfd]/.test(ch) && - /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(this.input.slice(pos - 10, pos)) + /\b(case|else|return|throw|new|in|(instance|type)?of|delete|void)$/.test(this.input.slice(pos - 10, pos)); if (this.options.locations) { - this.toks.curLine = 1 - this.toks.lineStart = __acorn.lineBreakG.lastIndex = 0 - var match - while ((match = __acorn.lineBreakG.exec(this.input)) && match.index < pos) { - ++this$1.toks.curLine - this$1.toks.lineStart = match.index + match[0].length + this.toks.curLine = 1; + this.toks.lineStart = acorn.lineBreakG.lastIndex = 0; + var match; + while ((match = acorn.lineBreakG.exec(this.input)) && match.index < pos) { + ++this$1.toks.curLine; + this$1.toks.lineStart = match.index + match[0].length; } } -} +}; lp.lookAhead = function(n) { var this$1 = this; while (n > this.ahead.length) - this$1.ahead.push(this$1.readToken()) + { this$1.ahead.push(this$1.readToken()); } return this.ahead[n - 1] -} +}; -function isDummy(node) { return node.name == "✖" } +function isDummy(node) { return node.name === "✖" } -var lp$1 = LooseParser.prototype +var lp$1 = LooseParser.prototype; lp$1.parseTopLevel = function() { var this$1 = this; - var node = this.startNodeAt(this.options.locations ? [0, __acorn.getLineInfo(this.input, 0)] : 0) - node.body = [] - while (this.tok.type !== __acorn.tokTypes.eof) node.body.push(this$1.parseStatement()) - this.last = this.tok + var node = this.startNodeAt(this.options.locations ? [0, acorn.getLineInfo(this.input, 0)] : 0); + node.body = []; + while (this.tok.type !== acorn.tokTypes.eof) { node.body.push(this$1.parseStatement()); } + this.toks.adaptDirectivePrologue(node.body); + this.last = this.tok; if (this.options.ecmaVersion >= 6) { - node.sourceType = this.options.sourceType + node.sourceType = this.options.sourceType; } return this.finishNode(node, "Program") -} +}; lp$1.parseStatement = function() { var this$1 = this; - var starttype = this.tok.type, node = this.startNode(), kind + var starttype = this.tok.type, node = this.startNode(), kind; if (this.toks.isLet()) { - starttype = __acorn.tokTypes._var - kind = "let" + starttype = acorn.tokTypes._var; + kind = "let"; } switch (starttype) { - case __acorn.tokTypes._break: case __acorn.tokTypes._continue: - this.next() - var isBreak = starttype === __acorn.tokTypes._break + case acorn.tokTypes._break: case acorn.tokTypes._continue: + this.next(); + var isBreak = starttype === acorn.tokTypes._break; if (this.semicolon() || this.canInsertSemicolon()) { - node.label = null + node.label = null; } else { - node.label = this.tok.type === __acorn.tokTypes.name ? this.parseIdent() : null - this.semicolon() + node.label = this.tok.type === acorn.tokTypes.name ? this.parseIdent() : null; + this.semicolon(); } return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement") - case __acorn.tokTypes._debugger: - this.next() - this.semicolon() + case acorn.tokTypes._debugger: + this.next(); + this.semicolon(); return this.finishNode(node, "DebuggerStatement") - case __acorn.tokTypes._do: - this.next() - node.body = this.parseStatement() - node.test = this.eat(__acorn.tokTypes._while) ? this.parseParenExpression() : this.dummyIdent() - this.semicolon() + case acorn.tokTypes._do: + this.next(); + node.body = this.parseStatement(); + node.test = this.eat(acorn.tokTypes._while) ? this.parseParenExpression() : this.dummyIdent(); + this.semicolon(); return this.finishNode(node, "DoWhileStatement") - case __acorn.tokTypes._for: - this.next() - this.pushCx() - this.expect(__acorn.tokTypes.parenL) - if (this.tok.type === __acorn.tokTypes.semi) return this.parseFor(node, null) - var isLet = this.toks.isLet() - if (isLet || this.tok.type === __acorn.tokTypes._var || this.tok.type === __acorn.tokTypes._const) { - var init$1 = this.parseVar(true, isLet ? "let" : this.tok.value) - if (init$1.declarations.length === 1 && (this.tok.type === __acorn.tokTypes._in || this.isContextual("of"))) { + case acorn.tokTypes._for: + this.next(); // `for` keyword + var isAwait = this.options.ecmaVersion >= 9 && this.inAsync && this.eatContextual("await"); + + this.pushCx(); + this.expect(acorn.tokTypes.parenL); + if (this.tok.type === acorn.tokTypes.semi) { return this.parseFor(node, null) } + var isLet = this.toks.isLet(); + if (isLet || this.tok.type === acorn.tokTypes._var || this.tok.type === acorn.tokTypes._const) { + var init$1 = this.parseVar(this.startNode(), true, isLet ? "let" : this.tok.value); + if (init$1.declarations.length === 1 && (this.tok.type === acorn.tokTypes._in || this.isContextual("of"))) { + if (this.options.ecmaVersion >= 9 && this.tok.type !== acorn.tokTypes._in) { + node.await = isAwait; + } return this.parseForIn(node, init$1) } return this.parseFor(node, init$1) } - var init = this.parseExpression(true) - if (this.tok.type === __acorn.tokTypes._in || this.isContextual("of")) + var init = this.parseExpression(true); + if (this.tok.type === acorn.tokTypes._in || this.isContextual("of")) { + if (this.options.ecmaVersion >= 9 && this.tok.type !== acorn.tokTypes._in) { + node.await = isAwait; + } return this.parseForIn(node, this.toAssignable(init)) + } return this.parseFor(node, init) - case __acorn.tokTypes._function: - this.next() + case acorn.tokTypes._function: + this.next(); return this.parseFunction(node, true) - case __acorn.tokTypes._if: - this.next() - node.test = this.parseParenExpression() - node.consequent = this.parseStatement() - node.alternate = this.eat(__acorn.tokTypes._else) ? this.parseStatement() : null + case acorn.tokTypes._if: + this.next(); + node.test = this.parseParenExpression(); + node.consequent = this.parseStatement(); + node.alternate = this.eat(acorn.tokTypes._else) ? this.parseStatement() : null; return this.finishNode(node, "IfStatement") - case __acorn.tokTypes._return: - this.next() - if (this.eat(__acorn.tokTypes.semi) || this.canInsertSemicolon()) node.argument = null - else { node.argument = this.parseExpression(); this.semicolon() } + case acorn.tokTypes._return: + this.next(); + if (this.eat(acorn.tokTypes.semi) || this.canInsertSemicolon()) { node.argument = null; } + else { node.argument = this.parseExpression(); this.semicolon(); } return this.finishNode(node, "ReturnStatement") - case __acorn.tokTypes._switch: - var blockIndent = this.curIndent, line = this.curLineStart - this.next() - node.discriminant = this.parseParenExpression() - node.cases = [] - this.pushCx() - this.expect(__acorn.tokTypes.braceL) + case acorn.tokTypes._switch: + var blockIndent = this.curIndent, line = this.curLineStart; + this.next(); + node.discriminant = this.parseParenExpression(); + node.cases = []; + this.pushCx(); + this.expect(acorn.tokTypes.braceL); - var cur - while (!this.closes(__acorn.tokTypes.braceR, blockIndent, line, true)) { - if (this$1.tok.type === __acorn.tokTypes._case || this$1.tok.type === __acorn.tokTypes._default) { - var isCase = this$1.tok.type === __acorn.tokTypes._case - if (cur) this$1.finishNode(cur, "SwitchCase") - node.cases.push(cur = this$1.startNode()) - cur.consequent = [] - this$1.next() - if (isCase) cur.test = this$1.parseExpression() - else cur.test = null - this$1.expect(__acorn.tokTypes.colon) + var cur; + while (!this.closes(acorn.tokTypes.braceR, blockIndent, line, true)) { + if (this$1.tok.type === acorn.tokTypes._case || this$1.tok.type === acorn.tokTypes._default) { + var isCase = this$1.tok.type === acorn.tokTypes._case; + if (cur) { this$1.finishNode(cur, "SwitchCase"); } + node.cases.push(cur = this$1.startNode()); + cur.consequent = []; + this$1.next(); + if (isCase) { cur.test = this$1.parseExpression(); } + else { cur.test = null; } + this$1.expect(acorn.tokTypes.colon); } else { if (!cur) { - node.cases.push(cur = this$1.startNode()) - cur.consequent = [] - cur.test = null + node.cases.push(cur = this$1.startNode()); + cur.consequent = []; + cur.test = null; } - cur.consequent.push(this$1.parseStatement()) + cur.consequent.push(this$1.parseStatement()); } } - if (cur) this.finishNode(cur, "SwitchCase") - this.popCx() - this.eat(__acorn.tokTypes.braceR) + if (cur) { this.finishNode(cur, "SwitchCase"); } + this.popCx(); + this.eat(acorn.tokTypes.braceR); return this.finishNode(node, "SwitchStatement") - case __acorn.tokTypes._throw: - this.next() - node.argument = this.parseExpression() - this.semicolon() + case acorn.tokTypes._throw: + this.next(); + node.argument = this.parseExpression(); + this.semicolon(); return this.finishNode(node, "ThrowStatement") - case __acorn.tokTypes._try: - this.next() - node.block = this.parseBlock() - node.handler = null - if (this.tok.type === __acorn.tokTypes._catch) { - var clause = this.startNode() - this.next() - this.expect(__acorn.tokTypes.parenL) - clause.param = this.toAssignable(this.parseExprAtom(), true) - this.expect(__acorn.tokTypes.parenR) - clause.body = this.parseBlock() - node.handler = this.finishNode(clause, "CatchClause") + case acorn.tokTypes._try: + this.next(); + node.block = this.parseBlock(); + node.handler = null; + if (this.tok.type === acorn.tokTypes._catch) { + var clause = this.startNode(); + this.next(); + if (this.eat(acorn.tokTypes.parenL)) { + clause.param = this.toAssignable(this.parseExprAtom(), true); + this.expect(acorn.tokTypes.parenR); + } else { + clause.param = null; + } + clause.body = this.parseBlock(); + node.handler = this.finishNode(clause, "CatchClause"); } - node.finalizer = this.eat(__acorn.tokTypes._finally) ? this.parseBlock() : null - if (!node.handler && !node.finalizer) return node.block + node.finalizer = this.eat(acorn.tokTypes._finally) ? this.parseBlock() : null; + if (!node.handler && !node.finalizer) { return node.block } return this.finishNode(node, "TryStatement") - case __acorn.tokTypes._var: - case __acorn.tokTypes._const: - return this.parseVar(false, kind || this.tok.value) + case acorn.tokTypes._var: + case acorn.tokTypes._const: + return this.parseVar(node, false, kind || this.tok.value) - case __acorn.tokTypes._while: - this.next() - node.test = this.parseParenExpression() - node.body = this.parseStatement() + case acorn.tokTypes._while: + this.next(); + node.test = this.parseParenExpression(); + node.body = this.parseStatement(); return this.finishNode(node, "WhileStatement") - case __acorn.tokTypes._with: - this.next() - node.object = this.parseParenExpression() - node.body = this.parseStatement() + case acorn.tokTypes._with: + this.next(); + node.object = this.parseParenExpression(); + node.body = this.parseStatement(); return this.finishNode(node, "WithStatement") - case __acorn.tokTypes.braceL: + case acorn.tokTypes.braceL: return this.parseBlock() - case __acorn.tokTypes.semi: - this.next() + case acorn.tokTypes.semi: + this.next(); return this.finishNode(node, "EmptyStatement") - case __acorn.tokTypes._class: + case acorn.tokTypes._class: return this.parseClass(true) - case __acorn.tokTypes._import: + case acorn.tokTypes._import: return this.parseImport() - case __acorn.tokTypes._export: + case acorn.tokTypes._export: return this.parseExport() default: if (this.toks.isAsyncFunction()) { - this.next() - this.next() + this.next(); + this.next(); return this.parseFunction(node, true, true) } - var expr = this.parseExpression() + var expr = this.parseExpression(); if (isDummy(expr)) { - this.next() - if (this.tok.type === __acorn.tokTypes.eof) return this.finishNode(node, "EmptyStatement") + this.next(); + if (this.tok.type === acorn.tokTypes.eof) { return this.finishNode(node, "EmptyStatement") } return this.parseStatement() - } else if (starttype === __acorn.tokTypes.name && expr.type === "Identifier" && this.eat(__acorn.tokTypes.colon)) { - node.body = this.parseStatement() - node.label = expr + } else if (starttype === acorn.tokTypes.name && expr.type === "Identifier" && this.eat(acorn.tokTypes.colon)) { + node.body = this.parseStatement(); + node.label = expr; return this.finishNode(node, "LabeledStatement") } else { - node.expression = expr - this.semicolon() + node.expression = expr; + this.semicolon(); return this.finishNode(node, "ExpressionStatement") } } -} +}; lp$1.parseBlock = function() { var this$1 = this; - var node = this.startNode() - this.pushCx() - this.expect(__acorn.tokTypes.braceL) - var blockIndent = this.curIndent, line = this.curLineStart - node.body = [] - while (!this.closes(__acorn.tokTypes.braceR, blockIndent, line, true)) - node.body.push(this$1.parseStatement()) - this.popCx() - this.eat(__acorn.tokTypes.braceR) + var node = this.startNode(); + this.pushCx(); + this.expect(acorn.tokTypes.braceL); + var blockIndent = this.curIndent, line = this.curLineStart; + node.body = []; + while (!this.closes(acorn.tokTypes.braceR, blockIndent, line, true)) + { node.body.push(this$1.parseStatement()); } + this.popCx(); + this.eat(acorn.tokTypes.braceR); return this.finishNode(node, "BlockStatement") -} +}; lp$1.parseFor = function(node, init) { - node.init = init - node.test = node.update = null - if (this.eat(__acorn.tokTypes.semi) && this.tok.type !== __acorn.tokTypes.semi) node.test = this.parseExpression() - if (this.eat(__acorn.tokTypes.semi) && this.tok.type !== __acorn.tokTypes.parenR) node.update = this.parseExpression() - this.popCx() - this.expect(__acorn.tokTypes.parenR) - node.body = this.parseStatement() + node.init = init; + node.test = node.update = null; + if (this.eat(acorn.tokTypes.semi) && this.tok.type !== acorn.tokTypes.semi) { node.test = this.parseExpression(); } + if (this.eat(acorn.tokTypes.semi) && this.tok.type !== acorn.tokTypes.parenR) { node.update = this.parseExpression(); } + this.popCx(); + this.expect(acorn.tokTypes.parenR); + node.body = this.parseStatement(); return this.finishNode(node, "ForStatement") -} +}; lp$1.parseForIn = function(node, init) { - var type = this.tok.type === __acorn.tokTypes._in ? "ForInStatement" : "ForOfStatement" - this.next() - node.left = init - node.right = this.parseExpression() - this.popCx() - this.expect(__acorn.tokTypes.parenR) - node.body = this.parseStatement() + var type = this.tok.type === acorn.tokTypes._in ? "ForInStatement" : "ForOfStatement"; + this.next(); + node.left = init; + node.right = this.parseExpression(); + this.popCx(); + this.expect(acorn.tokTypes.parenR); + node.body = this.parseStatement(); return this.finishNode(node, type) -} +}; -lp$1.parseVar = function(noIn, kind) { +lp$1.parseVar = function(node, noIn, kind) { var this$1 = this; - var node = this.startNode() - node.kind = kind - this.next() - node.declarations = [] + node.kind = kind; + this.next(); + node.declarations = []; do { - var decl = this$1.startNode() - decl.id = this$1.options.ecmaVersion >= 6 ? this$1.toAssignable(this$1.parseExprAtom(), true) : this$1.parseIdent() - decl.init = this$1.eat(__acorn.tokTypes.eq) ? this$1.parseMaybeAssign(noIn) : null - node.declarations.push(this$1.finishNode(decl, "VariableDeclarator")) - } while (this.eat(__acorn.tokTypes.comma)) + var decl = this$1.startNode(); + decl.id = this$1.options.ecmaVersion >= 6 ? this$1.toAssignable(this$1.parseExprAtom(), true) : this$1.parseIdent(); + decl.init = this$1.eat(acorn.tokTypes.eq) ? this$1.parseMaybeAssign(noIn) : null; + node.declarations.push(this$1.finishNode(decl, "VariableDeclarator")); + } while (this.eat(acorn.tokTypes.comma)) if (!node.declarations.length) { - var decl$1 = this.startNode() - decl$1.id = this.dummyIdent() - node.declarations.push(this.finishNode(decl$1, "VariableDeclarator")) + var decl$1 = this.startNode(); + decl$1.id = this.dummyIdent(); + node.declarations.push(this.finishNode(decl$1, "VariableDeclarator")); } - if (!noIn) this.semicolon() + if (!noIn) { this.semicolon(); } return this.finishNode(node, "VariableDeclaration") -} +}; lp$1.parseClass = function(isStatement) { var this$1 = this; - var node = this.startNode() - this.next() - if (this.tok.type === __acorn.tokTypes.name) node.id = this.parseIdent() - else if (isStatement === true) node.id = this.dummyIdent() - else node.id = null - node.superClass = this.eat(__acorn.tokTypes._extends) ? this.parseExpression() : null - node.body = this.startNode() - node.body.body = [] - this.pushCx() - var indent = this.curIndent + 1, line = this.curLineStart - this.eat(__acorn.tokTypes.braceL) - if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart } - while (!this.closes(__acorn.tokTypes.braceR, indent, line)) { - if (this$1.semicolon()) continue - var method = this$1.startNode(), isGenerator, isAsync + var node = this.startNode(); + this.next(); + if (this.tok.type === acorn.tokTypes.name) { node.id = this.parseIdent(); } + else if (isStatement === true) { node.id = this.dummyIdent(); } + else { node.id = null; } + node.superClass = this.eat(acorn.tokTypes._extends) ? this.parseExpression() : null; + node.body = this.startNode(); + node.body.body = []; + this.pushCx(); + var indent = this.curIndent + 1, line = this.curLineStart; + this.eat(acorn.tokTypes.braceL); + if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart; } + while (!this.closes(acorn.tokTypes.braceR, indent, line)) { + if (this$1.semicolon()) { continue } + var method = this$1.startNode(), isGenerator = (void 0), isAsync = (void 0); if (this$1.options.ecmaVersion >= 6) { - method.static = false - isGenerator = this$1.eat(__acorn.tokTypes.star) + method.static = false; + isGenerator = this$1.eat(acorn.tokTypes.star); } - this$1.parsePropertyName(method) - if (isDummy(method.key)) { if (isDummy(this$1.parseMaybeAssign())) this$1.next(); this$1.eat(__acorn.tokTypes.comma); continue } + this$1.parsePropertyName(method); + if (isDummy(method.key)) { if (isDummy(this$1.parseMaybeAssign())) { this$1.next(); } this$1.eat(acorn.tokTypes.comma); continue } if (method.key.type === "Identifier" && !method.computed && method.key.name === "static" && - (this$1.tok.type != __acorn.tokTypes.parenL && this$1.tok.type != __acorn.tokTypes.braceL)) { - method.static = true - isGenerator = this$1.eat(__acorn.tokTypes.star) - this$1.parsePropertyName(method) + (this$1.tok.type !== acorn.tokTypes.parenL && this$1.tok.type !== acorn.tokTypes.braceL)) { + method.static = true; + isGenerator = this$1.eat(acorn.tokTypes.star); + this$1.parsePropertyName(method); } else { - method.static = false + method.static = false; } if (!method.computed && - method.key.type === "Identifier" && method.key.name === "async" && this$1.tok.type !== __acorn.tokTypes.parenL && + method.key.type === "Identifier" && method.key.name === "async" && this$1.tok.type !== acorn.tokTypes.parenL && !this$1.canInsertSemicolon()) { - this$1.parsePropertyName(method) - isAsync = true + isAsync = true; + isGenerator = this$1.options.ecmaVersion >= 9 && this$1.eat(acorn.tokTypes.star); + this$1.parsePropertyName(method); } else { - isAsync = false + isAsync = false; } if (this$1.options.ecmaVersion >= 5 && method.key.type === "Identifier" && !method.computed && (method.key.name === "get" || method.key.name === "set") && - this$1.tok.type !== __acorn.tokTypes.parenL && this$1.tok.type !== __acorn.tokTypes.braceL) { - method.kind = method.key.name - this$1.parsePropertyName(method) - method.value = this$1.parseMethod(false) + this$1.tok.type !== acorn.tokTypes.parenL && this$1.tok.type !== acorn.tokTypes.braceL) { + method.kind = method.key.name; + this$1.parsePropertyName(method); + method.value = this$1.parseMethod(false); } else { if (!method.computed && !method.static && !isGenerator && !isAsync && ( method.key.type === "Identifier" && method.key.name === "constructor" || method.key.type === "Literal" && method.key.value === "constructor")) { - method.kind = "constructor" + method.kind = "constructor"; } else { - method.kind = "method" + method.kind = "method"; } - method.value = this$1.parseMethod(isGenerator, isAsync) + method.value = this$1.parseMethod(isGenerator, isAsync); } - node.body.body.push(this$1.finishNode(method, "MethodDefinition")) + node.body.body.push(this$1.finishNode(method, "MethodDefinition")); } - this.popCx() - if (!this.eat(__acorn.tokTypes.braceR)) { + this.popCx(); + if (!this.eat(acorn.tokTypes.braceR)) { // If there is no closing brace, make the node span to the start // of the next token (this is useful for Tern) - this.last.end = this.tok.start - if (this.options.locations) this.last.loc.end = this.tok.loc.start + this.last.end = this.tok.start; + if (this.options.locations) { this.last.loc.end = this.tok.loc.start; } } - this.semicolon() - this.finishNode(node.body, "ClassBody") + this.semicolon(); + this.finishNode(node.body, "ClassBody"); return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") -} +}; lp$1.parseFunction = function(node, isStatement, isAsync) { - var oldInAsync = this.inAsync - this.initFunction(node) + var oldInAsync = this.inAsync, oldInFunction = this.inFunction; + this.initFunction(node); if (this.options.ecmaVersion >= 6) { - node.generator = this.eat(__acorn.tokTypes.star) + node.generator = this.eat(acorn.tokTypes.star); } if (this.options.ecmaVersion >= 8) { - node.async = !!isAsync + node.async = !!isAsync; } - if (this.tok.type === __acorn.tokTypes.name) node.id = this.parseIdent() - else if (isStatement === true) node.id = this.dummyIdent() - this.inAsync = node.async - node.params = this.parseFunctionParams() - node.body = this.parseBlock() - this.inAsync = oldInAsync + if (this.tok.type === acorn.tokTypes.name) { node.id = this.parseIdent(); } + else if (isStatement === true) { node.id = this.dummyIdent(); } + this.inAsync = node.async; + this.inFunction = true; + node.params = this.parseFunctionParams(); + node.body = this.parseBlock(); + this.toks.adaptDirectivePrologue(node.body.body); + this.inAsync = oldInAsync; + this.inFunction = oldInFunction; return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression") -} +}; lp$1.parseExport = function() { - var node = this.startNode() - this.next() - if (this.eat(__acorn.tokTypes.star)) { - node.source = this.eatContextual("from") ? this.parseExprAtom() : this.dummyString() + var node = this.startNode(); + this.next(); + if (this.eat(acorn.tokTypes.star)) { + node.source = this.eatContextual("from") ? this.parseExprAtom() : this.dummyString(); return this.finishNode(node, "ExportAllDeclaration") } - if (this.eat(__acorn.tokTypes._default)) { + if (this.eat(acorn.tokTypes._default)) { // export default (function foo() {}) // This is FunctionExpression. - var isAsync - if (this.tok.type === __acorn.tokTypes._function || (isAsync = this.toks.isAsyncFunction())) { - var fNode = this.startNode() - this.next() - if (isAsync) this.next() - node.declaration = this.parseFunction(fNode, "nullableID", isAsync) - } else if (this.tok.type === __acorn.tokTypes._class) { - node.declaration = this.parseClass("nullableID") + var isAsync; + if (this.tok.type === acorn.tokTypes._function || (isAsync = this.toks.isAsyncFunction())) { + var fNode = this.startNode(); + this.next(); + if (isAsync) { this.next(); } + node.declaration = this.parseFunction(fNode, "nullableID", isAsync); + } else if (this.tok.type === acorn.tokTypes._class) { + node.declaration = this.parseClass("nullableID"); } else { - node.declaration = this.parseMaybeAssign() - this.semicolon() + node.declaration = this.parseMaybeAssign(); + this.semicolon(); } return this.finishNode(node, "ExportDefaultDeclaration") } if (this.tok.type.keyword || this.toks.isLet() || this.toks.isAsyncFunction()) { - node.declaration = this.parseStatement() - node.specifiers = [] - node.source = null + node.declaration = this.parseStatement(); + node.specifiers = []; + node.source = null; } else { - node.declaration = null - node.specifiers = this.parseExportSpecifierList() - node.source = this.eatContextual("from") ? this.parseExprAtom() : null - this.semicolon() + node.declaration = null; + node.specifiers = this.parseExportSpecifierList(); + node.source = this.eatContextual("from") ? this.parseExprAtom() : null; + this.semicolon(); } return this.finishNode(node, "ExportNamedDeclaration") -} +}; lp$1.parseImport = function() { - var node = this.startNode() - this.next() - if (this.tok.type === __acorn.tokTypes.string) { - node.specifiers = [] - node.source = this.parseExprAtom() - node.kind = "" + var node = this.startNode(); + this.next(); + if (this.tok.type === acorn.tokTypes.string) { + node.specifiers = []; + node.source = this.parseExprAtom(); } else { - var elt - if (this.tok.type === __acorn.tokTypes.name && this.tok.value !== "from") { - elt = this.startNode() - elt.local = this.parseIdent() - this.finishNode(elt, "ImportDefaultSpecifier") - this.eat(__acorn.tokTypes.comma) + var elt; + if (this.tok.type === acorn.tokTypes.name && this.tok.value !== "from") { + elt = this.startNode(); + elt.local = this.parseIdent(); + this.finishNode(elt, "ImportDefaultSpecifier"); + this.eat(acorn.tokTypes.comma); } - node.specifiers = this.parseImportSpecifierList() - node.source = this.eatContextual("from") && this.tok.type == __acorn.tokTypes.string ? this.parseExprAtom() : this.dummyString() - if (elt) node.specifiers.unshift(elt) + node.specifiers = this.parseImportSpecifiers(); + node.source = this.eatContextual("from") && this.tok.type === acorn.tokTypes.string ? this.parseExprAtom() : this.dummyString(); + if (elt) { node.specifiers.unshift(elt); } } - this.semicolon() + this.semicolon(); return this.finishNode(node, "ImportDeclaration") -} +}; -lp$1.parseImportSpecifierList = function() { +lp$1.parseImportSpecifiers = function() { var this$1 = this; - var elts = [] - if (this.tok.type === __acorn.tokTypes.star) { - var elt = this.startNode() - this.next() - elt.local = this.eatContextual("as") ? this.parseIdent() : this.dummyIdent() - elts.push(this.finishNode(elt, "ImportNamespaceSpecifier")) + var elts = []; + if (this.tok.type === acorn.tokTypes.star) { + var elt = this.startNode(); + this.next(); + elt.local = this.eatContextual("as") ? this.parseIdent() : this.dummyIdent(); + elts.push(this.finishNode(elt, "ImportNamespaceSpecifier")); } else { - var indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart - this.pushCx() - this.eat(__acorn.tokTypes.braceL) - if (this.curLineStart > continuedLine) continuedLine = this.curLineStart - while (!this.closes(__acorn.tokTypes.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { - var elt$1 = this$1.startNode() - if (this$1.eat(__acorn.tokTypes.star)) { - elt$1.local = this$1.eatContextual("as") ? this$1.parseIdent() : this$1.dummyIdent() - this$1.finishNode(elt$1, "ImportNamespaceSpecifier") + var indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart; + this.pushCx(); + this.eat(acorn.tokTypes.braceL); + if (this.curLineStart > continuedLine) { continuedLine = this.curLineStart; } + while (!this.closes(acorn.tokTypes.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { + var elt$1 = this$1.startNode(); + if (this$1.eat(acorn.tokTypes.star)) { + elt$1.local = this$1.eatContextual("as") ? this$1.parseIdent() : this$1.dummyIdent(); + this$1.finishNode(elt$1, "ImportNamespaceSpecifier"); } else { - if (this$1.isContextual("from")) break - elt$1.imported = this$1.parseIdent() - if (isDummy(elt$1.imported)) break - elt$1.local = this$1.eatContextual("as") ? this$1.parseIdent() : elt$1.imported - this$1.finishNode(elt$1, "ImportSpecifier") + if (this$1.isContextual("from")) { break } + elt$1.imported = this$1.parseIdent(); + if (isDummy(elt$1.imported)) { break } + elt$1.local = this$1.eatContextual("as") ? this$1.parseIdent() : elt$1.imported; + this$1.finishNode(elt$1, "ImportSpecifier"); } - elts.push(elt$1) - this$1.eat(__acorn.tokTypes.comma) + elts.push(elt$1); + this$1.eat(acorn.tokTypes.comma); } - this.eat(__acorn.tokTypes.braceR) - this.popCx() + this.eat(acorn.tokTypes.braceR); + this.popCx(); } return elts -} +}; lp$1.parseExportSpecifierList = function() { var this$1 = this; - var elts = [] - var indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart - this.pushCx() - this.eat(__acorn.tokTypes.braceL) - if (this.curLineStart > continuedLine) continuedLine = this.curLineStart - while (!this.closes(__acorn.tokTypes.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { - if (this$1.isContextual("from")) break - var elt = this$1.startNode() - elt.local = this$1.parseIdent() - if (isDummy(elt.local)) break - elt.exported = this$1.eatContextual("as") ? this$1.parseIdent() : elt.local - this$1.finishNode(elt, "ExportSpecifier") - elts.push(elt) - this$1.eat(__acorn.tokTypes.comma) + var elts = []; + var indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart; + this.pushCx(); + this.eat(acorn.tokTypes.braceL); + if (this.curLineStart > continuedLine) { continuedLine = this.curLineStart; } + while (!this.closes(acorn.tokTypes.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { + if (this$1.isContextual("from")) { break } + var elt = this$1.startNode(); + elt.local = this$1.parseIdent(); + if (isDummy(elt.local)) { break } + elt.exported = this$1.eatContextual("as") ? this$1.parseIdent() : elt.local; + this$1.finishNode(elt, "ExportSpecifier"); + elts.push(elt); + this$1.eat(acorn.tokTypes.comma); } - this.eat(__acorn.tokTypes.braceR) - this.popCx() + this.eat(acorn.tokTypes.braceR); + this.popCx(); return elts -} +}; -var lp$2 = LooseParser.prototype +var lp$2 = LooseParser.prototype; lp$2.checkLVal = function(expr) { - if (!expr) return expr + if (!expr) { return expr } switch (expr.type) { case "Identifier": case "MemberExpression": return expr case "ParenthesizedExpression": - expr.expression = this.checkLVal(expr.expression) + expr.expression = this.checkLVal(expr.expression); return expr default: return this.dummyIdent() } -} +}; lp$2.parseExpression = function(noIn) { var this$1 = this; - var start = this.storeCurrentPos() - var expr = this.parseMaybeAssign(noIn) - if (this.tok.type === __acorn.tokTypes.comma) { - var node = this.startNodeAt(start) - node.expressions = [expr] - while (this.eat(__acorn.tokTypes.comma)) node.expressions.push(this$1.parseMaybeAssign(noIn)) + var start = this.storeCurrentPos(); + var expr = this.parseMaybeAssign(noIn); + if (this.tok.type === acorn.tokTypes.comma) { + var node = this.startNodeAt(start); + node.expressions = [expr]; + while (this.eat(acorn.tokTypes.comma)) { node.expressions.push(this$1.parseMaybeAssign(noIn)); } return this.finishNode(node, "SequenceExpression") } return expr -} +}; lp$2.parseParenExpression = function() { - this.pushCx() - this.expect(__acorn.tokTypes.parenL) - var val = this.parseExpression() - this.popCx() - this.expect(__acorn.tokTypes.parenR) + this.pushCx(); + this.expect(acorn.tokTypes.parenL); + var val = this.parseExpression(); + this.popCx(); + this.expect(acorn.tokTypes.parenR); return val -} +}; lp$2.parseMaybeAssign = function(noIn) { if (this.toks.isContextual("yield")) { - var node = this.startNode() - this.next() - if (this.semicolon() || this.canInsertSemicolon() || (this.tok.type != __acorn.tokTypes.star && !this.tok.type.startsExpr)) { - node.delegate = false - node.argument = null + var node = this.startNode(); + this.next(); + if (this.semicolon() || this.canInsertSemicolon() || (this.tok.type !== acorn.tokTypes.star && !this.tok.type.startsExpr)) { + node.delegate = false; + node.argument = null; } else { - node.delegate = this.eat(__acorn.tokTypes.star) - node.argument = this.parseMaybeAssign() + node.delegate = this.eat(acorn.tokTypes.star); + node.argument = this.parseMaybeAssign(); } return this.finishNode(node, "YieldExpression") } - var start = this.storeCurrentPos() - var left = this.parseMaybeConditional(noIn) + var start = this.storeCurrentPos(); + var left = this.parseMaybeConditional(noIn); if (this.tok.type.isAssign) { - var node$1 = this.startNodeAt(start) - node$1.operator = this.tok.value - node$1.left = this.tok.type === __acorn.tokTypes.eq ? this.toAssignable(left) : this.checkLVal(left) - this.next() - node$1.right = this.parseMaybeAssign(noIn) + var node$1 = this.startNodeAt(start); + node$1.operator = this.tok.value; + node$1.left = this.tok.type === acorn.tokTypes.eq ? this.toAssignable(left) : this.checkLVal(left); + this.next(); + node$1.right = this.parseMaybeAssign(noIn); return this.finishNode(node$1, "AssignmentExpression") } return left -} +}; lp$2.parseMaybeConditional = function(noIn) { - var start = this.storeCurrentPos() - var expr = this.parseExprOps(noIn) - if (this.eat(__acorn.tokTypes.question)) { - var node = this.startNodeAt(start) - node.test = expr - node.consequent = this.parseMaybeAssign() - node.alternate = this.expect(__acorn.tokTypes.colon) ? this.parseMaybeAssign(noIn) : this.dummyIdent() + var start = this.storeCurrentPos(); + var expr = this.parseExprOps(noIn); + if (this.eat(acorn.tokTypes.question)) { + var node = this.startNodeAt(start); + node.test = expr; + node.consequent = this.parseMaybeAssign(); + node.alternate = this.expect(acorn.tokTypes.colon) ? this.parseMaybeAssign(noIn) : this.dummyIdent(); return this.finishNode(node, "ConditionalExpression") } return expr -} +}; lp$2.parseExprOps = function(noIn) { - var start = this.storeCurrentPos() - var indent = this.curIndent, line = this.curLineStart + var start = this.storeCurrentPos(); + var indent = this.curIndent, line = this.curLineStart; return this.parseExprOp(this.parseMaybeUnary(false), start, -1, noIn, indent, line) -} +}; lp$2.parseExprOp = function(left, start, minPrec, noIn, indent, line) { - if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) return left - var prec = this.tok.type.binop - if (prec != null && (!noIn || this.tok.type !== __acorn.tokTypes._in)) { + if (this.curLineStart !== line && this.curIndent < indent && this.tokenStartsLine()) { return left } + var prec = this.tok.type.binop; + if (prec != null && (!noIn || this.tok.type !== acorn.tokTypes._in)) { if (prec > minPrec) { - var node = this.startNodeAt(start) - node.left = left - node.operator = this.tok.value - this.next() - if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) { - node.right = this.dummyIdent() + var node = this.startNodeAt(start); + node.left = left; + node.operator = this.tok.value; + this.next(); + if (this.curLineStart !== line && this.curIndent < indent && this.tokenStartsLine()) { + node.right = this.dummyIdent(); } else { - var rightStart = this.storeCurrentPos() - node.right = this.parseExprOp(this.parseMaybeUnary(false), rightStart, prec, noIn, indent, line) + var rightStart = this.storeCurrentPos(); + node.right = this.parseExprOp(this.parseMaybeUnary(false), rightStart, prec, noIn, indent, line); } - this.finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression") + this.finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression"); return this.parseExprOp(node, start, minPrec, noIn, indent, line) } } return left -} +}; lp$2.parseMaybeUnary = function(sawUnary) { var this$1 = this; - var start = this.storeCurrentPos(), expr - if (this.options.ecmaVersion >= 8 && this.inAsync && this.toks.isContextual("await")) { - expr = this.parseAwait() - sawUnary = true + var start = this.storeCurrentPos(), expr; + if (this.options.ecmaVersion >= 8 && this.toks.isContextual("await") && + (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction)) + ) { + expr = this.parseAwait(); + sawUnary = true; } else if (this.tok.type.prefix) { - var node = this.startNode(), update = this.tok.type === __acorn.tokTypes.incDec - if (!update) sawUnary = true - node.operator = this.tok.value - node.prefix = true - this.next() - node.argument = this.parseMaybeUnary(true) - if (update) node.argument = this.checkLVal(node.argument) - expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression") - } else if (this.tok.type === __acorn.tokTypes.ellipsis) { - var node$1 = this.startNode() - this.next() - node$1.argument = this.parseMaybeUnary(sawUnary) - expr = this.finishNode(node$1, "SpreadElement") + var node = this.startNode(), update = this.tok.type === acorn.tokTypes.incDec; + if (!update) { sawUnary = true; } + node.operator = this.tok.value; + node.prefix = true; + this.next(); + node.argument = this.parseMaybeUnary(true); + if (update) { node.argument = this.checkLVal(node.argument); } + expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); + } else if (this.tok.type === acorn.tokTypes.ellipsis) { + var node$1 = this.startNode(); + this.next(); + node$1.argument = this.parseMaybeUnary(sawUnary); + expr = this.finishNode(node$1, "SpreadElement"); } else { - expr = this.parseExprSubscripts() + expr = this.parseExprSubscripts(); while (this.tok.type.postfix && !this.canInsertSemicolon()) { - var node$2 = this$1.startNodeAt(start) - node$2.operator = this$1.tok.value - node$2.prefix = false - node$2.argument = this$1.checkLVal(expr) - this$1.next() - expr = this$1.finishNode(node$2, "UpdateExpression") + var node$2 = this$1.startNodeAt(start); + node$2.operator = this$1.tok.value; + node$2.prefix = false; + node$2.argument = this$1.checkLVal(expr); + this$1.next(); + expr = this$1.finishNode(node$2, "UpdateExpression"); } } - if (!sawUnary && this.eat(__acorn.tokTypes.starstar)) { - var node$3 = this.startNodeAt(start) - node$3.operator = "**" - node$3.left = expr - node$3.right = this.parseMaybeUnary(false) + if (!sawUnary && this.eat(acorn.tokTypes.starstar)) { + var node$3 = this.startNodeAt(start); + node$3.operator = "**"; + node$3.left = expr; + node$3.right = this.parseMaybeUnary(false); return this.finishNode(node$3, "BinaryExpression") } return expr -} +}; lp$2.parseExprSubscripts = function() { - var start = this.storeCurrentPos() + var start = this.storeCurrentPos(); return this.parseSubscripts(this.parseExprAtom(), start, false, this.curIndent, this.curLineStart) -} +}; lp$2.parseSubscripts = function(base, start, noCalls, startIndent, line) { var this$1 = this; for (;;) { - if (this$1.curLineStart != line && this$1.curIndent <= startIndent && this$1.tokenStartsLine()) { - if (this$1.tok.type == __acorn.tokTypes.dot && this$1.curIndent == startIndent) - --startIndent + if (this$1.curLineStart !== line && this$1.curIndent <= startIndent && this$1.tokenStartsLine()) { + if (this$1.tok.type === acorn.tokTypes.dot && this$1.curIndent === startIndent) + { --startIndent; } else - return base + { return base } } - var maybeAsyncArrow = base.type === "Identifier" && base.name === "async" && !this$1.canInsertSemicolon() + var maybeAsyncArrow = base.type === "Identifier" && base.name === "async" && !this$1.canInsertSemicolon(); - if (this$1.eat(__acorn.tokTypes.dot)) { - var node = this$1.startNodeAt(start) - node.object = base - if (this$1.curLineStart != line && this$1.curIndent <= startIndent && this$1.tokenStartsLine()) - node.property = this$1.dummyIdent() + if (this$1.eat(acorn.tokTypes.dot)) { + var node = this$1.startNodeAt(start); + node.object = base; + if (this$1.curLineStart !== line && this$1.curIndent <= startIndent && this$1.tokenStartsLine()) + { node.property = this$1.dummyIdent(); } else - node.property = this$1.parsePropertyAccessor() || this$1.dummyIdent() - node.computed = false - base = this$1.finishNode(node, "MemberExpression") - } else if (this$1.tok.type == __acorn.tokTypes.bracketL) { - this$1.pushCx() - this$1.next() - var node$1 = this$1.startNodeAt(start) - node$1.object = base - node$1.property = this$1.parseExpression() - node$1.computed = true - this$1.popCx() - this$1.expect(__acorn.tokTypes.bracketR) - base = this$1.finishNode(node$1, "MemberExpression") - } else if (!noCalls && this$1.tok.type == __acorn.tokTypes.parenL) { - var exprList = this$1.parseExprList(__acorn.tokTypes.parenR) - if (maybeAsyncArrow && this$1.eat(__acorn.tokTypes.arrow)) - return this$1.parseArrowExpression(this$1.startNodeAt(start), exprList, true) - var node$2 = this$1.startNodeAt(start) - node$2.callee = base - node$2.arguments = exprList - base = this$1.finishNode(node$2, "CallExpression") - } else if (this$1.tok.type == __acorn.tokTypes.backQuote) { - var node$3 = this$1.startNodeAt(start) - node$3.tag = base - node$3.quasi = this$1.parseTemplate() - base = this$1.finishNode(node$3, "TaggedTemplateExpression") + { node.property = this$1.parsePropertyAccessor() || this$1.dummyIdent(); } + node.computed = false; + base = this$1.finishNode(node, "MemberExpression"); + } else if (this$1.tok.type === acorn.tokTypes.bracketL) { + this$1.pushCx(); + this$1.next(); + var node$1 = this$1.startNodeAt(start); + node$1.object = base; + node$1.property = this$1.parseExpression(); + node$1.computed = true; + this$1.popCx(); + this$1.expect(acorn.tokTypes.bracketR); + base = this$1.finishNode(node$1, "MemberExpression"); + } else if (!noCalls && this$1.tok.type === acorn.tokTypes.parenL) { + var exprList = this$1.parseExprList(acorn.tokTypes.parenR); + if (maybeAsyncArrow && this$1.eat(acorn.tokTypes.arrow)) + { return this$1.parseArrowExpression(this$1.startNodeAt(start), exprList, true) } + var node$2 = this$1.startNodeAt(start); + node$2.callee = base; + node$2.arguments = exprList; + base = this$1.finishNode(node$2, "CallExpression"); + } else if (this$1.tok.type === acorn.tokTypes.backQuote) { + var node$3 = this$1.startNodeAt(start); + node$3.tag = base; + node$3.quasi = this$1.parseTemplate(); + base = this$1.finishNode(node$3, "TaggedTemplateExpression"); } else { return base } } -} +}; lp$2.parseExprAtom = function() { - var node + var node; switch (this.tok.type) { - case __acorn.tokTypes._this: - case __acorn.tokTypes._super: - var type = this.tok.type === __acorn.tokTypes._this ? "ThisExpression" : "Super" - node = this.startNode() - this.next() + case acorn.tokTypes._this: + case acorn.tokTypes._super: + var type = this.tok.type === acorn.tokTypes._this ? "ThisExpression" : "Super"; + node = this.startNode(); + this.next(); return this.finishNode(node, type) - case __acorn.tokTypes.name: - var start = this.storeCurrentPos() - var id = this.parseIdent() - var isAsync = false + case acorn.tokTypes.name: + var start = this.storeCurrentPos(); + var id = this.parseIdent(); + var isAsync = false; if (id.name === "async" && !this.canInsertSemicolon()) { - if (this.eat(__acorn.tokTypes._function)) - return this.parseFunction(this.startNodeAt(start), false, true) - if (this.tok.type === __acorn.tokTypes.name) { - id = this.parseIdent() - isAsync = true + if (this.eat(acorn.tokTypes._function)) + { return this.parseFunction(this.startNodeAt(start), false, true) } + if (this.tok.type === acorn.tokTypes.name) { + id = this.parseIdent(); + isAsync = true; } } - return this.eat(__acorn.tokTypes.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id], isAsync) : id + return this.eat(acorn.tokTypes.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id], isAsync) : id - case __acorn.tokTypes.regexp: - node = this.startNode() - var val = this.tok.value - node.regex = {pattern: val.pattern, flags: val.flags} - node.value = val.value - node.raw = this.input.slice(this.tok.start, this.tok.end) - this.next() + case acorn.tokTypes.regexp: + node = this.startNode(); + var val = this.tok.value; + node.regex = {pattern: val.pattern, flags: val.flags}; + node.value = val.value; + node.raw = this.input.slice(this.tok.start, this.tok.end); + this.next(); return this.finishNode(node, "Literal") - case __acorn.tokTypes.num: case __acorn.tokTypes.string: - node = this.startNode() - node.value = this.tok.value - node.raw = this.input.slice(this.tok.start, this.tok.end) - this.next() + case acorn.tokTypes.num: case acorn.tokTypes.string: + node = this.startNode(); + node.value = this.tok.value; + node.raw = this.input.slice(this.tok.start, this.tok.end); + this.next(); return this.finishNode(node, "Literal") - case __acorn.tokTypes._null: case __acorn.tokTypes._true: case __acorn.tokTypes._false: - node = this.startNode() - node.value = this.tok.type === __acorn.tokTypes._null ? null : this.tok.type === __acorn.tokTypes._true - node.raw = this.tok.type.keyword - this.next() + case acorn.tokTypes._null: case acorn.tokTypes._true: case acorn.tokTypes._false: + node = this.startNode(); + node.value = this.tok.type === acorn.tokTypes._null ? null : this.tok.type === acorn.tokTypes._true; + node.raw = this.tok.type.keyword; + this.next(); return this.finishNode(node, "Literal") - case __acorn.tokTypes.parenL: - var parenStart = this.storeCurrentPos() - this.next() - var inner = this.parseExpression() - this.expect(__acorn.tokTypes.parenR) - if (this.eat(__acorn.tokTypes.arrow)) { + case acorn.tokTypes.parenL: + var parenStart = this.storeCurrentPos(); + this.next(); + var inner = this.parseExpression(); + this.expect(acorn.tokTypes.parenR); + if (this.eat(acorn.tokTypes.arrow)) { // (a,)=>a // SequenceExpression makes dummy in the last hole. Drop the dummy. - var params = inner.expressions || [inner] + var params = inner.expressions || [inner]; if (params.length && isDummy(params[params.length - 1])) - params.pop() + { params.pop(); } return this.parseArrowExpression(this.startNodeAt(parenStart), params) } if (this.options.preserveParens) { - var par = this.startNodeAt(parenStart) - par.expression = inner - inner = this.finishNode(par, "ParenthesizedExpression") + var par = this.startNodeAt(parenStart); + par.expression = inner; + inner = this.finishNode(par, "ParenthesizedExpression"); } return inner - case __acorn.tokTypes.bracketL: - node = this.startNode() - node.elements = this.parseExprList(__acorn.tokTypes.bracketR, true) + case acorn.tokTypes.bracketL: + node = this.startNode(); + node.elements = this.parseExprList(acorn.tokTypes.bracketR, true); return this.finishNode(node, "ArrayExpression") - case __acorn.tokTypes.braceL: + case acorn.tokTypes.braceL: return this.parseObj() - case __acorn.tokTypes._class: + case acorn.tokTypes._class: return this.parseClass(false) - case __acorn.tokTypes._function: - node = this.startNode() - this.next() + case acorn.tokTypes._function: + node = this.startNode(); + this.next(); return this.parseFunction(node, false) - case __acorn.tokTypes._new: + case acorn.tokTypes._new: return this.parseNew() - case __acorn.tokTypes.backQuote: + case acorn.tokTypes.backQuote: return this.parseTemplate() default: return this.dummyIdent() } -} +}; lp$2.parseNew = function() { - var node = this.startNode(), startIndent = this.curIndent, line = this.curLineStart - var meta = this.parseIdent(true) - if (this.options.ecmaVersion >= 6 && this.eat(__acorn.tokTypes.dot)) { - node.meta = meta - node.property = this.parseIdent(true) + var node = this.startNode(), startIndent = this.curIndent, line = this.curLineStart; + var meta = this.parseIdent(true); + if (this.options.ecmaVersion >= 6 && this.eat(acorn.tokTypes.dot)) { + node.meta = meta; + node.property = this.parseIdent(true); return this.finishNode(node, "MetaProperty") } - var start = this.storeCurrentPos() - node.callee = this.parseSubscripts(this.parseExprAtom(), start, true, startIndent, line) - if (this.tok.type == __acorn.tokTypes.parenL) { - node.arguments = this.parseExprList(__acorn.tokTypes.parenR) + var start = this.storeCurrentPos(); + node.callee = this.parseSubscripts(this.parseExprAtom(), start, true, startIndent, line); + if (this.tok.type === acorn.tokTypes.parenL) { + node.arguments = this.parseExprList(acorn.tokTypes.parenR); } else { - node.arguments = [] + node.arguments = []; } return this.finishNode(node, "NewExpression") -} +}; lp$2.parseTemplateElement = function() { - var elem = this.startNode() - elem.value = { - raw: this.input.slice(this.tok.start, this.tok.end).replace(/\r\n?/g, "\n"), - cooked: this.tok.value + var elem = this.startNode(); + + // The loose parser accepts invalid unicode escapes even in untagged templates. + if (this.tok.type === acorn.tokTypes.invalidTemplate) { + elem.value = { + raw: this.tok.value, + cooked: null + }; + } else { + elem.value = { + raw: this.input.slice(this.tok.start, this.tok.end).replace(/\r\n?/g, "\n"), + cooked: this.tok.value + }; } - this.next() - elem.tail = this.tok.type === __acorn.tokTypes.backQuote + this.next(); + elem.tail = this.tok.type === acorn.tokTypes.backQuote; return this.finishNode(elem, "TemplateElement") -} +}; lp$2.parseTemplate = function() { var this$1 = this; - var node = this.startNode() - this.next() - node.expressions = [] - var curElt = this.parseTemplateElement() - node.quasis = [curElt] + var node = this.startNode(); + this.next(); + node.expressions = []; + var curElt = this.parseTemplateElement(); + node.quasis = [curElt]; while (!curElt.tail) { - this$1.next() - node.expressions.push(this$1.parseExpression()) - if (this$1.expect(__acorn.tokTypes.braceR)) { - curElt = this$1.parseTemplateElement() + this$1.next(); + node.expressions.push(this$1.parseExpression()); + if (this$1.expect(acorn.tokTypes.braceR)) { + curElt = this$1.parseTemplateElement(); } else { - curElt = this$1.startNode() - curElt.value = {cooked: "", raw: ""} - curElt.tail = true - this$1.finishNode(curElt, "TemplateElement") + curElt = this$1.startNode(); + curElt.value = {cooked: "", raw: ""}; + curElt.tail = true; + this$1.finishNode(curElt, "TemplateElement"); } - node.quasis.push(curElt) + node.quasis.push(curElt); } - this.expect(__acorn.tokTypes.backQuote) + this.expect(acorn.tokTypes.backQuote); return this.finishNode(node, "TemplateLiteral") -} +}; lp$2.parseObj = function() { var this$1 = this; - var node = this.startNode() - node.properties = [] - this.pushCx() - var indent = this.curIndent + 1, line = this.curLineStart - this.eat(__acorn.tokTypes.braceL) - if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart } - while (!this.closes(__acorn.tokTypes.braceR, indent, line)) { - var prop = this$1.startNode(), isGenerator, isAsync, start + var node = this.startNode(); + node.properties = []; + this.pushCx(); + var indent = this.curIndent + 1, line = this.curLineStart; + this.eat(acorn.tokTypes.braceL); + if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart; } + while (!this.closes(acorn.tokTypes.braceR, indent, line)) { + var prop = this$1.startNode(), isGenerator = (void 0), isAsync = (void 0), start = (void 0); + if (this$1.options.ecmaVersion >= 9 && this$1.eat(acorn.tokTypes.ellipsis)) { + prop.argument = this$1.parseMaybeAssign(); + node.properties.push(this$1.finishNode(prop, "SpreadElement")); + this$1.eat(acorn.tokTypes.comma); + continue + } if (this$1.options.ecmaVersion >= 6) { - start = this$1.storeCurrentPos() - prop.method = false - prop.shorthand = false - isGenerator = this$1.eat(__acorn.tokTypes.star) + start = this$1.storeCurrentPos(); + prop.method = false; + prop.shorthand = false; + isGenerator = this$1.eat(acorn.tokTypes.star); } - this$1.parsePropertyName(prop) - if (!prop.computed && - prop.key.type === "Identifier" && prop.key.name === "async" && this$1.tok.type !== __acorn.tokTypes.parenL && - this$1.tok.type !== __acorn.tokTypes.colon && !this$1.canInsertSemicolon()) { - this$1.parsePropertyName(prop) - isAsync = true + this$1.parsePropertyName(prop); + if (this$1.toks.isAsyncProp(prop)) { + isAsync = true; + isGenerator = this$1.options.ecmaVersion >= 9 && this$1.eat(acorn.tokTypes.star); + this$1.parsePropertyName(prop); } else { - isAsync = false + isAsync = false; } - if (isDummy(prop.key)) { if (isDummy(this$1.parseMaybeAssign())) this$1.next(); this$1.eat(__acorn.tokTypes.comma); continue } - if (this$1.eat(__acorn.tokTypes.colon)) { - prop.kind = "init" - prop.value = this$1.parseMaybeAssign() - } else if (this$1.options.ecmaVersion >= 6 && (this$1.tok.type === __acorn.tokTypes.parenL || this$1.tok.type === __acorn.tokTypes.braceL)) { - prop.kind = "init" - prop.method = true - prop.value = this$1.parseMethod(isGenerator, isAsync) + if (isDummy(prop.key)) { if (isDummy(this$1.parseMaybeAssign())) { this$1.next(); } this$1.eat(acorn.tokTypes.comma); continue } + if (this$1.eat(acorn.tokTypes.colon)) { + prop.kind = "init"; + prop.value = this$1.parseMaybeAssign(); + } else if (this$1.options.ecmaVersion >= 6 && (this$1.tok.type === acorn.tokTypes.parenL || this$1.tok.type === acorn.tokTypes.braceL)) { + prop.kind = "init"; + prop.method = true; + prop.value = this$1.parseMethod(isGenerator, isAsync); } else if (this$1.options.ecmaVersion >= 5 && prop.key.type === "Identifier" && !prop.computed && (prop.key.name === "get" || prop.key.name === "set") && - (this$1.tok.type != __acorn.tokTypes.comma && this$1.tok.type != __acorn.tokTypes.braceR)) { - prop.kind = prop.key.name - this$1.parsePropertyName(prop) - prop.value = this$1.parseMethod(false) + (this$1.tok.type !== acorn.tokTypes.comma && this$1.tok.type !== acorn.tokTypes.braceR && this$1.tok.type !== acorn.tokTypes.eq)) { + prop.kind = prop.key.name; + this$1.parsePropertyName(prop); + prop.value = this$1.parseMethod(false); } else { - prop.kind = "init" + prop.kind = "init"; if (this$1.options.ecmaVersion >= 6) { - if (this$1.eat(__acorn.tokTypes.eq)) { - var assign = this$1.startNodeAt(start) - assign.operator = "=" - assign.left = prop.key - assign.right = this$1.parseMaybeAssign() - prop.value = this$1.finishNode(assign, "AssignmentExpression") + if (this$1.eat(acorn.tokTypes.eq)) { + var assign = this$1.startNodeAt(start); + assign.operator = "="; + assign.left = prop.key; + assign.right = this$1.parseMaybeAssign(); + prop.value = this$1.finishNode(assign, "AssignmentExpression"); } else { - prop.value = prop.key + prop.value = prop.key; } } else { - prop.value = this$1.dummyIdent() + prop.value = this$1.dummyIdent(); } - prop.shorthand = true + prop.shorthand = true; } - node.properties.push(this$1.finishNode(prop, "Property")) - this$1.eat(__acorn.tokTypes.comma) + node.properties.push(this$1.finishNode(prop, "Property")); + this$1.eat(acorn.tokTypes.comma); } - this.popCx() - if (!this.eat(__acorn.tokTypes.braceR)) { + this.popCx(); + if (!this.eat(acorn.tokTypes.braceR)) { // If there is no closing brace, make the node span to the start // of the next token (this is useful for Tern) - this.last.end = this.tok.start - if (this.options.locations) this.last.loc.end = this.tok.loc.start + this.last.end = this.tok.start; + if (this.options.locations) { this.last.loc.end = this.tok.loc.start; } } return this.finishNode(node, "ObjectExpression") -} +}; lp$2.parsePropertyName = function(prop) { if (this.options.ecmaVersion >= 6) { - if (this.eat(__acorn.tokTypes.bracketL)) { - prop.computed = true - prop.key = this.parseExpression() - this.expect(__acorn.tokTypes.bracketR) + if (this.eat(acorn.tokTypes.bracketL)) { + prop.computed = true; + prop.key = this.parseExpression(); + this.expect(acorn.tokTypes.bracketR); return } else { - prop.computed = false + prop.computed = false; } } - var key = (this.tok.type === __acorn.tokTypes.num || this.tok.type === __acorn.tokTypes.string) ? this.parseExprAtom() : this.parseIdent() - prop.key = key || this.dummyIdent() -} + var key = (this.tok.type === acorn.tokTypes.num || this.tok.type === acorn.tokTypes.string) ? this.parseExprAtom() : this.parseIdent(); + prop.key = key || this.dummyIdent(); +}; lp$2.parsePropertyAccessor = function() { - if (this.tok.type === __acorn.tokTypes.name || this.tok.type.keyword) return this.parseIdent() -} + if (this.tok.type === acorn.tokTypes.name || this.tok.type.keyword) { return this.parseIdent() } +}; lp$2.parseIdent = function() { - var name = this.tok.type === __acorn.tokTypes.name ? this.tok.value : this.tok.type.keyword - if (!name) return this.dummyIdent() - var node = this.startNode() - this.next() - node.name = name + var name = this.tok.type === acorn.tokTypes.name ? this.tok.value : this.tok.type.keyword; + if (!name) { return this.dummyIdent() } + var node = this.startNode(); + this.next(); + node.name = name; return this.finishNode(node, "Identifier") -} +}; lp$2.initFunction = function(node) { - node.id = null - node.params = [] + node.id = null; + node.params = []; if (this.options.ecmaVersion >= 6) { - node.generator = false - node.expression = false + node.generator = false; + node.expression = false; } if (this.options.ecmaVersion >= 8) - node.async = false -} + { node.async = false; } +}; // Convert existing expression atom to assignable pattern // if possible. @@ -1222,117 +1263,135 @@ lp$2.toAssignable = function(node, binding) { var this$1 = this; - if (!node || node.type == "Identifier" || (node.type == "MemberExpression" && !binding)) { + if (!node || node.type === "Identifier" || (node.type === "MemberExpression" && !binding)) { // Okay - } else if (node.type == "ParenthesizedExpression") { - node.expression = this.toAssignable(node.expression, binding) + } else if (node.type === "ParenthesizedExpression") { + this.toAssignable(node.expression, binding); } else if (this.options.ecmaVersion < 6) { return this.dummyIdent() - } else if (node.type == "ObjectExpression") { - node.type = "ObjectPattern" - var props = node.properties - for (var i = 0; i < props.length; i++) - props[i].value = this$1.toAssignable(props[i].value, binding) - } else if (node.type == "ArrayExpression") { - node.type = "ArrayPattern" - this.toAssignableList(node.elements, binding) - } else if (node.type == "SpreadElement") { - node.type = "RestElement" - node.argument = this.toAssignable(node.argument, binding) - } else if (node.type == "AssignmentExpression") { - node.type = "AssignmentPattern" - delete node.operator + } else if (node.type === "ObjectExpression") { + node.type = "ObjectPattern"; + for (var i = 0, list = node.properties; i < list.length; i += 1) + { + var prop = list[i]; + + this$1.toAssignable(prop, binding); + } + } else if (node.type === "ArrayExpression") { + node.type = "ArrayPattern"; + this.toAssignableList(node.elements, binding); + } else if (node.type === "Property") { + this.toAssignable(node.value, binding); + } else if (node.type === "SpreadElement") { + node.type = "RestElement"; + this.toAssignable(node.argument, binding); + } else if (node.type === "AssignmentExpression") { + node.type = "AssignmentPattern"; + delete node.operator; } else { return this.dummyIdent() } return node -} +}; lp$2.toAssignableList = function(exprList, binding) { var this$1 = this; - for (var i = 0; i < exprList.length; i++) - exprList[i] = this$1.toAssignable(exprList[i], binding) + for (var i = 0, list = exprList; i < list.length; i += 1) + { + var expr = list[i]; + + this$1.toAssignable(expr, binding); + } return exprList -} +}; lp$2.parseFunctionParams = function(params) { - params = this.parseExprList(__acorn.tokTypes.parenR) + params = this.parseExprList(acorn.tokTypes.parenR); return this.toAssignableList(params, true) -} +}; lp$2.parseMethod = function(isGenerator, isAsync) { - var node = this.startNode(), oldInAsync = this.inAsync - this.initFunction(node) + var node = this.startNode(), oldInAsync = this.inAsync, oldInFunction = this.inFunction; + this.initFunction(node); if (this.options.ecmaVersion >= 6) - node.generator = !!isGenerator + { node.generator = !!isGenerator; } if (this.options.ecmaVersion >= 8) - node.async = !!isAsync - this.inAsync = node.async - node.params = this.parseFunctionParams() - node.expression = this.options.ecmaVersion >= 6 && this.tok.type !== __acorn.tokTypes.braceL - node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock() - this.inAsync = oldInAsync + { node.async = !!isAsync; } + this.inAsync = node.async; + this.inFunction = true; + node.params = this.parseFunctionParams(); + node.body = this.parseBlock(); + this.toks.adaptDirectivePrologue(node.body.body); + this.inAsync = oldInAsync; + this.inFunction = oldInFunction; return this.finishNode(node, "FunctionExpression") -} +}; lp$2.parseArrowExpression = function(node, params, isAsync) { - var oldInAsync = this.inAsync - this.initFunction(node) + var oldInAsync = this.inAsync, oldInFunction = this.inFunction; + this.initFunction(node); if (this.options.ecmaVersion >= 8) - node.async = !!isAsync - this.inAsync = node.async - node.params = this.toAssignableList(params, true) - node.expression = this.tok.type !== __acorn.tokTypes.braceL - node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock() - this.inAsync = oldInAsync + { node.async = !!isAsync; } + this.inAsync = node.async; + this.inFunction = true; + node.params = this.toAssignableList(params, true); + node.expression = this.tok.type !== acorn.tokTypes.braceL; + if (node.expression) { + node.body = this.parseMaybeAssign(); + } else { + node.body = this.parseBlock(); + this.toks.adaptDirectivePrologue(node.body.body); + } + this.inAsync = oldInAsync; + this.inFunction = oldInFunction; return this.finishNode(node, "ArrowFunctionExpression") -} +}; lp$2.parseExprList = function(close, allowEmpty) { var this$1 = this; - this.pushCx() - var indent = this.curIndent, line = this.curLineStart, elts = [] - this.next() // Opening bracket + this.pushCx(); + var indent = this.curIndent, line = this.curLineStart, elts = []; + this.next(); // Opening bracket while (!this.closes(close, indent + 1, line)) { - if (this$1.eat(__acorn.tokTypes.comma)) { - elts.push(allowEmpty ? null : this$1.dummyIdent()) + if (this$1.eat(acorn.tokTypes.comma)) { + elts.push(allowEmpty ? null : this$1.dummyIdent()); continue } - var elt = this$1.parseMaybeAssign() + var elt = this$1.parseMaybeAssign(); if (isDummy(elt)) { - if (this$1.closes(close, indent, line)) break - this$1.next() + if (this$1.closes(close, indent, line)) { break } + this$1.next(); } else { - elts.push(elt) + elts.push(elt); } - this$1.eat(__acorn.tokTypes.comma) + this$1.eat(acorn.tokTypes.comma); } - this.popCx() + this.popCx(); if (!this.eat(close)) { // If there is no closing brace, make the node span to the start // of the next token (this is useful for Tern) - this.last.end = this.tok.start - if (this.options.locations) this.last.loc.end = this.tok.loc.start + this.last.end = this.tok.start; + if (this.options.locations) { this.last.loc.end = this.tok.loc.start; } } return elts -} +}; lp$2.parseAwait = function() { - var node = this.startNode() - this.next() - node.argument = this.parseMaybeUnary() + var node = this.startNode(); + this.next(); + node.argument = this.parseMaybeUnary(); return this.finishNode(node, "AwaitExpression") -} +}; // Acorn: Loose parser // -// This module provides an alternative parser (`parse_dammit`) that -// exposes that same interface as `parse`, but will try to parse -// anything as JavaScript, repairing syntax error the best it can. -// There are circumstances in which it will raise an error and give -// up, but they are very rare. The resulting AST will be a mostly +// This module provides an alternative parser that exposes that same +// interface as the main module's `parse` function, but will try to +// parse anything as JavaScript, repairing syntax error the best it +// can. There are circumstances in which it will raise an error and +// give up, but they are very rare. The resulting AST will be a mostly // valid JavaScript AST (as per the [Mozilla parser API][api], except // that: // @@ -1347,9 +1406,9 @@ // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API // // The expected use for this is to *first* try `acorn.parse`, and only -// if that fails switch to `parse_dammit`. The loose parser might -// parse badly indented code incorrectly, so **don't** use it as -// your default parser. +// if that fails switch to the loose parser. The loose parser might +// parse badly indented code incorrectly, so **don't** use it as your +// default parser. // // Quite a lot of acorn.js is duplicated here. The alternative was to // add a *lot* of extra cruft to that file, making it less readable @@ -1357,20 +1416,14 @@ // invasive changes and simplifications without creating a complicated // tangle. -__acorn.defaultOptions.tabSize = 4 +acorn.defaultOptions.tabSize = 4; -// eslint-disable-next-line camelcase -function parse_dammit(input, options) { - var p = new LooseParser(input, options) - p.next() - return p.parseTopLevel() +function parse(input, options) { + return LooseParser.parse(input, options) } -__acorn.addLooseExports(parse_dammit, LooseParser, pluginsLoose) - -exports.parse_dammit = parse_dammit; +exports.parse = parse; exports.LooseParser = LooseParser; -exports.pluginsLoose = pluginsLoose; Object.defineProperty(exports, '__esModule', { value: true });
diff --git a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc index 6bdb1ba..96a85b3 100644 --- a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc +++ b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
@@ -302,8 +302,7 @@ ExecutionContext* execution_context = ExecutionContext::From(script_state); Document* document = ToDocument(execution_context); - if (!document->GetFrame() || - !document->GetFrame()->DeprecatedIsFeatureEnabled( + if (!document->IsFeatureEnabled( mojom::FeaturePolicyFeature::kEncryptedMedia)) { UseCounter::Count(document, WebFeature::kEncryptedMediaDisabledByFeaturePolicy);
diff --git a/third_party/blink/renderer/modules/filesystem/README.md b/third_party/blink/renderer/modules/filesystem/README.md new file mode 100644 index 0000000..6e3f3df --- /dev/null +++ b/third_party/blink/renderer/modules/filesystem/README.md
@@ -0,0 +1,74 @@ +# FileSystem API + +This directory contains the renderer side implementation of various filesystem +related APIs. + +## Related directories + +[`//storage/browser/fileapi/`](../../../storage/browser/fileapi) contains part +of the browser side implementation, while +[`//content/browser/fileapi/`](../../../content/browser/fileapi) contains the +rest of the browser side implementation and +[`blink/public/mojom/filesystem`](../../../third_party/blink/public/mojom/filesystem) +contains the mojom interfaces for these APIs. + +## APIs In this directory + +### File and Directory Entries API + +First of all this directory contains the implementation of the +[Entries API](https://wicg.github.io/entries-api). This API consists of +types to expose read-only access to file and directory entries to the web, +primarily used by drag-and-drop and `<input type=file>`. Our implementation +doesn't match the interface names of the spec, but otherwise should be pretty +close to the spec. + +TODO(mek): More details + +### File API: Directories and FileSystem + +Secondly this directory contains the implementation of something similar to the +deprecated [w3c file-system-api](https://www.w3.org/TR/2012/WD-file-system-api-20120417/). +This API is very similar to the previous Entries API, but it also adds support +for writing and modifying to files and directories, as well as a way to get +access to a origin scoped sandboxed filesystem. + +TODO(mek): More details + +### Writable Files + +Finally this directory contains the implementation of the new and still under +development [Writable Files API](https://github.com/WICG/writable-files/blob/master/EXPLAINER.md). +This API is mostly implemented on top of the same backend as the previous two +APIs, but hopes to eventually replace both of those, while also adding new +functionality. + +It consists of the following parts: + + * `FileSystemBaseHandle`, `FileSystemFileHandle` and `FileSystemDirectoryHandle`: + these interfaces mimic the old `Entry` interfaces (and inherit from `EntryBase` + to share as much of the implementation as possible), but expose a more modern + promisified API. + + * `getSystemDirectory`: An entry point (exposed via `FileSystemDirectoryHandle`) + that today only gives access to the same sandboxed filesystem as what was + available through the old API. In the future this could get extended to add + support for other directories as well. + + * `FileSystemWriter`: a more modern API with similar functionality to the + old `FileWriter` API. The implementation of this actually does make use of + a different mojom interface than the old API. But since the functionality is + mostly the same, hopefully we will be able to migrate the old implementation + to the new mojom API as well. + + * `chooseFileSystemEntries`: An entry point, currently on `window`, that lets + a website pop-up a file picker, prompting the user to select one or more + files or directories, to which the website than gets access. + +Since the `Handle` interfaces are based on the implementation of the `Entry` +interfaces, internally and across IPC these are still represented by +`filesystem://` URLs. Hopefully in the future we will be able to change this and +turn it into a more capabilities based API (where having a mojo handle gives you +access to specific files or directories), as with the current implementation it +is very hard to properly support transferring handles to other processes via +postMessage (which is something we do want to support in the future).
diff --git a/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl b/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl new file mode 100644 index 0000000..8e50e6f --- /dev/null +++ b/third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.idl
@@ -0,0 +1,11 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// https://github.com/WICG/writable-files/blob/master/EXPLAINER.md +enum ChooseFileSystemEntriesType { "openFile", "saveFile", "openDirectory" }; + +dictionary ChooseFileSystemEntriesOptions { + ChooseFileSystemEntriesType type = "openFile"; + boolean multiple = false; +};
diff --git a/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc b/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc index f3bcda2..049e3dd 100644 --- a/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc +++ b/third_party/blink/renderer/modules/filesystem/dom_window_file_system.cc
@@ -135,7 +135,8 @@ ScriptPromise DOMWindowFileSystem::chooseFileSystemEntries( ScriptState* script_state, - LocalDOMWindow& window) { + LocalDOMWindow& window, + const ChooseFileSystemEntriesOptions& options) { if (!window.IsCurrentlyDisplayedInFrame()) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kAbortError)); @@ -157,7 +158,7 @@ auto* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromise result = resolver->Promise(); - LocalFileSystem::From(*document)->ChooseEntry(resolver); + LocalFileSystem::From(*document)->ChooseEntry(resolver, options); return result; }
diff --git a/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h b/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h index a12e3be..8d4264d 100644 --- a/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h +++ b/third_party/blink/renderer/modules/filesystem/dom_window_file_system.h
@@ -32,6 +32,7 @@ namespace blink { +class ChooseFileSystemEntriesOptions; class LocalDOMWindow; class ScriptPromise; class ScriptState; @@ -60,7 +61,10 @@ kPersistent, }; - static ScriptPromise chooseFileSystemEntries(ScriptState*, LocalDOMWindow&); + static ScriptPromise chooseFileSystemEntries( + ScriptState*, + LocalDOMWindow&, + const ChooseFileSystemEntriesOptions&); }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc index ec80085..1a26eeb 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc +++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
@@ -436,18 +436,20 @@ } void FileSystemDispatcher::ChooseEntry( + mojom::blink::ChooseFileSystemEntryType type, std::unique_ptr<ChooseEntryCallbacks> callbacks) { - GetFileSystemManager().ChooseEntry(WTF::Bind( - [](std::unique_ptr<ChooseEntryCallbacks> callbacks, - base::File::Error result, - Vector<mojom::blink::FileSystemEntryPtr> entries) { - if (result != base::File::FILE_OK) { - callbacks->OnError(result); - } else { - callbacks->OnSuccess(std::move(entries)); - } - }, - std::move(callbacks))); + GetFileSystemManager().ChooseEntry( + type, WTF::Bind( + [](std::unique_ptr<ChooseEntryCallbacks> callbacks, + base::File::Error result, + Vector<mojom::blink::FileSystemEntryPtr> entries) { + if (result != base::File::FILE_OK) { + callbacks->OnError(result); + } else { + callbacks->OnSuccess(std::move(entries)); + } + }, + std::move(callbacks))); } mojom::blink::FileSystemManager& FileSystemDispatcher::GetFileSystemManager() {
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h index d8a899a..bbee2b8 100644 --- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h +++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
@@ -143,7 +143,8 @@ using ChooseEntryCallbacks = WebCallbacks<Vector<mojom::blink::FileSystemEntryPtr>, base::File::Error>; - void ChooseEntry(std::unique_ptr<ChooseEntryCallbacks> callbacks); + void ChooseEntry(mojom::blink::ChooseFileSystemEntryType, + std::unique_ptr<ChooseEntryCallbacks> callbacks); private: class WriteListener;
diff --git a/third_party/blink/renderer/modules/filesystem/local_file_system.cc b/third_party/blink/renderer/modules/filesystem/local_file_system.cc index 29c34b3..1c2b1ed3 100644 --- a/third_party/blink/renderer/modules/filesystem/local_file_system.cc +++ b/third_party/blink/renderer/modules/filesystem/local_file_system.cc
@@ -43,6 +43,7 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h" +#include "third_party/blink/renderer/modules/filesystem/choose_file_system_entries_options.h" #include "third_party/blink/renderer/modules/filesystem/directory_entry.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h" #include "third_party/blink/renderer/modules/filesystem/file_system_client.h" @@ -119,12 +120,13 @@ : public WebCallbacks<Vector<mojom::blink::FileSystemEntryPtr>, base::File::Error> { public: - ChooseEntryCallbacks(ScriptPromiseResolver* resolver, bool return_multiple) - : resolver_(resolver), return_multiple_(return_multiple) {} + ChooseEntryCallbacks(ScriptPromiseResolver* resolver, + const ChooseFileSystemEntriesOptions& options) + : resolver_(resolver), options_(options) {} void OnSuccess(Vector<mojom::blink::FileSystemEntryPtr> entries) override { ScriptState::Scope scope(resolver_->GetScriptState()); - if (return_multiple_) { + if (options_.multiple()) { Vector<ScriptPromise> result; result.ReserveInitialCapacity(entries.size()); for (const auto& entry : entries) @@ -151,19 +153,43 @@ resolver_->GetExecutionContext(), entry->file_system_id); // TODO(mek): Try to create handle directly rather than having to do more // IPCs to get the actual entries. - fs->GetFile(fs->root(), entry->base_name, FileSystemFlags(), - new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver), - new PromiseErrorCallback(new_resolver)); + if (options_.type() == "openDirectory") { + fs->GetDirectory( + fs->root(), entry->base_name, FileSystemFlags(), + new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver), + new PromiseErrorCallback(new_resolver)); + } else { + fs->GetFile(fs->root(), entry->base_name, FileSystemFlags(), + new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver), + new PromiseErrorCallback(new_resolver)); + } return result; } Persistent<ScriptPromiseResolver> resolver_; - bool return_multiple_; + ChooseFileSystemEntriesOptions options_; }; +mojom::blink::ChooseFileSystemEntryType ConvertChooserType(const String& input, + bool multiple) { + if (input == "openFile") { + return multiple + ? mojom::blink::ChooseFileSystemEntryType::kOpenMultipleFiles + : mojom::blink::ChooseFileSystemEntryType::kOpenFile; + } + if (input == "saveFile") + return mojom::blink::ChooseFileSystemEntryType::kSaveFile; + if (input == "openDirectory") + return mojom::blink::ChooseFileSystemEntryType::kOpenDirectory; + NOTREACHED(); + return mojom::blink::ChooseFileSystemEntryType::kOpenFile; +} + } // namespace -void LocalFileSystem::ChooseEntry(ScriptPromiseResolver* resolver) { +void LocalFileSystem::ChooseEntry( + ScriptPromiseResolver* resolver, + const ChooseFileSystemEntriesOptions& options) { if (!base::FeatureList::IsEnabled(blink::features::kWritableFilesAPI)) { resolver->Reject( FileError::CreateDOMException(base::File::FILE_ERROR_ABORT)); @@ -171,7 +197,8 @@ } FileSystemDispatcher::From(resolver->GetExecutionContext()) - .ChooseEntry(std::make_unique<ChooseEntryCallbacks>(resolver, false)); + .ChooseEntry(ConvertChooserType(options.type(), options.multiple()), + std::make_unique<ChooseEntryCallbacks>(resolver, options)); } void LocalFileSystem::RequestFileSystemAccessInternal(
diff --git a/third_party/blink/renderer/modules/filesystem/local_file_system.h b/third_party/blink/renderer/modules/filesystem/local_file_system.h index b137d0e9..5a4a6fa 100644 --- a/third_party/blink/renderer/modules/filesystem/local_file_system.h +++ b/third_party/blink/renderer/modules/filesystem/local_file_system.h
@@ -45,6 +45,7 @@ class AsyncFileSystemCallbacks; class CallbackWrapper; +class ChooseFileSystemEntriesOptions; class FileSystemClient; class ExecutionContext; class KURL; @@ -76,7 +77,8 @@ std::unique_ptr<AsyncFileSystemCallbacks>, SynchronousType sync_type); - void ChooseEntry(ScriptPromiseResolver*); + void ChooseEntry(ScriptPromiseResolver*, + const ChooseFileSystemEntriesOptions& options); FileSystemClient& Client() const { return *client_; }
diff --git a/third_party/blink/renderer/modules/filesystem/window_file_system.idl b/third_party/blink/renderer/modules/filesystem/window_file_system.idl index 3259df9f..ed10797d 100644 --- a/third_party/blink/renderer/modules/filesystem/window_file_system.idl +++ b/third_party/blink/renderer/modules/filesystem/window_file_system.idl
@@ -41,5 +41,6 @@ // https://github.com/WICG/writable-files/blob/master/EXPLAINER.md // TODO(crbug.com/878581): This needs some kind of options dictionary. [RuntimeEnabled=WritableFiles, CallWith=ScriptState, SecureContext] - Promise<(FileSystemBaseHandle or sequence<FileSystemBaseHandle>)> chooseFileSystemEntries(); + Promise<(FileSystemBaseHandle or sequence<FileSystemBaseHandle>)> + chooseFileSystemEntries(optional ChooseFileSystemEntriesOptions options); };
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation.cc b/third_party/blink/renderer/modules/geolocation/geolocation.cc index c0eda1e..d170d78 100644 --- a/third_party/blink/renderer/modules/geolocation/geolocation.cc +++ b/third_party/blink/renderer/modules/geolocation/geolocation.cc
@@ -224,7 +224,7 @@ return; } - if (!GetFrame()->DeprecatedIsFeatureEnabled( + if (!GetDocument()->IsFeatureEnabled( mojom::FeaturePolicyFeature::kGeolocation, ReportOptions::kReportOnFailure)) { UseCounter::Count(GetDocument(),
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc index 09a493d..051df45 100644 --- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc +++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -492,17 +492,15 @@ // Feature policy deprecation messages. if (Audio()) { - if (!document->GetFrame()->DeprecatedIsFeatureEnabled( - mojom::FeaturePolicyFeature::kMicrophone, - ReportOptions::kReportOnFailure)) { + if (!document->IsFeatureEnabled(mojom::FeaturePolicyFeature::kMicrophone, + ReportOptions::kReportOnFailure)) { UseCounter::Count( document, WebFeature::kMicrophoneDisabledByFeaturePolicyEstimate); } } if (Video()) { - if (!document->GetFrame()->DeprecatedIsFeatureEnabled( - mojom::FeaturePolicyFeature::kCamera, - ReportOptions::kReportOnFailure)) { + if (!document->IsFeatureEnabled(mojom::FeaturePolicyFeature::kCamera, + ReportOptions::kReportOnFailure)) { UseCounter::Count(document, WebFeature::kCameraDisabledByFeaturePolicyEstimate); }
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index 928eb865..63c25f79 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -524,6 +524,7 @@ "encryptedmedia/media_key_system_configuration.idl", "encryptedmedia/media_key_system_media_capability.idl", "eventsource/event_source_init.idl", + "filesystem/choose_file_system_entries_options.idl", "filesystem/file_system_directory_iterator_entry.idl", "filesystem/file_system_flags.idl", "filesystem/file_system_get_directory_options.idl",
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc index ed942e0e..f6cb9237 100644 --- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc +++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -54,7 +54,7 @@ // If document is not allowed to use the policy-controlled feature named // "picture-in-picture", return kDisabledByFeaturePolicy status. if (RuntimeEnabledFeatures::PictureInPictureAPIEnabled() && - !frame->DeprecatedIsFeatureEnabled( + !GetSupplementable()->IsFeatureEnabled( blink::mojom::FeaturePolicyFeature::kPictureInPicture)) { return Status::kDisabledByFeaturePolicy; }
diff --git a/third_party/blink/renderer/modules/sensor/sensor.cc b/third_party/blink/renderer/modules/sensor/sensor.cc index 2c96cf8..1a7a8a9c 100644 --- a/third_party/blink/renderer/modules/sensor/sensor.cc +++ b/third_party/blink/renderer/modules/sensor/sensor.cc
@@ -22,11 +22,11 @@ namespace { const double kWaitingIntervalThreshold = 0.01; -bool AreFeaturesEnabled(LocalFrame* frame, +bool AreFeaturesEnabled(Document* document, const Vector<mojom::FeaturePolicyFeature>& features) { return std::all_of(features.begin(), features.end(), - [frame](mojom::FeaturePolicyFeature feature) { - return frame->DeprecatedIsFeatureEnabled(feature); + [document](mojom::FeaturePolicyFeature feature) { + return document->IsFeatureEnabled(feature); }); } @@ -45,9 +45,9 @@ // [SecureContext] in idl. DCHECK(execution_context->IsSecureContext()); DCHECK(!features.IsEmpty()); - LocalFrame* frame = ToDocument(execution_context)->GetFrame(); + Document* document = ToDocument(execution_context); - if (!frame || !AreFeaturesEnabled(frame, features)) { + if (!AreFeaturesEnabled(document, features)) { exception_state.ThrowSecurityError( "Access to sensor features is disallowed by feature policy"); return;
diff --git a/third_party/blink/renderer/modules/vr/navigator_vr.cc b/third_party/blink/renderer/modules/vr/navigator_vr.cc index 01dae7eb..02bfb83c 100644 --- a/third_party/blink/renderer/modules/vr/navigator_vr.cc +++ b/third_party/blink/renderer/modules/vr/navigator_vr.cc
@@ -144,8 +144,8 @@ script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError, kNotAssociatedWithDocumentMessage)); } - if (!frame->DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr, - ReportOptions::kReportOnFailure)) { + if (!GetDocument()->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr, + ReportOptions::kReportOnFailure)) { return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kSecurityError, kFeaturePolicyBlockedMessage));
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc index 3c9f39d..335177b 100644 --- a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc +++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
@@ -119,9 +119,6 @@ } GetDeferredTaskHandler().ContextWillBeDestroyed(); - DCHECK(!active_source_nodes_.size()); - DCHECK(!is_resolving_resume_promises_); - DCHECK(!resume_resolvers_.size()); } void BaseAudioContext::Initialize() { @@ -179,6 +176,10 @@ listener_->WaitForHRTFDatabaseLoaderThreadCompletion(); Clear(); + + DCHECK(!is_resolving_resume_promises_); + DCHECK_EQ(resume_resolvers_.size(), 0u); + DCHECK_EQ(active_source_nodes_.size(), 0u); } void BaseAudioContext::ContextDestroyed(ExecutionContext*) {
diff --git a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc index 21ff4de..0b9d4e2b 100644 --- a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc +++ b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
@@ -102,9 +102,8 @@ UseCounter::CountCrossOriginIframe( document, WebFeature::kRequestMIDIAccessIframe_ObscuredByFootprinting); - if (!document.GetFrame()->DeprecatedIsFeatureEnabled( - mojom::FeaturePolicyFeature::kMidiFeature, - ReportOptions::kReportOnFailure)) { + if (!document.IsFeatureEnabled(mojom::FeaturePolicyFeature::kMidiFeature, + ReportOptions::kReportOnFailure)) { UseCounter::Count(document, WebFeature::kMidiDisabledByFeaturePolicy); document.AddConsoleMessage(ConsoleMessage::Create( kJSMessageSource, kWarningMessageLevel, kFeaturePolicyConsoleWarning));
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc index 8cb4dbb..6f6fd97 100644 --- a/third_party/blink/renderer/modules/xr/xr.cc +++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -73,9 +73,10 @@ did_log_requestDevice_ = true; } - if (!frame->DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr, - ReportOptions::kReportOnFailure)) { - // Only allow the call to be made if the appropraite feature policy is in + if (!frame->GetDocument()->IsFeatureEnabled( + mojom::FeaturePolicyFeature::kWebVr, + ReportOptions::kReportOnFailure)) { + // Only allow the call to be made if the appropriate feature policy is in // place. return ScriptPromise::RejectWithDOMException( script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index ac1e91f..8b05ed3 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1228,11 +1228,6 @@ "plugins/plugin_data.h", "plugins/plugin_script_forbidden_scope.cc", "plugins/plugin_script_forbidden_scope.h", - "pod_arena.h", - "pod_free_list_arena.h", - "pod_interval.h", - "pod_interval_tree.h", - "pod_red_black_tree.h", "prerender.cc", "prerender.h", "prerender_client.h", @@ -1360,8 +1355,6 @@ "transforms/transformation_matrix.h", "transforms/translate_transform_operation.cc", "transforms/translate_transform_operation.h", - "ukm_time_aggregator.cc", - "ukm_time_aggregator.h", "uuid.cc", "uuid.h", "waitable_event.cc", @@ -1776,14 +1769,7 @@ "mojo/kurl_security_origin_test.cc", "mojo/string16_mojom_traits_test.cc", "plugins/plugin_data_test.cc", - "pod_arena_test.cc", - "pod_free_list_arena_test.cc", - "pod_interval_tree_test.cc", - "pod_red_black_tree_test.cc", "shared_buffer_test.cc", - "testing/arena_test_helpers.h", - "testing/tree_test_helpers.cc", - "testing/tree_test_helpers.h", "text/bidi_resolver_test.cc", "text/bidi_test_harness.h", "text/capitalize_test.cc", @@ -1807,7 +1793,6 @@ "transforms/rotation_test.cc", "transforms/transform_operations_test.cc", "transforms/transformation_matrix_test.cc", - "ukm_time_aggregator_test.cc", "uuid_test.cc", "web_icon_sizes_parser_test.cc", "web_screen_info_test.cc",
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc index ec6ee21b..19b7b58 100644 --- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc +++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -1150,13 +1150,13 @@ Vector<Glyph, 256> glyphs(num_glyphs); for (unsigned i = 0; i < num_glyphs; i++) glyphs[i] = run.glyph_data_[i].glyph; - Vector<FloatRect, 256> bounds_list(num_glyphs); + Vector<SkRect, 256> bounds_list(num_glyphs); current_font_data.BoundsForGlyphs(glyphs, &bounds_list); GlyphBoundsAccumulator bounds(width_); for (unsigned i = 0; i < num_glyphs; i++) { const HarfBuzzRunGlyphData& glyph_data = run.glyph_data_[i]; - bounds.Unite<is_horizontal_run>(glyph_data, bounds_list[i]); + bounds.Unite<is_horizontal_run>(glyph_data, FloatRect(bounds_list[i])); bounds.origin += glyph_data.advance; } #endif
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.cc b/third_party/blink/renderer/platform/fonts/simple_font_data.cc index 811beb0..520dad1 100644 --- a/third_party/blink/renderer/platform/fonts/simple_font_data.cc +++ b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
@@ -354,18 +354,15 @@ return FloatRect(bounds); } -void SimpleFontData::BoundsForGlyphs(const Vector<Glyph, 256> glyphs, - Vector<FloatRect, 256>* bounds) const { +void SimpleFontData::BoundsForGlyphs(const Vector<Glyph, 256>& glyphs, + Vector<SkRect, 256>* bounds) const { DCHECK_EQ(glyphs.size(), bounds->size()); if (!platform_data_.size()) return; - Vector<SkRect, 256> skia_bounds(glyphs.size()); - SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyphs(glyphs, skia_bounds.data()); - - for (unsigned i = 0; i < skia_bounds.size(); i++) - (*bounds)[i] = FloatRect(skia_bounds[i]); + DCHECK_EQ(bounds->size(), glyphs.size()); + SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyphs(glyphs, bounds->data()); } float SimpleFontData::PlatformWidthForGlyph(Glyph glyph) const {
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.h b/third_party/blink/renderer/platform/fonts/simple_font_data.h index ea751f5..cc4a85d2 100644 --- a/third_party/blink/renderer/platform/fonts/simple_font_data.h +++ b/third_party/blink/renderer/platform/fonts/simple_font_data.h
@@ -112,7 +112,7 @@ } FloatRect BoundsForGlyph(Glyph) const; - void BoundsForGlyphs(const Vector<Glyph, 256>, Vector<FloatRect, 256>*) const; + void BoundsForGlyphs(const Vector<Glyph, 256>&, Vector<SkRect, 256>*) const; FloatRect PlatformBoundsForGlyph(Glyph) const; float WidthForGlyph(Glyph) const; float PlatformWidthForGlyph(Glyph) const;
diff --git a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc index 9d7f4b5..77ec6209 100644 --- a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc +++ b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc
@@ -110,7 +110,7 @@ } } -void SkiaTextMetrics::GetSkiaBoundsForGlyphs(const Vector<Glyph, 256> glyphs, +void SkiaTextMetrics::GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>& glyphs, SkRect* bounds) { #if defined(OS_MACOSX) for (unsigned i = 0; i < glyphs.size(); i++) {
diff --git a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h index bd9c0a3..787d8af 100644 --- a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h +++ b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h
@@ -26,7 +26,7 @@ void GetGlyphExtentsForHarfBuzz(hb_codepoint_t, hb_glyph_extents_t*); void GetSkiaBoundsForGlyph(Glyph, SkRect* bounds); - void GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>, SkRect*); + void GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>&, SkRect*); float GetSkiaWidthForGlyph(Glyph); static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value);
diff --git a/third_party/blink/renderer/platform/fonts/skia/sktypeface_factory.cc b/third_party/blink/renderer/platform/fonts/skia/sktypeface_factory.cc index aa54588..c6a2daf 100644 --- a/third_party/blink/renderer/platform/fonts/skia/sktypeface_factory.cc +++ b/third_party/blink/renderer/platform/fonts/skia/sktypeface_factory.cc
@@ -15,7 +15,8 @@ sk_sp<SkTypeface> SkTypeface_Factory::FromFontConfigInterfaceIdAndTtcIndex( int config_id, int ttc_index) { -#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(OS_WIN) +#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && !defined(OS_WIN) && \ + !defined(OS_FUCHSIA) sk_sp<SkFontConfigInterface> fci(SkFontConfigInterface::RefGlobal()); SkFontConfigInterface::FontIdentity font_identity; font_identity.fID = config_id;
diff --git a/third_party/blink/renderer/platform/geometry/DEPS b/third_party/blink/renderer/platform/geometry/DEPS index 3d15f40..9b2fc5f 100644 --- a/third_party/blink/renderer/platform/geometry/DEPS +++ b/third_party/blink/renderer/platform/geometry/DEPS
@@ -10,7 +10,6 @@ "+third_party/blink/renderer/platform/json", "+third_party/blink/renderer/platform/layout_unit.h", "+third_party/blink/renderer/platform/platform_export.h", - "+third_party/blink/renderer/platform/pod_interval_tree.h", "+third_party/blink/renderer/platform/wtf", "+ui/gfx/geometry", ]
diff --git a/third_party/blink/renderer/platform/geometry/float_polygon.h b/third_party/blink/renderer/platform/geometry/float_polygon.h index 3fa1003..6a5150c 100644 --- a/third_party/blink/renderer/platform/geometry/float_polygon.h +++ b/third_party/blink/renderer/platform/geometry/float_polygon.h
@@ -32,20 +32,14 @@ #include "third_party/blink/renderer/platform/geometry/float_point.h" #include "third_party/blink/renderer/platform/geometry/float_rect.h" -#include "third_party/blink/renderer/platform/pod_interval_tree.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" +#include "third_party/blink/renderer/platform/wtf/pod_interval_tree.h" #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { class FloatPolygonEdge; -// This class is used by PODIntervalTree for debugging. -#ifndef NDEBUG -template <class> -struct ValueToString; -#endif - class PLATFORM_EXPORT FloatPolygon { USING_FAST_MALLOC(FloatPolygon); WTF_MAKE_NONCOPYABLE(FloatPolygon); @@ -68,8 +62,8 @@ bool IsEmpty() const { return empty_; } private: - typedef PODInterval<float, FloatPolygonEdge*> EdgeInterval; - typedef PODIntervalTree<float, FloatPolygonEdge*> EdgeIntervalTree; + typedef WTF::PODInterval<float, FloatPolygonEdge*> EdgeInterval; + typedef WTF::PODIntervalTree<float, FloatPolygonEdge*> EdgeIntervalTree; Vector<FloatPoint> vertices_; FloatRect bounding_box_; @@ -138,25 +132,21 @@ const FloatPolygon* polygon_; }; +} // namespace blink + +namespace WTF { // These structures are used by PODIntervalTree for debugging. #ifndef NDEBUG template <> -struct ValueToString<float> { +struct ValueToString<blink::FloatPolygonEdge*> { STATIC_ONLY(ValueToString); - static String ToString(const float value) { return String::Number(value); } -}; - -template <> -struct ValueToString<FloatPolygonEdge*> { - STATIC_ONLY(ValueToString); - static String ToString(const FloatPolygonEdge* edge) { + static String ToString(const blink::FloatPolygonEdge* edge) { return String::Format("%p (%f,%f %f,%f)", edge, edge->Vertex1().X(), edge->Vertex1().Y(), edge->Vertex2().X(), edge->Vertex2().Y()); } }; #endif - -} // namespace blink +} // namespace WTF #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_FLOAT_POLYGON_H_
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc index 4e7fab98..a9855ee1 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -160,6 +160,14 @@ {}) {} }; +class FrameSchedulerImplStopNonTimersInBackgroundDisabledTest + : public FrameSchedulerImplTest { + public: + FrameSchedulerImplStopNonTimersInBackgroundDisabledTest() + : FrameSchedulerImplTest({}, + {blink::features::kStopNonTimersInBackground}) {} +}; + namespace { class MockLifecycleObserver final : public FrameScheduler::Observer { @@ -391,7 +399,8 @@ EXPECT_EQ(5, counter); } -TEST_F(FrameSchedulerImplTest, PageFreezeAndUnfreezeFlagDisabled) { +TEST_F(FrameSchedulerImplStopNonTimersInBackgroundDisabledTest, + PageFreezeAndUnfreezeFlagDisabled) { int counter = 0; LoadingTaskQueue()->task_runner()->PostTask( FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter))); @@ -1612,6 +1621,8 @@ }; TEST_F(ThrottleableAndFreezableTaskTypesTest, QueueTraitsFromFieldTrialParams) { + if (base::FeatureList::IsEnabled(blink::features::kStopNonTimersInBackground)) + return; // These tests will start to fail if the default task queues or queue traits // change for these task types. @@ -1627,7 +1638,6 @@ task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits().SetCanBeFrozen(true).SetCanBePaused( true)); - task_queue = GetTaskQueue(TaskType::kDatabaseAccess); EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() .SetCanBeThrottled(true) @@ -1669,6 +1679,9 @@ }; TEST_F(FreezableOnlyTaskTypesTest, QueueTraitsFromFieldTrialParams) { + if (base::FeatureList::IsEnabled(blink::features::kStopNonTimersInBackground)) + return; + // These tests will start to fail if the default task queues or queue traits // change for these task types. @@ -1726,6 +1739,9 @@ }; TEST_F(ThrottleableOnlyTaskTypesTest, QueueTraitsFromFieldTrialParams) { + if (base::FeatureList::IsEnabled(blink::features::kStopNonTimersInBackground)) + return; + // These tests will start to fail if the default task queues or queue traits // change for these task types.
diff --git a/third_party/blink/renderer/platform/testing/DEPS b/third_party/blink/renderer/platform/testing/DEPS index a5014603..86347437 100644 --- a/third_party/blink/renderer/platform/testing/DEPS +++ b/third_party/blink/renderer/platform/testing/DEPS
@@ -31,7 +31,6 @@ "+third_party/blink/renderer/platform/loader", "+third_party/blink/renderer/platform/network", "+third_party/blink/renderer/platform/platform_export.h", - "+third_party/blink/renderer/platform/pod_arena.h", "+third_party/blink/renderer/platform/runtime_enabled_features.h", "+third_party/blink/renderer/platform/scheduler", "+third_party/blink/renderer/platform/scroll",
diff --git a/third_party/blink/renderer/platform/wtf/BUILD.gn b/third_party/blink/renderer/platform/wtf/BUILD.gn index 6b95b50..1ea11b0 100644 --- a/third_party/blink/renderer/platform/wtf/BUILD.gn +++ b/third_party/blink/renderer/platform/wtf/BUILD.gn
@@ -113,6 +113,11 @@ "math_extras.h", "noncopyable.h", "not_found.h", + "pod_arena.h", + "pod_free_list_arena.h", + "pod_interval.h", + "pod_interval_tree.h", + "pod_red_black_tree.h", "ref_counted.h", "ref_vector.h", "retain_ptr.h", @@ -320,6 +325,13 @@ "hash_set_test.cc", "list_hash_set_test.cc", "math_extras_test.cc", + "pod_arena_test.cc", + "pod_arena_test_helpers.h", + "pod_free_list_arena_test.cc", + "pod_interval_tree_test.cc", + "pod_red_black_tree_test.cc", + "pod_tree_test_helpers.cc", + "pod_tree_test_helpers.h", "saturated_arithmetic_test.cc", "scoped_logger_test.cc", "string_hasher_test.cc",
diff --git a/third_party/blink/renderer/platform/pod_arena.h b/third_party/blink/renderer/platform/wtf/pod_arena.h similarity index 96% rename from third_party/blink/renderer/platform/pod_arena.h rename to third_party/blink/renderer/platform/wtf/pod_arena.h index 75a08c1d..173c979 100644 --- a/third_party/blink/renderer/platform/pod_arena.h +++ b/third_party/blink/renderer/platform/wtf/pod_arena.h
@@ -23,8 +23,8 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_ARENA_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_ARENA_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_H_ #include <stdint.h> #include <memory> @@ -37,7 +37,7 @@ #include "third_party/blink/renderer/platform/wtf/ref_counted.h" #include "third_party/blink/renderer/platform/wtf/vector.h" -namespace blink { +namespace WTF { // An arena which allocates only Plain Old Data (POD), or classes and // structs bottoming out in Plain Old Data. NOTE: the constructors of @@ -191,6 +191,6 @@ Vector<std::unique_ptr<Chunk>> chunks_; }; -} // namespace blink +} // namespace WTF -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_ARENA_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_H_
diff --git a/third_party/blink/renderer/platform/pod_arena_test.cc b/third_party/blink/renderer/platform/wtf/pod_arena_test.cc similarity index 95% rename from third_party/blink/renderer/platform/pod_arena_test.cc rename to third_party/blink/renderer/platform/wtf/pod_arena_test.cc index c1f07840..a9c2d51 100644 --- a/third_party/blink/renderer/platform/pod_arena_test.cc +++ b/third_party/blink/renderer/platform/wtf/pod_arena_test.cc
@@ -23,14 +23,14 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "third_party/blink/renderer/platform/pod_arena.h" +#include "third_party/blink/renderer/platform/wtf/pod_arena.h" #include <algorithm> #include "base/memory/scoped_refptr.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/renderer/platform/testing/arena_test_helpers.h" +#include "third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h" -namespace blink { +namespace WTF { using ArenaTestHelpers::TrackedAllocator; @@ -93,4 +93,4 @@ } } -} // namespace blink +} // namespace WTF
diff --git a/third_party/blink/renderer/platform/testing/arena_test_helpers.h b/third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h similarity index 89% rename from third_party/blink/renderer/platform/testing/arena_test_helpers.h rename to third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h index 4d2cb5e3..09ed3f1 100644 --- a/third_party/blink/renderer/platform/testing/arena_test_helpers.h +++ b/third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h
@@ -23,16 +23,16 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_ARENA_TEST_HELPERS_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_ARENA_TEST_HELPERS_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_TEST_HELPERS_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_TEST_HELPERS_H_ -#include "third_party/blink/renderer/platform/pod_arena.h" #include "third_party/blink/renderer/platform/wtf/not_found.h" +#include "third_party/blink/renderer/platform/wtf/pod_arena.h" #include "third_party/blink/renderer/platform/wtf/vector.h" #include <gtest/gtest.h> -namespace blink { +namespace WTF { namespace ArenaTestHelpers { // An allocator for the PODArena which tracks the regions which have @@ -66,6 +66,6 @@ }; } // namespace ArenaTestHelpers -} // namespace blink +} // namespace WTF -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_ARENA_TEST_HELPERS_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_ARENA_TEST_HELPERS_H_
diff --git a/third_party/blink/renderer/platform/pod_free_list_arena.h b/third_party/blink/renderer/platform/wtf/pod_free_list_arena.h similarity index 94% rename from third_party/blink/renderer/platform/pod_free_list_arena.h rename to third_party/blink/renderer/platform/wtf/pod_free_list_arena.h index 3cab486..ff1b1e8 100644 --- a/third_party/blink/renderer/platform/pod_free_list_arena.h +++ b/third_party/blink/renderer/platform/wtf/pod_free_list_arena.h
@@ -23,14 +23,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_FREE_LIST_ARENA_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_FREE_LIST_ARENA_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_FREE_LIST_ARENA_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_FREE_LIST_ARENA_H_ -#include "third_party/blink/renderer/platform/pod_arena.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" +#include "third_party/blink/renderer/platform/wtf/pod_arena.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" -namespace blink { +namespace WTF { template <class T> class PODFreeListArena : public RefCounted<PODFreeListArena<T>> { @@ -123,6 +123,6 @@ friend class PODFreeListArenaTest; }; -} // namespace blink +} // namespace WTF #endif
diff --git a/third_party/blink/renderer/platform/pod_free_list_arena_test.cc b/third_party/blink/renderer/platform/wtf/pod_free_list_arena_test.cc similarity index 96% rename from third_party/blink/renderer/platform/pod_free_list_arena_test.cc rename to third_party/blink/renderer/platform/wtf/pod_free_list_arena_test.cc index 69fee78..94fc4a4 100644 --- a/third_party/blink/renderer/platform/pod_free_list_arena_test.cc +++ b/third_party/blink/renderer/platform/wtf/pod_free_list_arena_test.cc
@@ -23,14 +23,14 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "third_party/blink/renderer/platform/pod_free_list_arena.h" +#include "third_party/blink/renderer/platform/wtf/pod_free_list_arena.h" #include "base/memory/scoped_refptr.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/renderer/platform/testing/arena_test_helpers.h" +#include "third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h" #include "third_party/blink/renderer/platform/wtf/vector.h" -namespace blink { +namespace WTF { using ArenaTestHelpers::TrackedAllocator; @@ -163,4 +163,4 @@ } } -} // namespace blink +} // namespace WTF
diff --git a/third_party/blink/renderer/platform/pod_interval.h b/third_party/blink/renderer/platform/wtf/pod_interval.h similarity index 86% rename from third_party/blink/renderer/platform/pod_interval.h rename to third_party/blink/renderer/platform/wtf/pod_interval.h index b96a68c8..b4e2585 100644 --- a/third_party/blink/renderer/platform/pod_interval.h +++ b/third_party/blink/renderer/platform/wtf/pod_interval.h
@@ -23,15 +23,16 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_H_ -#include "third_party/blink/renderer/platform/heap/handle.h" #ifndef NDEBUG #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #endif -namespace blink { +#include "third_party/blink/renderer/platform/wtf/allocator.h" + +namespace WTF { // Class representing a closed interval which can hold an arbitrary // Plain Old Datatype (POD) as its endpoints and a piece of user @@ -71,8 +72,6 @@ // Note that this class requires a copy constructor and assignment // operator in order to be stored in the red-black tree. -#include "third_party/blink/renderer/platform/wtf/allocator.h" - #ifndef NDEBUG template <class T> struct ValueToString; @@ -143,11 +142,31 @@ private: T low_; T high_; - GC_PLUGIN_IGNORE("crbug.com/513116") +// https://crbug.com/513116. +#if defined(__clang__) + __attribute__((annotate("blink_gc_plugin_ignore"))) UserData data_; +#else UserData data_; +#endif T max_high_; }; -} // namespace blink +#ifndef NDEBUG +template <> +struct ValueToString<float> { + STATIC_ONLY(ValueToString); + static String ToString(const float value) { return String::Number(value); } +}; +template <> +struct ValueToString<double> { + static String ToString(const double value) { return String::Number(value); } +}; +template <> +struct ValueToString<int> { + static String ToString(const int& value) { return String::Number(value); } +}; +#endif -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_H_ +} // namespace WTF + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_H_
diff --git a/third_party/blink/renderer/platform/pod_interval_tree.h b/third_party/blink/renderer/platform/wtf/pod_interval_tree.h similarity index 94% rename from third_party/blink/renderer/platform/pod_interval_tree.h rename to third_party/blink/renderer/platform/wtf/pod_interval_tree.h index ad4e865..f0bbacd 100644 --- a/third_party/blink/renderer/platform/pod_interval_tree.h +++ b/third_party/blink/renderer/platform/wtf/pod_interval_tree.h
@@ -23,17 +23,17 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_TREE_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_TREE_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_TREE_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_TREE_H_ -#include "third_party/blink/renderer/platform/pod_arena.h" -#include "third_party/blink/renderer/platform/pod_interval.h" -#include "third_party/blink/renderer/platform/pod_red_black_tree.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/noncopyable.h" +#include "third_party/blink/renderer/platform/wtf/pod_arena.h" +#include "third_party/blink/renderer/platform/wtf/pod_interval.h" +#include "third_party/blink/renderer/platform/wtf/pod_red_black_tree.h" #include "third_party/blink/renderer/platform/wtf/vector.h" -namespace blink { +namespace WTF { #ifndef NDEBUG template <class T> @@ -253,6 +253,6 @@ }; #endif -} // namespace blink +} // namespace WTF -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_INTERVAL_TREE_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_INTERVAL_TREE_H_
diff --git a/third_party/blink/renderer/platform/pod_interval_tree_test.cc b/third_party/blink/renderer/platform/wtf/pod_interval_tree_test.cc similarity index 96% rename from third_party/blink/renderer/platform/pod_interval_tree_test.cc rename to third_party/blink/renderer/platform/wtf/pod_interval_tree_test.cc index ad20eb0..22cc18b 100644 --- a/third_party/blink/renderer/platform/pod_interval_tree_test.cc +++ b/third_party/blink/renderer/platform/wtf/pod_interval_tree_test.cc
@@ -25,15 +25,14 @@ // Tests for the interval tree class. -#include "third_party/blink/renderer/platform/pod_interval_tree.h" +#include "third_party/blink/renderer/platform/wtf/pod_interval_tree.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/renderer/platform/geometry/float_polygon.h" -#include "third_party/blink/renderer/platform/testing/tree_test_helpers.h" +#include "third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/vector.h" -namespace blink { +namespace WTF { using TreeTestHelpers::InitRandom; using TreeTestHelpers::NextRandom; @@ -196,13 +195,6 @@ // in release builds. // #define DEBUG_INSERTION_AND_DELETION_TEST -#ifndef NDEBUG -template <> -struct ValueToString<int> { - static String ToString(const int& value) { return String::Number(value); } -}; -#endif - namespace { void TreeInsertionAndDeletionTest(int32_t seed, int tree_size) { @@ -342,4 +334,4 @@ ASSERT_TRUE(tree.CheckInvariants()); } -} // namespace blink +} // namespace WTF
diff --git a/third_party/blink/renderer/platform/pod_red_black_tree.h b/third_party/blink/renderer/platform/wtf/pod_red_black_tree.h similarity index 98% rename from third_party/blink/renderer/platform/pod_red_black_tree.h rename to third_party/blink/renderer/platform/wtf/pod_red_black_tree.h index 6de3b42..9b845352 100644 --- a/third_party/blink/renderer/platform/pod_red_black_tree.h +++ b/third_party/blink/renderer/platform/wtf/pod_red_black_tree.h
@@ -69,21 +69,21 @@ // The design of this red-black tree comes from Cormen, Leiserson, // and Rivest, _Introduction to Algorithms_, MIT Press, 1990. -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_RED_BLACK_TREE_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_RED_BLACK_TREE_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_RED_BLACK_TREE_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_RED_BLACK_TREE_H_ #include "base/memory/scoped_refptr.h" -#include "third_party/blink/renderer/platform/pod_free_list_arena.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" #include "third_party/blink/renderer/platform/wtf/noncopyable.h" +#include "third_party/blink/renderer/platform/wtf/pod_free_list_arena.h" #ifndef NDEBUG #include "third_party/blink/renderer/platform/wtf/text/cstring.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #endif -namespace blink { +namespace WTF { #ifndef NDEBUG template <class T> @@ -794,6 +794,6 @@ #endif }; -} // namespace blink +} // namespace WTF -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_POD_RED_BLACK_TREE_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_RED_BLACK_TREE_H_
diff --git a/third_party/blink/renderer/platform/pod_red_black_tree_test.cc b/third_party/blink/renderer/platform/wtf/pod_red_black_tree_test.cc similarity index 96% rename from third_party/blink/renderer/platform/pod_red_black_tree_test.cc rename to third_party/blink/renderer/platform/wtf/pod_red_black_tree_test.cc index cb2ad97..a583998 100644 --- a/third_party/blink/renderer/platform/pod_red_black_tree_test.cc +++ b/third_party/blink/renderer/platform/wtf/pod_red_black_tree_test.cc
@@ -25,14 +25,14 @@ // Tests for the red-black tree class. -#include "third_party/blink/renderer/platform/pod_red_black_tree.h" +#include "third_party/blink/renderer/platform/wtf/pod_red_black_tree.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/renderer/platform/testing/arena_test_helpers.h" -#include "third_party/blink/renderer/platform/testing/tree_test_helpers.h" +#include "third_party/blink/renderer/platform/wtf/pod_arena_test_helpers.h" +#include "third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h" #include "third_party/blink/renderer/platform/wtf/vector.h" -namespace blink { +namespace WTF { using ArenaTestHelpers::TrackedAllocator; using TreeTestHelpers::InitRandom; @@ -193,4 +193,4 @@ InsertionAndDeletionTest(12311, 100); } -} // namespace blink +} // namespace WTF
diff --git a/third_party/blink/renderer/platform/testing/tree_test_helpers.cc b/third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.cc similarity index 93% rename from third_party/blink/renderer/platform/testing/tree_test_helpers.cc rename to third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.cc index b3c7089..0d96775 100644 --- a/third_party/blink/renderer/platform/testing/tree_test_helpers.cc +++ b/third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.cc
@@ -23,11 +23,11 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "third_party/blink/renderer/platform/testing/tree_test_helpers.h" +#include "third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h" #include <cstdlib> -namespace blink { +namespace WTF { namespace TreeTestHelpers { void InitRandom(const int32_t seed) { @@ -40,4 +40,4 @@ } } // namespace TreeTestHelpers -} // namespace blink +} // namespace WTF
diff --git a/third_party/blink/renderer/platform/testing/tree_test_helpers.h b/third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h similarity index 89% rename from third_party/blink/renderer/platform/testing/tree_test_helpers.h rename to third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h index 0192b08..1bf0fa6 100644 --- a/third_party/blink/renderer/platform/testing/tree_test_helpers.h +++ b/third_party/blink/renderer/platform/wtf/pod_tree_test_helpers.h
@@ -28,12 +28,12 @@ // // These are **not** thread safe! -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_TREE_TEST_HELPERS_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_TREE_TEST_HELPERS_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_TREE_TEST_HELPERS_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_TREE_TEST_HELPERS_H_ #include <stdint.h> -namespace blink { +namespace WTF { namespace TreeTestHelpers { // Initializes the pseudo-random number generator with a specific seed. @@ -45,6 +45,6 @@ int32_t NextRandom(const int32_t maximum_value); } // namespace TreeTestHelpers -} // namespace blink +} // namespace WTF -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_TREE_TEST_HELPERS_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_POD_TREE_TEST_HELPERS_H_
diff --git a/third_party/molokocacao/BUILD.gn b/third_party/molokocacao/BUILD.gn deleted file mode 100644 index 9b660f59..0000000 --- a/third_party/molokocacao/BUILD.gn +++ /dev/null
@@ -1,16 +0,0 @@ -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -source_set("molokocacao") { - sources = [ - "NSBezierPath+MCAdditions.h", - "NSBezierPath+MCAdditions.m", - ] - - deps = [ - "//third_party/google_toolbox_for_mac", - ] - - libs = [ "AppKit.framework" ] -}
diff --git a/third_party/molokocacao/LICENSE b/third_party/molokocacao/LICENSE deleted file mode 100644 index 6133156..0000000 --- a/third_party/molokocacao/LICENSE +++ /dev/null
@@ -1,23 +0,0 @@ -Copyright 2008 MolokoCacao -All rights reserved - -Redistribution and use in source and binary forms, with or without -modification, are permitted providing that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/molokocacao/NSBezierPath+MCAdditions.h b/third_party/molokocacao/NSBezierPath+MCAdditions.h deleted file mode 100644 index f56660f..0000000 --- a/third_party/molokocacao/NSBezierPath+MCAdditions.h +++ /dev/null
@@ -1,27 +0,0 @@ -// -// NSBezierPath+MCAdditions.h -// -// Created by Sean Patrick O'Brien on 4/1/08. -// Copyright 2008 MolokoCacao. All rights reserved. -// - -#ifndef THIRD_PARTY_MOLOKOCACAO_NSBEZIERPATH_MCADDITIONS_H_ -#define THIRD_PARTY_MOLOKOCACAO_NSBEZIERPATH_MCADDITIONS_H_ - -#import <Cocoa/Cocoa.h> - -@interface NSBezierPath (MCAdditions) - -+ (NSBezierPath*)bezierPathWithCGPath:(CGPathRef)pathRef; - -- (NSBezierPath*)pathWithStrokeWidth:(CGFloat)strokeWidth; - -- (void)fillWithInnerShadow:(NSShadow *)shadow; -- (void)drawBlurWithColor:(NSColor*)color radius:(CGFloat)radius; - -- (void)strokeInside; -- (void)strokeInsideWithinRect:(NSRect)clipRect; - -@end - -#endif // THIRD_PARTY_MOLOKOCACAO_NSBEZIERPATH_MCADDITIONS_H_
diff --git a/third_party/molokocacao/NSBezierPath+MCAdditions.m b/third_party/molokocacao/NSBezierPath+MCAdditions.m deleted file mode 100644 index 3b006ed..0000000 --- a/third_party/molokocacao/NSBezierPath+MCAdditions.m +++ /dev/null
@@ -1,190 +0,0 @@ -// -// NSBezierPath+MCAdditions.m -// -// Created by Sean Patrick O'Brien on 4/1/08. -// Copyright 2008 MolokoCacao. All rights reserved. -// - -#import "NSBezierPath+MCAdditions.h" - -#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSBezierPath+CGPath.h" - -// remove/comment out this line of you don't want to use undocumented functions -#define MCBEZIER_USE_PRIVATE_FUNCTION - -#ifdef MCBEZIER_USE_PRIVATE_FUNCTION -extern CGPathRef CGContextCopyPath(CGContextRef context); -#endif - -static void CGPathCallback(void *info, const CGPathElement *element) -{ - NSBezierPath *path = info; - CGPoint *points = element->points; - - switch (element->type) { - case kCGPathElementMoveToPoint: - { - [path moveToPoint:NSMakePoint(points[0].x, points[0].y)]; - break; - } - case kCGPathElementAddLineToPoint: - { - [path lineToPoint:NSMakePoint(points[0].x, points[0].y)]; - break; - } - case kCGPathElementAddQuadCurveToPoint: - { - // NOTE: This is untested. - NSPoint currentPoint = [path currentPoint]; - NSPoint interpolatedPoint = NSMakePoint((currentPoint.x + 2*points[0].x) / 3, (currentPoint.y + 2*points[0].y) / 3); - [path curveToPoint:NSMakePoint(points[1].x, points[1].y) controlPoint1:interpolatedPoint controlPoint2:interpolatedPoint]; - break; - } - case kCGPathElementAddCurveToPoint: - { - [path curveToPoint:NSMakePoint(points[2].x, points[2].y) controlPoint1:NSMakePoint(points[0].x, points[0].y) controlPoint2:NSMakePoint(points[1].x, points[1].y)]; - break; - } - case kCGPathElementCloseSubpath: - { - [path closePath]; - break; - } - } -} - -@implementation NSBezierPath (MCAdditions) - -+ (NSBezierPath *)bezierPathWithCGPath:(CGPathRef)pathRef -{ - NSBezierPath *path = [NSBezierPath bezierPath]; - CGPathApply(pathRef, path, CGPathCallback); - - return path; -} - -- (NSBezierPath *)pathWithStrokeWidth:(CGFloat)strokeWidth -{ -#ifdef MCBEZIER_USE_PRIVATE_FUNCTION - NSBezierPath *path = [self copy]; - CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; - CGPathRef pathRef = [path gtm_CGPath]; - [path release]; - - CGContextSaveGState(context); - - CGContextBeginPath(context); - CGContextAddPath(context, pathRef); - CGContextSetLineWidth(context, strokeWidth); - CGContextReplacePathWithStrokedPath(context); - CGPathRef strokedPathRef = CGContextCopyPath(context); - CGContextBeginPath(context); - NSBezierPath *strokedPath = [NSBezierPath bezierPathWithCGPath:strokedPathRef]; - - CGContextRestoreGState(context); - - CFRelease(pathRef); - CFRelease(strokedPathRef); - - return strokedPath; -#else - return nil; -#endif // MCBEZIER_USE_PRIVATE_FUNCTION -} - -- (void)fillWithInnerShadow:(NSShadow *)shadow -{ - [NSGraphicsContext saveGraphicsState]; - - NSSize offset = shadow.shadowOffset; - NSSize originalOffset = offset; - CGFloat radius = shadow.shadowBlurRadius; - NSRect bounds = NSInsetRect(self.bounds, -(ABS(offset.width) + radius), -(ABS(offset.height) + radius)); - - // The context's user transform isn't automatically applied to shadow offsets. - offset.height += bounds.size.height; - shadow.shadowOffset = offset; - NSAffineTransform *transform = [NSAffineTransform transform]; - if ([[NSGraphicsContext currentContext] isFlipped]) - [transform translateXBy:0 yBy:bounds.size.height]; - else - [transform translateXBy:0 yBy:-bounds.size.height]; - - NSBezierPath *drawingPath = [NSBezierPath bezierPathWithRect:bounds]; - [drawingPath setWindingRule:NSEvenOddWindingRule]; - [drawingPath appendBezierPath:self]; - [drawingPath transformUsingAffineTransform:transform]; - - [self addClip]; - [shadow set]; - [[NSColor blackColor] set]; - [drawingPath fill]; - - shadow.shadowOffset = originalOffset; - - [NSGraphicsContext restoreGraphicsState]; -} - -- (void)drawBlurWithColor:(NSColor *)color radius:(CGFloat)radius -{ - NSRect bounds = NSInsetRect(self.bounds, -radius, -radius); - NSShadow *shadow = [[NSShadow alloc] init]; - shadow.shadowOffset = NSMakeSize(0, bounds.size.height); - shadow.shadowBlurRadius = radius; - shadow.shadowColor = color; - NSBezierPath *path = [self copy]; - NSAffineTransform *transform = [NSAffineTransform transform]; - if ([[NSGraphicsContext currentContext] isFlipped]) - [transform translateXBy:0 yBy:bounds.size.height]; - else - [transform translateXBy:0 yBy:-bounds.size.height]; - [path transformUsingAffineTransform:transform]; - - [NSGraphicsContext saveGraphicsState]; - - [shadow set]; - [[NSColor blackColor] set]; - NSRectClip(bounds); - [path fill]; - - [NSGraphicsContext restoreGraphicsState]; - - [path release]; - [shadow release]; -} - -// Credit for the next two methods goes to Matt Gemmell -- (void)strokeInside -{ - /* Stroke within path using no additional clipping rectangle. */ - [self strokeInsideWithinRect:NSZeroRect]; -} - -- (void)strokeInsideWithinRect:(NSRect)clipRect -{ - NSGraphicsContext *thisContext = [NSGraphicsContext currentContext]; - float lineWidth = [self lineWidth]; - - /* Save the current graphics context. */ - [thisContext saveGraphicsState]; - - /* Double the stroke width, since -stroke centers strokes on paths. */ - [self setLineWidth:(lineWidth * 2.0)]; - - /* Clip drawing to this path; draw nothing outwith the path. */ - [self setClip]; - - /* Further clip drawing to clipRect, usually the view's frame. */ - if (clipRect.size.width > 0.0 && clipRect.size.height > 0.0) { - [NSBezierPath clipRect:clipRect]; - } - - /* Stroke the path. */ - [self stroke]; - - /* Restore the previous graphics context. */ - [thisContext restoreGraphicsState]; - [self setLineWidth:lineWidth]; -} - -@end
diff --git a/third_party/molokocacao/README.chromium b/third_party/molokocacao/README.chromium deleted file mode 100644 index 235c82a5..0000000 --- a/third_party/molokocacao/README.chromium +++ /dev/null
@@ -1,15 +0,0 @@ -Name: NSBezierPath additions from Sean Patrick O'Brien -Short Name: NSBezierPath -URL: http://www.seanpatrickobrien.com/journal/posts/3 -Source URL: http://www.seanpatrickobrien.com/downloads/track/?path=%2Ftutorials%2F1%2FExampleButton.zip -Version: 1.0 -License: BSD -Security critical: YES - -Description: -Additions to NSBezierPath to make certain operations more convenient (inner -shadows on paths, for example). - -Local Modifications: - - Added LICENSE file based on email correspondence with Sean. - - Added header guards.
diff --git a/tools/licenses.py b/tools/licenses.py index e75bc891..f9c1ed5 100755 --- a/tools/licenses.py +++ b/tools/licenses.py
@@ -306,7 +306,6 @@ os.path.join('third_party', 'lss'), os.path.join('third_party', 'lzma_sdk'), os.path.join('third_party', 'mesa'), - os.path.join('third_party', 'molokocacao'), os.path.join('third_party', 'motemplate'), os.path.join('third_party', 'mozc'), os.path.join('third_party', 'mozilla'),
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 00f565b..f672dcec 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -2866,6 +2866,17 @@ <int value="3" label="User navigated away from page while bubble hidden"/> </enum> +<enum name="AutofillLocalCardMigrationDialogOffer"> + <int value="0" label="Shown"/> + <int value="1" label="Not shown due to legal message being invalid"/> +</enum> + +<enum name="AutofillLocalCardMigrationDialogUserInteraction"> + <int value="0" label="User explicitly accepted dialog"/> + <int value="1" label="User explicitly denied dialog"/> + <int value="2" label="User clicked legal message link"/> +</enum> + <enum name="AutofillMacAddressBook"> <int value="0" label="Showed popup entry"/> <int value="1" label="Selected popup entry"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index a9cb875..88aabe2 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -6881,6 +6881,37 @@ <summary>Record how bubble is closed by different user interactions.</summary> </histogram> +<histogram name="Autofill.LocalCardMigrationDialogActiveDuration" units="ms"> + <owner>siyua@chromium.org</owner> + <summary> + Record duration of the local card migration dialog being visible to users. + </summary> +</histogram> + +<histogram name="Autofill.LocalCardMigrationDialogOffer" + enum="AutofillLocalCardMigrationDialogOffer"> + <owner>siyua@chromium.org</owner> + <summary> + Record events related to showing the local card migration dialog. + </summary> +</histogram> + +<histogram name="Autofill.LocalCardMigrationDialogUserInteraction" + enum="AutofillLocalCardMigrationDialogUserInteraction"> + <owner>siyua@chromium.org</owner> + <summary> + Record user interactions related to local card migration dialog. + </summary> +</histogram> + +<histogram name="Autofill.LocalCardMigrationDialogUserSelectionPercentage" + units="%"> + <owner>siyua@chromium.org</owner> + <summary> + Record the percentage of cards selected by the user in the migration dialog. + </summary> +</histogram> + <histogram name="Autofill.LocalCardMigrationOrigin" enum="LocalCardMigrationPrompt"> <owner>jiahuiguo@chromium.org</owner> @@ -9081,6 +9112,77 @@ </summary> </histogram> +<histogram base="true" name="Blink.MainFrame.CompositingCommitRatio" units="%"> + <owner>paint-dev@chromium.org</owner> +<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" --> + + <summary> + The percentage of time between a BeginMainFrame and paint results commit in + Blink that is used for committing paint results to the compositor. + </summary> +</histogram> + +<histogram base="true" name="Blink.MainFrame.CompositingRatio" units="%"> + <owner>paint-dev@chromium.org</owner> +<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" --> + + <summary> + The percentage of time between a BeginMainFrame and paint results commit in + Blink that is used for computing Compositing. + </summary> +</histogram> + += +<histogram base="true" name="Blink.MainFrame.IntersectionRatio" units="%"> + <owner>paint-dev@chromium.org</owner> +<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" --> + + <summary> + The percentage of time between a BeginMainFrame and paint results commit in + Blink that is used for computing Intersection Observations. + </summary> +</histogram> + +<histogram base="true" name="Blink.MainFrame.PaintRatio" units="%"> + <owner>paint-dev@chromium.org</owner> +<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" --> + + <summary> + The percentage of time between a BeginMainFrame and paint results commit in + Blink that is used for computing Paint. + </summary> +</histogram> + +<histogram base="true" name="Blink.MainFrame.PrePaintRatio" units="%"> + <owner>paint-dev@chromium.org</owner> +<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" --> + + <summary> + The percentage of time between a BeginMainFrame and paint results commit in + Blink that is used for computing PrePaint. + </summary> +</histogram> + +<histogram base="true" name="Blink.MainFrame.StyleAndLayoutRatio" units="%"> + <owner>paint-dev@chromium.org</owner> +<!-- Name completed by histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" --> + + <summary> + The percentage of time between a BeginMainFrame and paint results commit in + Blink that is used for computing Style and Layout. + </summary> +</histogram> + +<histogram name="Blink.MainFrame.UpdateTime" units="microseconds"> + <owner>paint-dev@chromium.org</owner> + <summary> + Time between a BeginMainFrame and paint results commit in Blink. + + This histogram will not record metrics on machines with low-resolution + clocks. + </summary> +</histogram> + <histogram name="Blink.MediaDocument.DownloadButton" enum="MediaDocumentDownloadButtonType"> <obsolete> @@ -107678,6 +107780,36 @@ </summary> </histogram> +<histogram name="Tabs.Tasks.DuplicatedTab.DuplicatedTabCount" units="tabs" + expires_after="2019-01-01"> + <owner>yusufo@chromium.org</owner> + <owner>wychen@chromium.org</owner> + <summary> + During tab restoration, a tab is considered as a duplicated tab when it has + an identical url with another restored tab. + + This histogram records the number of duplicated tabs on a cold start after + all tabs are restored. The possible range for this number is from 0 to total + number of restored tabs minus 1. In other words, this number is equals to + total number of restored tabs minus the number of unique URLs. + </summary> +</histogram> + +<histogram name="Tabs.Tasks.DuplicatedTab.DuplicatedTabRatio" units="%" + expires_after="2019-01-01"> + <owner>yusufo@chromium.org</owner> + <owner>wychen@chromium.org</owner> + <summary> + During tab restoration, a tab is considered as a duplicated tab when it has + an identical url with another restored tab. + + This histogram records the ratio of duplicated tabs to the total number of + tabs on a cold start after all tabs are restored. This ratio will never + reach 100%, since the highest possible number of duplicated tabs is total + number of restored tabs minus 1. + </summary> +</histogram> + <histogram name="Tabs.Tasks.HubAndSpokeNavigationUsage" units="spokes" expires_after="2019-01-01"> <!-- Name completed by histogram_suffixes name="HubAndSpokeNavigationUsageType" --> @@ -120690,6 +120822,16 @@ <affected-histogram name="Autofill.LocalCardMigrationBubbleUserInteraction"/> </histogram_suffixes> +<histogram_suffixes + name="AutofillLocalCardMigrationDialogDurationWithCloseEvent" separator="."> + <suffix name="Accepted" + label="The dialog was closed due to the user clicking the save button."/> + <suffix name="Denied" + label="The dialog was closed due to the user clicking the cancel + button."/> + <affected-histogram name="Autofill.LocalCardMigrationDialogActiveDuration"/> +</histogram_suffixes> + <histogram_suffixes name="AutofillLocalCardMigrationOrigin" separator="."> <suffix name="SettingsPage" label="Trigger from settings page"/> <suffix name="UseOfLocalCard" @@ -121030,6 +121172,18 @@ name="Blink.LazyLoad.CrossOriginFrames.InitialDeferralAction"/> </histogram_suffixes> +<histogram_suffixes name="BlinkMainFrameUpdateTimeSuffixes" separator="."> + <suffix name="1msTo5ms" label="Ratio when main frame between 1ms and 5ms."/> + <suffix name="LessThan1ms" label="Ratio when main frame shorter than 1ms."/> + <suffix name="MoreThan5ms" label="Ratio when main frame longer than 5ms."/> + <affected-histogram name="Blink.MainFrame.CompositingCommitRatio"/> + <affected-histogram name="Blink.MainFrame.CompositingRatio"/> + <affected-histogram name="Blink.MainFrame.IntersectionRatio"/> + <affected-histogram name="Blink.MainFrame.PaintRatio"/> + <affected-histogram name="Blink.MainFrame.PrePaintRatio"/> + <affected-histogram name="Blink.MainFrame.StyleAndLayoutRatio"/> +</histogram_suffixes> + <histogram_suffixes name="BlinkVisibleLoadTimeSuffixes" separator="."> <suffix name="2G" label="2G effective connection type"/> <suffix name="3G" label="3G effective connection type"/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index dbfb430..a9878e6f 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -547,11 +547,11 @@ </event> <event name="Blink.UpdateTime"> - <owner>vmpstr@chromium.org</owner> + <owner>schenney@chromium.org</owner> <summary> Metrics that measure various update times in Blink. This includes paint, - compositing, and layout update times. The metrics are recorded once per - second and at the destruction of the local frame root. + compositing, and layout update times. The metrics are recorded once per 30 + seconds and at the destruction of the local frame root. </summary> <metric name="Compositing.Average"> <summary> @@ -559,34 +559,87 @@ event period. </summary> </metric> + <metric name="Compositing.AverageRatio"> + <summary> + The average over frames within the sample window of the ratio of time + taken in the compositing phase to the total time for the main frame. An + int in the range [0,100]. + </summary> + </metric> <metric name="Compositing.WorstCase"> <summary> The longest single time taken by the compositing phase in microseconds in the event period. </summary> </metric> + <metric name="Compositing.WorstCaseRatio"> + <summary> + The highest proportion of a frame ever used by the compositing phase + within the sample window. An int in the range [0,100]. + </summary> + </metric> <metric name="CompositingCommit.Average"> <summary> The average time taken by the compositing commit at the end of the blink lifecycle, in microseconds in the event period. </summary> </metric> + <metric name="CompositingCommit.AverageRatio"> + <summary> + The average over frames within the sample window of the ratio of time + taken by the compositing commit at the end of the blink lifecycle to the + total time for the main frame. An int in the range [0,100]. + </summary> + </metric> <metric name="CompositingCommit.WorstCase"> <summary> The longest single time taken by the compositing commit at the end of the blink lifecycle, in microseconds in the event period. </summary> </metric> + <metric name="CompositingCommit.WorstCaseRatio"> + <summary> + The highest proportion of a frame ever taken by the compositing commit at + the end of the blink lifecycle to the total time for the main frame. An + int in the range [0,100]. + </summary> + </metric> <metric name="IntersectionObservation.Average"> <summary> The average time taken to compute IntersectionObserver observations in microseconds in the event period. </summary> </metric> + <metric name="IntersectionObservation.AverageRatio"> + <summary> + The average over frames within the sample window of the ratio of time + taken compute IntersectionObserver observations to the total time for the + main frame. An int in the range [0,100]. + </summary> + </metric> <metric name="IntersectionObservation.WorstCase"> <summary> - The longest single time taken by to compute IntersectionObserver - observations in microseconds in the event period. + The longest single time taken to compute IntersectionObserver observations + in microseconds in the event period. + </summary> + </metric> + <metric name="IntersectionObservation.WorstCaseRatio"> + <summary> + The highest proportion of a frame ever taken to compute + IntersectionObserver observations within the sample window. An int in the + range [0,100]. + </summary> + </metric> + <metric name="MainFrame.Average"> + <summary> + The average time between a BeginMainFrame and the commit of paint results, + in microseconds. + </summary> + </metric> + <metric name="MainFrame.WorstCase"> + <summary> + The longest single time between a BeginMainFrame and the commit of paint + results, in microseconds. </summary> </metric> <metric name="Paint.Average"> @@ -595,36 +648,75 @@ period. </summary> </metric> + <metric name="Paint.AverageRatio"> + <summary> + The average over frames within the sample window of the ratio of time + taken in the paint phase to the total time for the main frame. An int in + the range [0,100]. + </summary> + </metric> <metric name="Paint.WorstCase"> <summary> The longest single time taken by the paint phase in microseconds in the event period. </summary> </metric> + <metric name="Paint.WorstCaseRatio"> + <summary> + The highest proportion of a frame ever used by the paint phase within the + sample window. An int in the range [0,100]. + </summary> + </metric> <metric name="PrePaint.Average"> <summary> The average time taken by the pre-paint phase in microseconds in the event period. </summary> </metric> + <metric name="PrePaint.AverageRatio"> + <summary> + The average over frames within the sample window of the ratio of time + taken in the pre-paint phase to the total time for the main frame. An int + in the range [0,100]. + </summary> + </metric> <metric name="PrePaint.WorstCase"> <summary> The longest single time taken by the pre-paint phase in microseconds in the event period. </summary> </metric> + <metric name="PrePaint.WorstCaseRatio"> + <summary> + The highest proportion of a frame ever used by the pre-paint phase within + the sample window. An int in the range [0,100]. + </summary> + </metric> <metric name="StyleAndLayout.Average"> <summary> The average time taken by the style and layout phases in microseconds in the event period. </summary> </metric> + <metric name="StyleAndLayout.AverageRatio"> + <summary> + The average over frames within the sample window of the ratio of time + taken to update style and layout to the total time for the main frame. An + int in the range [0,100]. + </summary> + </metric> <metric name="StyleAndLayout.WorstCase"> <summary> The longest single time taken by the style and layout phases in microseconds in the event period. </summary> </metric> + <metric name="StyleAndLayout.WorstCaseRatio"> + <summary> + The highest proportion of a frame ever used to compute style and layout + within the sample window. An int in the range [0,100]. + </summary> + </metric> </event> <event name="Blink.UseCounter"> @@ -1478,6 +1570,21 @@ </metric> </event> +<event name="LookalikeUrl.NavigationSuggestion" singular="True"> + <owner>meacer@chromium.org</owner> + <owner>cthomp@chromium.org</owner> + <summary> + Metrics recorded when a navigated URL's domain name is visually similar to a + popular domain or a domain that the user engaged with. + </summary> + <metric name="MatchType"> + <summary> + An enum value representing the type of the match (popular domain, engaged + domain, etc.). The enum is defined in |LookalikeUrlNavigationObserver|. + </summary> + </metric> +</event> + <event name="Media.Autoplay.Attempt"> <owner>mlamouri@chromium.org</owner> <owner>media-dev@chromium.org</owner> @@ -2845,6 +2952,12 @@ provisional navigations. </summary> </metric> + <metric name="Net.HttpResponseCode"> + <summary> + The HTTP response code (e.g., 200, 404, etc.) associated with the main + frame page load. + </summary> + </metric> <metric name="Net.HttpRttEstimate.OnNavigationStart"> <summary> The HTTP round trip time estimate for this page load, at the time the
diff --git a/ui/accelerated_widget_mac/display_link_mac.cc b/ui/accelerated_widget_mac/display_link_mac.cc index a209810..81de0b1 100644 --- a/ui/accelerated_widget_mac/display_link_mac.cc +++ b/ui/accelerated_widget_mac/display_link_mac.cc
@@ -31,6 +31,36 @@ namespace ui { +using DisplayLinkMap = std::map<CGDirectDisplayID, DisplayLinkMac*>; + +namespace { + +// The task runner to post tasks to from the display link thread. Note that this +// is initialized with the very first DisplayLinkMac instance, and is never +// changed (even, e.g, in tests that re-initialize the main thread task runner). +// https://885329 +scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner() { + static scoped_refptr<base::SingleThreadTaskRunner> task_runner = + base::ThreadTaskRunnerHandle::Get(); + return task_runner; +} + +// Each display link instance consumes a non-negligible number of cycles, so +// make all display links on the same screen share the same object. +// +// Note that this is a weak map, holding non-owning pointers to the +// DisplayLinkMac objects. DisplayLinkMac is a ref-counted class, and is +// jointly owned by the various callers that got a copy by calling +// GetForDisplay(). +// +// ** This map may only be accessed from the main thread. ** +DisplayLinkMap& GetAllDisplayLinks() { + static base::NoDestructor<DisplayLinkMap> all_display_links; + return *all_display_links; +} + +} // namespace + // static scoped_refptr<DisplayLinkMac> DisplayLinkMac::GetForDisplay( CGDirectDisplayID display_id) { @@ -193,21 +223,6 @@ } // static -DisplayLinkMac::DisplayLinkMap& DisplayLinkMac::GetAllDisplayLinks() { - DCHECK_EQ(base::ThreadTaskRunnerHandle::Get(), GetMainThreadTaskRunner()); - static base::NoDestructor<DisplayLinkMac::DisplayLinkMap> all_display_links; - return *all_display_links; -} - -// static -scoped_refptr<base::SingleThreadTaskRunner> -DisplayLinkMac::GetMainThreadTaskRunner() { - static scoped_refptr<base::SingleThreadTaskRunner> task_runner = - base::ThreadTaskRunnerHandle::Get(); - return task_runner; -} - -// static CVReturn DisplayLinkMac::DisplayLinkCallback( CVDisplayLinkRef display_link, const CVTimeStamp* now,
diff --git a/ui/accelerated_widget_mac/display_link_mac.h b/ui/accelerated_widget_mac/display_link_mac.h index 2fce897..b552163 100644 --- a/ui/accelerated_widget_mac/display_link_mac.h +++ b/ui/accelerated_widget_mac/display_link_mac.h
@@ -14,10 +14,6 @@ #include "base/time/time.h" #include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h" -namespace base { -class SingleThreadTaskRunner; -} - namespace ui { class ACCELERATED_WIDGET_MAC_EXPORT DisplayLinkMac @@ -52,20 +48,6 @@ // Processes the display link callback. void UpdateVSyncParameters(const CVTimeStamp& time); - // Each display link instance consumes a non-negligible number of cycles, so - // make all display links on the same screen share the same object. This map - // must only be changed from the main thread. - // - // Note that this is a weak map, holding non-owning pointers to the - // DisplayLinkMac objects. DisplayLinkMac is a ref-counted class, and is - // jointly owned by the various callers that got a copy by calling - // GetForDisplay(). - using DisplayLinkMap = std::map<CGDirectDisplayID, DisplayLinkMac*>; - static DisplayLinkMap& GetAllDisplayLinks(); - - // The task runner to post tasks to from the display link thread. - static scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner(); - // Called by the system on the display link thread, and posts a call to // DoUpdateVSyncParameters() to the UI thread. static CVReturn DisplayLinkCallback(
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index 8cb1b77..90158da 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn
@@ -905,7 +905,7 @@ "ime/win/tsf_text_store_unittest.cc", ] if (is_linux && use_aura && !is_chromeos) { - if (use_x11) { + if (use_x11 || use_ozone) { sources += [ "ime/input_method_auralinux_unittest.cc" ] } else { sources += [ "ime/input_method_minimal_unittest.cc" ]
diff --git a/ui/base/ime/input_method_auralinux.cc b/ui/base/ime/input_method_auralinux.cc index 6997920..90a806a 100644 --- a/ui/base/ime/input_method_auralinux.cc +++ b/ui/base/ime/input_method_auralinux.cc
@@ -275,6 +275,14 @@ NotifyTextInputCaretBoundsChanged(client); context_->SetCursorLocation(GetTextInputClient()->GetCaretBounds()); + gfx::Range text_range, selection_range; + base::string16 text; + if (client->GetTextRange(&text_range) && + client->GetTextFromRange(text_range, &text) && + client->GetSelectionRange(&selection_range)) { + context_->SetSurroundingText(text, selection_range); + } + if (!IsTextInputTypeNone() && text_input_type_ != TEXT_INPUT_TYPE_PASSWORD && GetEngine()) GetEngine()->SetCompositionBounds(GetCompositionBounds(client)); @@ -307,13 +315,6 @@ context_->Reset(); context_simple_->Reset(); - // Some input methods may not honour the reset call. Focusing out/in the - // |context_| to make sure it gets reset correctly. - if (text_input_type_ != TEXT_INPUT_TYPE_NONE) { - context_->Blur(); - context_->Focus(); - } - composition_ = CompositionText(); result_text_.clear(); is_sync_mode_ = false; @@ -353,6 +354,14 @@ } } +void InputMethodAuraLinux::OnDeleteSurroundingText(int32_t index, + uint32_t length) { + if (GetTextInputClient() && composition_.text.empty()) { + uint32_t before = index >= 0 ? 0U : static_cast<uint32_t>(-1 * index); + GetTextInputClient()->ExtendSelectionAndDelete(before, length - before); + } +} + void InputMethodAuraLinux::OnPreeditChanged( const CompositionText& composition_text) { if (IgnoringNonKeyInput() || IsTextInputTypeNone())
diff --git a/ui/base/ime/input_method_auralinux.h b/ui/base/ime/input_method_auralinux.h index ef4985b..8963ab9 100644 --- a/ui/base/ime/input_method_auralinux.h +++ b/ui/base/ime/input_method_auralinux.h
@@ -35,6 +35,7 @@ // Overriden from ui::LinuxInputMethodContextDelegate void OnCommit(const base::string16& text) override; + void OnDeleteSurroundingText(int32_t index, uint32_t length) override; void OnPreeditChanged(const CompositionText& composition_text) override; void OnPreeditEnd() override; void OnPreeditStart() override {}
diff --git a/ui/base/ime/input_method_auralinux_unittest.cc b/ui/base/ime/input_method_auralinux_unittest.cc index 7424f5f..23e6be6 100644 --- a/ui/base/ime/input_method_auralinux_unittest.cc +++ b/ui/base/ime/input_method_auralinux_unittest.cc
@@ -125,6 +125,19 @@ cursor_position_ = rect; } + void SetSurroundingText(const base::string16& text, + const gfx::Range& selection_range) override { + TestResult::GetInstance()->RecordAction( + base::ASCIIToUTF16("surroundingtext:") + text); + + std::stringstream rs; + rs << "selectionrangestart:" << selection_range.start(); + std::stringstream re; + re << "selectionrangeend:" << selection_range.end(); + TestResult::GetInstance()->RecordAction(base::ASCIIToUTF16(rs.str())); + TestResult::GetInstance()->RecordAction(base::ASCIIToUTF16(re.str())); + }; + private: LinuxInputMethodContextDelegate* delegate_; std::vector<base::string16> actions_; @@ -187,6 +200,9 @@ : DummyTextInputClient(text_input_type){}; base::string16 composition_text; + gfx::Range text_range; + gfx::Range selection_range; + base::string16 surrounding_text; protected: void SetCompositionText(const CompositionText& composition) override { @@ -229,6 +245,22 @@ TestResult::GetInstance()->RecordAction(base::ASCIIToUTF16("keypress:") + base::ASCIIToUTF16(ss.str())); } + + bool GetTextRange(gfx::Range* range) const override { + *range = text_range; + return true; + } + bool GetSelectionRange(gfx::Range* range) const override { + *range = selection_range; + return true; + } + bool GetTextFromRange(const gfx::Range& range, + base::string16* text) const override { + if (surrounding_text.empty()) + return false; + *text = surrounding_text.substr(range.GetMin(), range.length()); + return true; + } }; class InputMethodAuraLinuxTest : public testing::Test { @@ -760,5 +792,59 @@ test_result_->Verify(); } +TEST_F(InputMethodAuraLinuxTest, SurroundingText_NoSelectionTest) { + std::unique_ptr<TextInputClientForTesting> client( + new TextInputClientForTesting(TEXT_INPUT_TYPE_TEXT)); + input_method_auralinux_->SetFocusedTextInputClient(client.get()); + input_method_auralinux_->OnTextInputTypeChanged(client.get()); + + client->surrounding_text = base::ASCIIToUTF16("abcdef"); + client->text_range = gfx::Range(0, 6); + client->selection_range = gfx::Range(3, 3); + + input_method_auralinux_->OnCaretBoundsChanged(client.get()); + + test_result_->ExpectAction("surroundingtext:abcdef"); + test_result_->ExpectAction("selectionrangestart:3"); + test_result_->ExpectAction("selectionrangeend:3"); + test_result_->Verify(); +} + +TEST_F(InputMethodAuraLinuxTest, SurroundingText_SelectionTest) { + std::unique_ptr<TextInputClientForTesting> client( + new TextInputClientForTesting(TEXT_INPUT_TYPE_TEXT)); + input_method_auralinux_->SetFocusedTextInputClient(client.get()); + input_method_auralinux_->OnTextInputTypeChanged(client.get()); + + client->surrounding_text = base::ASCIIToUTF16("abcdef"); + client->text_range = gfx::Range(0, 6); + client->selection_range = gfx::Range(2, 5); + + input_method_auralinux_->OnCaretBoundsChanged(client.get()); + + test_result_->ExpectAction("surroundingtext:abcdef"); + test_result_->ExpectAction("selectionrangestart:2"); + test_result_->ExpectAction("selectionrangeend:5"); + test_result_->Verify(); +} + +TEST_F(InputMethodAuraLinuxTest, SurroundingText_PartialText) { + std::unique_ptr<TextInputClientForTesting> client( + new TextInputClientForTesting(TEXT_INPUT_TYPE_TEXT)); + input_method_auralinux_->SetFocusedTextInputClient(client.get()); + input_method_auralinux_->OnTextInputTypeChanged(client.get()); + + client->surrounding_text = base::ASCIIToUTF16("abcdefghij"); + client->text_range = gfx::Range(5, 10); + client->selection_range = gfx::Range(7, 9); + + input_method_auralinux_->OnCaretBoundsChanged(client.get()); + + test_result_->ExpectAction("surroundingtext:fghij"); + test_result_->ExpectAction("selectionrangestart:7"); + test_result_->ExpectAction("selectionrangeend:9"); + test_result_->Verify(); +} + } // namespace } // namespace ui
diff --git a/ui/base/ime/input_method_factory.cc b/ui/base/ime/input_method_factory.cc index 5a7a623..2cd9b79 100644 --- a/ui/base/ime/input_method_factory.cc +++ b/ui/base/ime/input_method_factory.cc
@@ -20,7 +20,7 @@ #include "ui/base/ime/input_method_mac.h" #elif defined(OS_FUCHSIA) #include "ui/base/ime/input_method_fuchsia.h" -#elif defined(USE_AURA) && defined(USE_X11) +#elif defined(USE_AURA) && (defined(USE_X11) || defined(USE_OZONE)) #include "ui/base/ime/input_method_auralinux.h" #else #include "ui/base/ime/input_method_minimal.h" @@ -66,7 +66,7 @@ return std::make_unique<InputMethodMac>(delegate); #elif defined(OS_FUCHSIA) return std::make_unique<InputMethodFuchsia>(delegate); -#elif defined(USE_AURA) && defined(USE_X11) +#elif defined(USE_AURA) && (defined(USE_X11) || defined(USE_OZONE)) return std::make_unique<InputMethodAuraLinux>(delegate); #else return std::make_unique<InputMethodMinimal>(delegate);
diff --git a/ui/base/ime/input_method_win_imm32.cc b/ui/base/ime/input_method_win_imm32.cc index 162cf77..723408b 100644 --- a/ui/base/ime/input_method_win_imm32.cc +++ b/ui/base/ime/input_method_win_imm32.cc
@@ -89,6 +89,7 @@ void InputMethodWinImm32::OnTextInputTypeChanged( const TextInputClient* client) { + InputMethodBase::OnTextInputTypeChanged(client); if (!IsTextInputClientFocused(client) || !IsWindowFocused(client)) return; imm32_manager_.CancelIME(toplevel_window_handle_);
diff --git a/ui/base/ime/input_method_win_tsf.cc b/ui/base/ime/input_method_win_tsf.cc index 5e723f1..0bc1842 100644 --- a/ui/base/ime/input_method_win_tsf.cc +++ b/ui/base/ime/input_method_win_tsf.cc
@@ -79,6 +79,7 @@ } void InputMethodWinTSF::OnTextInputTypeChanged(const TextInputClient* client) { + InputMethodBase::OnTextInputTypeChanged(client); if (!IsTextInputClientFocused(client) || !IsWindowFocused(client)) return; ui::TSFBridge::GetInstance()->CancelComposition();
diff --git a/ui/base/ime/linux/fake_input_method_context.cc b/ui/base/ime/linux/fake_input_method_context.cc index 5053aa1..c6c04798 100644 --- a/ui/base/ime/linux/fake_input_method_context.cc +++ b/ui/base/ime/linux/fake_input_method_context.cc
@@ -27,4 +27,9 @@ void FakeInputMethodContext::SetCursorLocation(const gfx::Rect& rect) { } +void FakeInputMethodContext::SetSurroundingText( + const base::string16& text, + const gfx::Range& selection_range) { +} + } // namespace ui
diff --git a/ui/base/ime/linux/fake_input_method_context.h b/ui/base/ime/linux/fake_input_method_context.h index ec9ac7e4..0fd8fdf5 100644 --- a/ui/base/ime/linux/fake_input_method_context.h +++ b/ui/base/ime/linux/fake_input_method_context.h
@@ -21,6 +21,8 @@ void Focus() override; void Blur() override; void SetCursorLocation(const gfx::Rect& rect) override; + void SetSurroundingText(const base::string16& text, + const gfx::Range& selection_range) override; private: DISALLOW_COPY_AND_ASSIGN(FakeInputMethodContext);
diff --git a/ui/base/ime/linux/linux_input_method_context.h b/ui/base/ime/linux/linux_input_method_context.h index 4fbaebc..ca80623 100644 --- a/ui/base/ime/linux/linux_input_method_context.h +++ b/ui/base/ime/linux/linux_input_method_context.h
@@ -11,7 +11,8 @@ namespace gfx { class Rect; -} +class Range; +} // namespace gfx namespace ui { @@ -33,6 +34,10 @@ // client window rect. virtual void SetCursorLocation(const gfx::Rect& rect) = 0; + // Tells the system IME the surrounding text around the cursor location. + virtual void SetSurroundingText(const base::string16& text, + const gfx::Range& selection_range) = 0; + // Resets the context. A client needs to call OnTextInputTypeChanged() again // before calling DispatchKeyEvent(). virtual void Reset() = 0; @@ -52,6 +57,9 @@ // Commits the |text| to the text input client. virtual void OnCommit(const base::string16& text) = 0; + // Deletes the surrounding text at |index| for given |length|. + virtual void OnDeleteSurroundingText(int32_t index, uint32_t length) = 0; + // Sets the composition text to the text input client. virtual void OnPreeditChanged(const CompositionText& composition_text) = 0;
diff --git a/ui/chromeos/events/event_rewriter_chromeos.cc b/ui/chromeos/events/event_rewriter_chromeos.cc index 5607e96..11552015 100644 --- a/ui/chromeos/events/event_rewriter_chromeos.cc +++ b/ui/chromeos/events/event_rewriter_chromeos.cc
@@ -302,7 +302,8 @@ return EventRewriterChromeOS::kDeviceAppleKeyboard; } - if (!found_apple && keyboard_device.type == INPUT_DEVICE_EXTERNAL) { + if (!found_apple && (keyboard_device.type == INPUT_DEVICE_USB || + keyboard_device.type == INPUT_DEVICE_BLUETOOTH)) { // ui::InputDevice is a generic input device, and we're not sure if it's // actually a keyboard. return found_keyboard
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index bcbdfc13a..92ed2ff0 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -407,6 +407,7 @@ void DidPresentCompositorFrame( uint32_t frame_token, const gfx::PresentationFeedback& feedback) override {} + void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override {} // cc::LayerTreeHostSingleThreadClient implementation. void DidSubmitCompositorFrame() override;
diff --git a/ui/display/manager/touch_device_manager.cc b/ui/display/manager/touch_device_manager.cc index b71cfa5..41606b4e 100644 --- a/ui/display/manager/touch_device_manager.cc +++ b/ui/display/manager/touch_device_manager.cc
@@ -715,8 +715,10 @@ bool HasExternalTouchscreenDevice() { for (const auto& device : ui::InputDeviceManager::GetInstance()->GetTouchscreenDevices()) { - if (device.type == ui::InputDeviceType::INPUT_DEVICE_EXTERNAL) + if (device.type == ui::InputDeviceType::INPUT_DEVICE_USB || + device.type == ui::InputDeviceType::INPUT_DEVICE_BLUETOOTH) { return true; + } } return false; }
diff --git a/ui/display/manager/touch_device_manager_unittest.cc b/ui/display/manager/touch_device_manager_unittest.cc index acc60f5..54c57f5 100644 --- a/ui/display/manager/touch_device_manager_unittest.cc +++ b/ui/display/manager/touch_device_manager_unittest.cc
@@ -142,7 +142,7 @@ std::vector<ui::TouchscreenDevice> devices; for (int i = 0; i < 5; ++i) { devices.push_back(CreateTouchscreenDevice( - i, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(256, 256))); + i, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(256, 256))); } DisplayInfoList displays; @@ -159,9 +159,9 @@ TEST_F(TouchAssociationTest, OneToOneMapping) { std::vector<ui::TouchscreenDevice> devices; devices.push_back(CreateTouchscreenDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(800, 600))); + 1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(800, 600))); devices.push_back(CreateTouchscreenDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1024, 768))); + 2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1024, 768))); test::ScopedSetInternalDisplayId set_internal(display_manager(), displays_[0].id()); @@ -178,7 +178,7 @@ TEST_F(TouchAssociationTest, MapToCorrectDisplaySize) { std::vector<ui::TouchscreenDevice> devices; devices.push_back(CreateTouchscreenDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1024, 768))); + 2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1024, 768))); test::ScopedSetInternalDisplayId set_internal(display_manager(), displays_[0].id()); @@ -194,9 +194,9 @@ TEST_F(TouchAssociationTest, MapWhenSizeDiffersByOne) { std::vector<ui::TouchscreenDevice> devices; devices.push_back(CreateTouchscreenDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(801, 600))); + 1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(801, 600))); devices.push_back(CreateTouchscreenDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1023, 768))); + 2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1023, 768))); test::ScopedSetInternalDisplayId set_internal(display_manager(), displays_[0].id()); @@ -213,9 +213,9 @@ TEST_F(TouchAssociationTest, MapWhenSizesDoNotMatch) { std::vector<ui::TouchscreenDevice> devices; devices.push_back(CreateTouchscreenDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1022, 768))); + 1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1022, 768))); devices.push_back(CreateTouchscreenDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(802, 600))); + 2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(802, 600))); DisplayInfoList displays; displays.push_back(displays_[0]); @@ -236,7 +236,7 @@ TEST_F(TouchAssociationTest, MapInternalTouchscreen) { std::vector<ui::TouchscreenDevice> devices; devices.push_back(CreateTouchscreenDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080))); + 1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080))); devices.push_back(CreateTouchscreenDevice( 2, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(9999, 888))); @@ -279,7 +279,7 @@ devices.push_back(CreateTouchscreenDevice( 2, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(1920, 1080))); devices.push_back(CreateTouchscreenDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1024, 768))); + 3, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1024, 768))); test::ScopedSetInternalDisplayId set_internal(display_manager(), displays_[0].id()); @@ -298,7 +298,7 @@ TEST_F(TouchAssociationTest, TestWithNoInternalDisplay) { std::vector<ui::TouchscreenDevice> devices; devices.push_back(CreateTouchscreenDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080))); + 1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080))); devices.push_back(CreateTouchscreenDevice( 2, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(9999, 888))); @@ -315,11 +315,11 @@ TEST_F(TouchAssociationTest, MatchRemainingDevicesToInternalDisplay) { std::vector<ui::TouchscreenDevice> devices; devices.push_back(CreateTouchscreenDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(123, 456))); + 1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(123, 456))); devices.push_back(CreateTouchscreenDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(234, 567))); + 2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(234, 567))); devices.push_back(CreateTouchscreenDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(345, 678))); + 3, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(345, 678))); test::ScopedSetInternalDisplayId set_internal(display_manager(), displays_[0].id()); @@ -338,11 +338,11 @@ MatchRemainingDevicesWithNoInternalDisplayPresent) { std::vector<ui::TouchscreenDevice> devices; devices.push_back(CreateTouchscreenDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(123, 456))); + 1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(123, 456))); devices.push_back(CreateTouchscreenDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(234, 567))); + 2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(234, 567))); devices.push_back(CreateTouchscreenDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(345, 678))); + 3, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(345, 678))); touch_device_manager()->AssociateTouchscreens(&displays_, devices); @@ -364,11 +364,11 @@ TouchDeviceManager::TouchAssociationMap touch_associations; devices_.push_back(CreateTouchscreenDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080))); + 1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080))); devices_.push_back(CreateTouchscreenDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1024, 768))); + 2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1024, 768))); devices_.push_back(CreateTouchscreenDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(640, 480))); + 3, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(640, 480))); devices_.push_back(CreateTouchscreenDevice( 4, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(800, 600))); @@ -600,7 +600,7 @@ // Create a device with name |device_name_1| connected to |ports[0]|. devices_.push_back(CreateTouchscreenDevice( - 1, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080))); + 1, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080))); devices_.back().name = device_name_1; devices_.back().phys = ports[0]; @@ -608,7 +608,7 @@ int product_id = devices_.back().product_id; devices_.push_back(CreateTouchscreenDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080))); + 2, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080))); // Create another device with the same name but different port. Ensure that // the touch device idnetifier is the same by setting the same vendor id, @@ -619,7 +619,7 @@ devices_.back().product_id = product_id; devices_.push_back(CreateTouchscreenDevice( - 3, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(1920, 1080))); + 3, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(1920, 1080))); devices_.back().name = device_name_1; devices_.back().phys = ports[2]; devices_.back().vendor_id = vendor_id; @@ -629,7 +629,7 @@ 4, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(800, 600))); devices_.push_back(CreateTouchscreenDevice( - 5, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(4096, 4096))); + 5, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(4096, 4096))); devices_.back().name = device_name_2; devices_.back().phys = ports[3]; @@ -637,7 +637,7 @@ product_id = devices_.back().product_id; devices_.push_back(CreateTouchscreenDevice( - 6, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, gfx::Size(4096, 4096))); + 6, ui::InputDeviceType::INPUT_DEVICE_USB, gfx::Size(4096, 4096))); devices_.back().name = device_name_2; devices_.back().phys = ports[4]; devices_.back().vendor_id = vendor_id;
diff --git a/ui/display/manager/touch_transform_controller_unittest.cc b/ui/display/manager/touch_transform_controller_unittest.cc index 131bb54..ba7cdd1 100644 --- a/ui/display/manager/touch_transform_controller_unittest.cc +++ b/ui/display/manager/touch_transform_controller_unittest.cc
@@ -41,7 +41,7 @@ ui::TouchscreenDevice CreateTouchscreenDevice(unsigned int id, const gfx::Size& size) { - return ui::TouchscreenDevice(id, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, + return ui::TouchscreenDevice(id, ui::InputDeviceType::INPUT_DEVICE_USB, std::string(), size, 0); }
diff --git a/ui/events/devices/device_util_linux.cc b/ui/events/devices/device_util_linux.cc index 2d703f5..d81d3a8 100644 --- a/ui/events/devices/device_util_linux.cc +++ b/ui/events/devices/device_util_linux.cc
@@ -37,8 +37,9 @@ path = path.DirName()) { // Bluetooth LE devices are virtual "uhid" devices. if (path == - base::FilePath(FILE_PATH_LITERAL("/sys/devices/virtual/misc/uhid"))) - return InputDeviceType::INPUT_DEVICE_EXTERNAL; + base::FilePath(FILE_PATH_LITERAL("/sys/devices/virtual/misc/uhid"))) { + return InputDeviceType::INPUT_DEVICE_BLUETOOTH; + } std::string subsystem_path = base::MakeAbsoluteFilePath(path.Append(FILE_PATH_LITERAL("subsystem"))) @@ -60,9 +61,9 @@ // External bus attachments. if (subsystem_path == "/sys/bus/usb") - return InputDeviceType::INPUT_DEVICE_EXTERNAL; + return InputDeviceType::INPUT_DEVICE_USB; if (subsystem_path == "/sys/class/bluetooth") - return InputDeviceType::INPUT_DEVICE_EXTERNAL; + return InputDeviceType::INPUT_DEVICE_BLUETOOTH; } return InputDeviceType::INPUT_DEVICE_UNKNOWN;
diff --git a/ui/events/devices/input_device.h b/ui/events/devices/input_device.h index f97154d9..2e0da79 100644 --- a/ui/events/devices/input_device.h +++ b/ui/events/devices/input_device.h
@@ -14,9 +14,10 @@ namespace ui { enum InputDeviceType { - INPUT_DEVICE_INTERNAL, // Internally connected input device. - INPUT_DEVICE_EXTERNAL, // Known externally connected input device. - INPUT_DEVICE_UNKNOWN, // Device that may or may not be an external device. + INPUT_DEVICE_INTERNAL, // Internally connected input device. + INPUT_DEVICE_USB, // Known externally connected usb input device. + INPUT_DEVICE_BLUETOOTH, // Known externally connected bluetooth input device. + INPUT_DEVICE_UNKNOWN, // Device that may or may not be an external device. }; // Represents an input device state.
diff --git a/ui/events/devices/mojo/input_device_struct_traits.cc b/ui/events/devices/mojo/input_device_struct_traits.cc index b7e005c..edae74a 100644 --- a/ui/events/devices/mojo/input_device_struct_traits.cc +++ b/ui/events/devices/mojo/input_device_struct_traits.cc
@@ -15,8 +15,10 @@ switch (type) { case ui::INPUT_DEVICE_INTERNAL: return ui::mojom::InputDeviceType::INPUT_DEVICE_INTERNAL; - case ui::INPUT_DEVICE_EXTERNAL: - return ui::mojom::InputDeviceType::INPUT_DEVICE_EXTERNAL; + case ui::INPUT_DEVICE_USB: + return ui::mojom::InputDeviceType::INPUT_DEVICE_USB; + case ui::INPUT_DEVICE_BLUETOOTH: + return ui::mojom::InputDeviceType::INPUT_DEVICE_BLUETOOTH; case ui::INPUT_DEVICE_UNKNOWN: return ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN; } @@ -31,8 +33,11 @@ case ui::mojom::InputDeviceType::INPUT_DEVICE_INTERNAL: *output = ui::INPUT_DEVICE_INTERNAL; break; - case ui::mojom::InputDeviceType::INPUT_DEVICE_EXTERNAL: - *output = ui::INPUT_DEVICE_EXTERNAL; + case ui::mojom::InputDeviceType::INPUT_DEVICE_USB: + *output = ui::INPUT_DEVICE_USB; + break; + case ui::mojom::InputDeviceType::INPUT_DEVICE_BLUETOOTH: + *output = ui::INPUT_DEVICE_BLUETOOTH; break; case ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN: *output = ui::INPUT_DEVICE_UNKNOWN;
diff --git a/ui/events/devices/mojo/input_devices.mojom b/ui/events/devices/mojo/input_devices.mojom index c9f60f6..2671cec 100644 --- a/ui/events/devices/mojo/input_devices.mojom +++ b/ui/events/devices/mojo/input_devices.mojom
@@ -9,7 +9,8 @@ // Corresponds to ui::InputDeviceType enum InputDeviceType { INPUT_DEVICE_INTERNAL, - INPUT_DEVICE_EXTERNAL, + INPUT_DEVICE_USB, + INPUT_DEVICE_BLUETOOTH, INPUT_DEVICE_UNKNOWN, };
diff --git a/ui/events/ozone/evdev/event_device_test_util.cc b/ui/events/ozone/evdev/event_device_test_util.cc index 86feff7..e72c4e7b 100644 --- a/ui/events/ozone/evdev/event_device_test_util.cc +++ b/ui/events/ozone/evdev/event_device_test_util.cc
@@ -634,7 +634,7 @@ return ui::InputDeviceType::INPUT_DEVICE_INTERNAL; case BUS_USB: case 0x1D: // Used in kLogitechTouchKeyboardK400 but not listed in input.h. - return ui::InputDeviceType::INPUT_DEVICE_EXTERNAL; + return ui::InputDeviceType::INPUT_DEVICE_USB; default: NOTREACHED() << "Unexpected bus type"; return ui::InputDeviceType::INPUT_DEVICE_UNKNOWN;
diff --git a/ui/latency/frame_metrics.cc b/ui/latency/frame_metrics.cc index 99bdf25..27f26b9 100644 --- a/ui/latency/frame_metrics.cc +++ b/ui/latency/frame_metrics.cc
@@ -8,6 +8,7 @@ #include <limits> #include <vector> +#include "base/bit_cast.h" #include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event_argument.h" @@ -389,6 +390,27 @@ latency_acceleration_analyzer_.StartNewReportPeriod(); } +double FrameMetrics::FastApproximateSqrt(double x) { + if (x <= 0) + return 0; + // Basically performs x*fastinvSqrt(x) - using high precision (3 steps) + double y = x; + double xhalf = 0.5f * x; + float xf = static_cast<float>(x); + int32_t i = bit_cast<int32_t>(xf); + // Magic Number for initial guess. Reference: + // http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf. + i = 0x5f3759df - (i >> 1); + x = static_cast<double>(bit_cast<float>(i)); + // Newton step. + x = x * (1.5 - xhalf * x * x); + // Newton step. + x = x * (1.5 - xhalf * x * x); + // Newton step. + x = x * (1.5 - xhalf * x * x); + return y * x; +} + namespace { // FrameMetricsTraceData delegates tracing logic to TracedValue in a deferred
diff --git a/ui/latency/frame_metrics.h b/ui/latency/frame_metrics.h index 221c11f..d0f6f35 100644 --- a/ui/latency/frame_metrics.h +++ b/ui/latency/frame_metrics.h
@@ -146,6 +146,14 @@ void AddFrameDisplayed(base::TimeTicks source_timestamp, base::TimeTicks display_timestamp); + // Compute the square root by using method described in paper: + // http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf. + // It finds a result within 0.0001 and 0.1 of the true square root for |x| < + // 100 and |x| < 2^15 respectively. It's more than 2 times faster for Nexus 4 + // and other lower end android devices and ~3-5% faster on desktop. Crash when + // x is less than 0. + static double FastApproximateSqrt(double x); + protected: void TraceStats() const;
diff --git a/ui/latency/frame_metrics_test_common.h b/ui/latency/frame_metrics_test_common.h index 30ed36d9..5ee17c4 100644 --- a/ui/latency/frame_metrics_test_common.h +++ b/ui/latency/frame_metrics_test_common.h
@@ -15,10 +15,8 @@ // Some convenience macros for checking expected error. #define EXPECT_ABS_LT(a, b) EXPECT_LT(std::abs(a), std::abs(b)) #define EXPECT_ABS_LE(a, b) EXPECT_LE(std::abs(a), std::abs(b)) -#define EXPECT_NEAR_SMR(expected, actual, weight) \ - EXPECT_NEAR(expected, actual, MaxErrorSMR(expected, weight)) -#define EXPECT_NEAR_VARIANCE_OF_ROOT(expected, actual, mean, weight) \ - EXPECT_NEAR(expected, actual, MaxErrorSMR(mean, weight)); +#define EXPECT_NEAR_SQRT_APPROX(expected, actual) \ + EXPECT_NEAR(expected, actual, MaxErrorSQRTApprox(expected, actual)) namespace ui { namespace frame_metrics { @@ -84,8 +82,8 @@ // between ~5 and ~13 decimal places. // The precision should be even better when the sample's |weight| > 1 since // the implementation should only do any rounding after scaling by weight. -inline double MaxErrorSMR(double expected_value, uint64_t weight) { - return std::max(.5, 1e-8 * expected_value / weight); +inline double MaxErrorSQRTApprox(double expected_value, double value) { + return std::max(0.5, std::max(expected_value, value) * 1e-3); } // This class initializes the ratio boundaries on construction in a way that
diff --git a/ui/latency/frame_metrics_unittest.cc b/ui/latency/frame_metrics_unittest.cc index 8306e93..55f43a7a 100644 --- a/ui/latency/frame_metrics_unittest.cc +++ b/ui/latency/frame_metrics_unittest.cc
@@ -5,6 +5,7 @@ #include "ui/latency/frame_metrics.h" #include "base/bind.h" +#include "base/rand_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/latency/frame_metrics_test_common.h" @@ -240,15 +241,13 @@ TestStreamAnalysis r = LatencyAnalysis(); EXPECT_DOUBLE_EQ(latency.InSecondsF(), r.mean); - EXPECT_DOUBLE_EQ(latency.InSecondsF(), r.rms); - EXPECT_NEAR_SMR(r.smr, latency.InSecondsF(), produced.InMicroseconds()); + EXPECT_NEAR_SQRT_APPROX(latency.InSecondsF(), r.rms); + EXPECT_NEAR_SQRT_APPROX(r.smr, latency.InSecondsF()); EXPECT_EQ(0, r.std_dev); - EXPECT_NEAR_VARIANCE_OF_ROOT(0, r.variance_of_roots, 0, - produced.InMicroseconds()); + EXPECT_NEAR_SQRT_APPROX(0, r.variance_of_roots); EXPECT_DOUBLE_EQ(latency.InSecondsF(), r.worst_mean.value); - EXPECT_DOUBLE_EQ(latency.InSecondsF(), r.worst_rms.value); - EXPECT_NEAR_SMR(r.worst_smr.value, latency.InSecondsF(), - produced.InMicroseconds()); + EXPECT_NEAR_SQRT_APPROX(latency.InSecondsF(), r.worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(r.worst_smr.value, latency.InSecondsF()); } // Apply a saw tooth pattern to the frame skips with values that are easy to @@ -276,8 +275,8 @@ const double expected_skip_to_produce_rms = std::sqrt(expected_skip_to_produce_mean_square); const double expected_skip_rms = SkipTransform(expected_skip_to_produce_rms); - EXPECT_EQ(expected_skip_rms, r.rms); - EXPECT_EQ(expected_skip_rms, r.worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(expected_skip_rms, r.rms); + EXPECT_NEAR_SQRT_APPROX(expected_skip_rms, r.worst_rms.value); const double expected_expected_skip_to_produce_mean_root = (0 + 1.0) / 2; const double expected_expected_skip_to_produce_smr = @@ -285,13 +284,13 @@ expected_expected_skip_to_produce_mean_root; const double expected_skip_smr = SkipTransform(expected_expected_skip_to_produce_smr); - EXPECT_EQ(expected_skip_smr, r.smr); - EXPECT_EQ(expected_skip_smr, r.worst_smr.value); + EXPECT_NEAR_SQRT_APPROX(expected_skip_smr, r.smr); + EXPECT_NEAR_SQRT_APPROX(expected_skip_smr, r.worst_smr.value); const double expected_skip_to_produce_std_dev = (0.5 + 0.5) / 2; const double expected_skip_std_dev = SkipTransform(expected_skip_to_produce_std_dev); - EXPECT_EQ(expected_skip_std_dev, r.std_dev); + EXPECT_NEAR_SQRT_APPROX(expected_skip_std_dev, r.std_dev); const double expected_skip_to_produce_std_dev_of_roots = (0.5 + 0.5) / 2; const double expected_skip_to_produce_variance_of_roots = @@ -299,7 +298,7 @@ expected_skip_to_produce_std_dev_of_roots; const double expected_skip_variance_of_roots = SkipTransform(expected_skip_to_produce_variance_of_roots); - EXPECT_EQ(expected_skip_variance_of_roots, r.variance_of_roots); + EXPECT_NEAR_SQRT_APPROX(expected_skip_variance_of_roots, r.variance_of_roots); } // Apply a saw tooth pattern to the latency with values that are easy to @@ -322,34 +321,35 @@ const double expected_latency_mean_square = (100.0 * 100 + 36 * 36) / 2; const double expected_latency_rms = std::sqrt(expected_latency_mean_square); - EXPECT_DOUBLE_EQ(expected_latency_rms, r.rms); - EXPECT_DOUBLE_EQ(expected_latency_rms, r.worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(expected_latency_rms, r.rms); + EXPECT_NEAR_SQRT_APPROX(expected_latency_rms, r.worst_rms.value); const double expected_latency_mean_root = (10.0 + 6) / 2; const double expected_latency_smr = expected_latency_mean_root * expected_latency_mean_root; - EXPECT_DOUBLE_EQ(expected_latency_smr, r.smr); - EXPECT_DOUBLE_EQ(expected_latency_smr, r.worst_smr.value); + EXPECT_NEAR_SQRT_APPROX(expected_latency_smr, r.smr); + EXPECT_NEAR_SQRT_APPROX(expected_latency_smr, r.worst_smr.value); const double expected_latency_std_dev = (100.0 - 36) / 2; - EXPECT_DOUBLE_EQ(expected_latency_std_dev, r.std_dev); + EXPECT_NEAR_SQRT_APPROX(expected_latency_std_dev, r.std_dev); const double expected_latency_std_dev_of_roots = (10.0 - 6) / 2; const double expected_latency_variance_of_roots = expected_latency_std_dev_of_roots * expected_latency_std_dev_of_roots; - EXPECT_DOUBLE_EQ(expected_latency_variance_of_roots, r.variance_of_roots); + EXPECT_NEAR_SQRT_APPROX(expected_latency_variance_of_roots, + r.variance_of_roots); // Verify latency speed, where mean, RMS, SMR, etc. should be equal. r = SpeedAnalysis(); const double expected_speed = 64; EXPECT_DOUBLE_EQ(expected_speed, r.mean); - EXPECT_DOUBLE_EQ(expected_speed, r.rms); - EXPECT_DOUBLE_EQ(expected_speed, r.smr); + EXPECT_NEAR_SQRT_APPROX(expected_speed, r.rms); + EXPECT_NEAR_SQRT_APPROX(expected_speed, r.smr); EXPECT_DOUBLE_EQ(0, r.std_dev); - EXPECT_DOUBLE_EQ(0, r.variance_of_roots); + EXPECT_NEAR_SQRT_APPROX(0, r.variance_of_roots); EXPECT_DOUBLE_EQ(expected_speed, r.worst_mean.value); - EXPECT_DOUBLE_EQ(expected_speed, r.worst_rms.value); - EXPECT_DOUBLE_EQ(expected_speed, r.worst_smr.value); + EXPECT_NEAR_SQRT_APPROX(expected_speed, r.worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(expected_speed, r.worst_smr.value); // Verify latency accelleration, where mean, RMS, SMR, etc. should be equal. // The slack is relatively large since the frame durations are so long, which @@ -889,6 +889,30 @@ &FrameMetricsTest::AccelerationAnalysis); } +// Test the accuracy of the Newton's approximate square root calculation. +// Since suqare_rooot is always used on small numbers in cc, this test only test +// accuracy of small |x| value. A random number |x| between (0 - 100) is +// generated, Test if the difference of square roots obtained from +// FastApproximateSqrt and std::sqrt is less than |error_rage| (0.0001); +TEST_F(FrameMetricsTest, SquareRootApproximation) { + const double slack = 0.001; + for (int i = 0; i < 3; i++) { + int x = base::RandInt(0, 100); + double sol1 = std::sqrt(x); + double sol2 = FrameMetrics::FastApproximateSqrt(x); + EXPECT_NEAR(sol1, sol2, slack) + << "failed to give a good approximate square root of " << x; + } + + for (int i = 0; i < 3; i++) { + double x = double{base::RandUint64()} / base::RandomBitGenerator::max(); + double sol1 = std::sqrt(x); + double sol2 = FrameMetrics::FastApproximateSqrt(x); + EXPECT_NEAR(sol1, sol2, slack) + << "failed to give a good approximate square root of " << x; + } +} + } // namespace } // namespace frame_metrics } // namespace ui
diff --git a/ui/latency/stream_analyzer.cc b/ui/latency/stream_analyzer.cc index 0453e27..2623e46 100644 --- a/ui/latency/stream_analyzer.cc +++ b/ui/latency/stream_analyzer.cc
@@ -4,6 +4,8 @@ #include "ui/latency/stream_analyzer.h" +#include "ui/latency/frame_metrics.h" + namespace ui { StreamAnalysis::StreamAnalysis() = default; @@ -89,8 +91,9 @@ DCHECK_GT(weight, 0u); const uint64_t weighted_value = static_cast<uint64_t>(weight) * value; - const uint64_t weighted_root = weight * std::sqrt(static_cast<double>(value) * - kFixedPointRootMultiplier); + const uint64_t weighted_root = + weight * FrameMetrics::FastApproximateSqrt(static_cast<double>(value) * + kFixedPointRootMultiplier); const Accumulator96b weighted_square(value, weight); // Verify overflow isn't an issue. @@ -128,7 +131,7 @@ double StreamAnalyzer::ComputeRMS() const { double mean_square = square_accumulator_.ToDouble() / total_weight_; - double result = std::sqrt(mean_square); + double result = FrameMetrics::FastApproximateSqrt(mean_square); return client_->TransformResult(result); } @@ -152,7 +155,7 @@ double StreamAnalyzer::ComputeStdDev() const { double variance = VarianceHelper(accumulator_, square_accumulator_.ToDouble()); - double std_dev = std::sqrt(variance); + double std_dev = FrameMetrics::FrameMetrics::FastApproximateSqrt(variance); return client_->TransformResult(std_dev); }
diff --git a/ui/latency/stream_analyzer_unittest.cc b/ui/latency/stream_analyzer_unittest.cc index 0841096..5aca77c 100644 --- a/ui/latency/stream_analyzer_unittest.cc +++ b/ui/latency/stream_analyzer_unittest.cc
@@ -44,6 +44,7 @@ }; TEST_F(StreamAnalyzerTest, AllResultsTheSame) { + const double approx_sqrt_error = 0.0001; // Try adding a single sample vs. multiple samples. for (size_t samples : {1u, 100u}) { // A power of 2 sweep for both the value and weight dimensions. @@ -57,17 +58,18 @@ uint64_t expected_value = value * TestStreamAnalyzerClient::result_scale; EXPECT_EQ(expected_value, analyzer_->ComputeMean()); - EXPECT_EQ(expected_value, analyzer_->ComputeRMS()); - EXPECT_NEAR_SMR(analyzer_->ComputeSMR(), expected_value, weight); - EXPECT_DOUBLE_EQ(0, analyzer_->ComputeStdDev()); - EXPECT_NEAR_VARIANCE_OF_ROOT(0, analyzer_->ComputeVarianceOfRoots(), - expected_value, weight); + EXPECT_NEAR_SQRT_APPROX(expected_value, analyzer_->ComputeRMS()); + EXPECT_NEAR_SQRT_APPROX(analyzer_->ComputeSMR(), expected_value); + EXPECT_NEAR_SQRT_APPROX(0, analyzer_->ComputeStdDev()); + EXPECT_NEAR(0, analyzer_->ComputeVarianceOfRoots(), + approx_sqrt_error * value); // Verify values are forwarded to the WindowedAnalyzer. EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstMean().value); - EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstRMS().value); - EXPECT_NEAR_SMR(expected_value, - analyzer_->window().ComputeWorstSMR().value, weight); + EXPECT_NEAR_SQRT_APPROX(expected_value, + analyzer_->window().ComputeWorstRMS().value); + EXPECT_NEAR_SQRT_APPROX(expected_value, + analyzer_->window().ComputeWorstSMR().value); } } } @@ -83,17 +85,18 @@ uint64_t expected_value = value * TestStreamAnalyzerClient::result_scale; // Makes sure our precision is good enough. EXPECT_EQ(expected_value, analyzer_->ComputeMean()); - EXPECT_EQ(expected_value, analyzer_->ComputeRMS()); - EXPECT_NEAR_SMR(expected_value, analyzer_->ComputeSMR(), weight); - EXPECT_DOUBLE_EQ(0, analyzer_->ComputeStdDev()); - EXPECT_NEAR_VARIANCE_OF_ROOT(0, analyzer_->ComputeVarianceOfRoots(), - expected_value, weight); + EXPECT_NEAR_SQRT_APPROX(expected_value, analyzer_->ComputeRMS()); + EXPECT_NEAR_SQRT_APPROX(expected_value, analyzer_->ComputeSMR()); + EXPECT_NEAR_SQRT_APPROX(0, analyzer_->ComputeStdDev()); + EXPECT_NEAR(0, analyzer_->ComputeVarianceOfRoots(), + approx_sqrt_error * value); // Verify values are forwarded to the WindowedAnalyzer. EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstMean().value); - EXPECT_EQ(expected_value, analyzer_->window().ComputeWorstRMS().value); - EXPECT_NEAR_SMR(expected_value, - analyzer_->window().ComputeWorstSMR().value, weight); + EXPECT_NEAR_SQRT_APPROX(expected_value, + analyzer_->window().ComputeWorstRMS().value); + EXPECT_NEAR_SQRT_APPROX(expected_value, + analyzer_->window().ComputeWorstSMR().value); } } } @@ -133,11 +136,12 @@ for (size_t i = 0; i < 1000; i++) { AddPatternHelper(&shared_client_, analyzer(), pattern49, kSampleWeight); EXPECT_DOUBLE_EQ(expected_mean, analyzer_->ComputeMean()); - EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), kSampleWeight); - EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS()); - EXPECT_DOUBLE_EQ(expected_std_dev, analyzer_->ComputeStdDev()); - EXPECT_DOUBLE_EQ(expected_variance_of_roots, - analyzer_->ComputeVarianceOfRoots()); + // since each value creates a difference of 0.001, the result should + EXPECT_NEAR_SQRT_APPROX(expected_smr, analyzer_->ComputeSMR()); + EXPECT_NEAR_SQRT_APPROX(expected_rms, analyzer_->ComputeRMS()); + EXPECT_NEAR_SQRT_APPROX(expected_std_dev, analyzer_->ComputeStdDev()); + EXPECT_NEAR_SQRT_APPROX(expected_variance_of_roots, + analyzer_->ComputeVarianceOfRoots()); } thresholds = analyzer_->ComputeThresholds(); ASSERT_EQ(3u, thresholds.size()); @@ -158,11 +162,11 @@ } thresholds = analyzer_->ComputeThresholds(); EXPECT_DOUBLE_EQ(expected_mean, analyzer_->ComputeMean()); - EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), kSampleWeight); - EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS()); - EXPECT_DOUBLE_EQ(expected_std_dev, analyzer_->ComputeStdDev()); - EXPECT_DOUBLE_EQ(expected_variance_of_roots, - analyzer_->ComputeVarianceOfRoots()); + EXPECT_NEAR_SQRT_APPROX(expected_smr, analyzer_->ComputeSMR()); + EXPECT_NEAR_SQRT_APPROX(expected_rms, analyzer_->ComputeRMS()); + EXPECT_NEAR_SQRT_APPROX(expected_std_dev, analyzer_->ComputeStdDev()); + EXPECT_NEAR_SQRT_APPROX(expected_variance_of_roots, + analyzer_->ComputeVarianceOfRoots()); EXPECT_EQ(client_.TransformResult(thresholds_[0]), thresholds[0].threshold); EXPECT_EQ(client_.TransformResult(thresholds_[1]), thresholds[1].threshold); EXPECT_EQ(client_.TransformResult(thresholds_[2]), thresholds[2].threshold); @@ -180,11 +184,11 @@ } thresholds = analyzer_->ComputeThresholds(); EXPECT_DOUBLE_EQ(expected_mean, analyzer_->ComputeMean()); - EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), kSampleWeight); - EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS()); - EXPECT_DOUBLE_EQ(expected_std_dev, analyzer_->ComputeStdDev()); - EXPECT_DOUBLE_EQ(expected_variance_of_roots, - analyzer_->ComputeVarianceOfRoots()); + EXPECT_NEAR_SQRT_APPROX(expected_smr, analyzer_->ComputeSMR()); + EXPECT_NEAR_SQRT_APPROX(expected_rms, analyzer_->ComputeRMS()); + EXPECT_NEAR_SQRT_APPROX(expected_std_dev, analyzer_->ComputeStdDev()); + EXPECT_NEAR_SQRT_APPROX(expected_variance_of_roots, + analyzer_->ComputeVarianceOfRoots()); EXPECT_EQ(client_.TransformResult(thresholds_[0]), thresholds[0].threshold); EXPECT_EQ(client_.TransformResult(thresholds_[1]), thresholds[1].threshold); EXPECT_EQ(client_.TransformResult(thresholds_[2]), thresholds[2].threshold); @@ -295,7 +299,7 @@ double expected_rms = client_.TransformResult(std::sqrt(mean_square)); EXPECT_ABS_LT(expected_rms * .001, expected_rms - naive_analyzer.ComputeRMS()); - EXPECT_DOUBLE_EQ(expected_rms, analyzer_->ComputeRMS()); + EXPECT_NEAR_SQRT_APPROX(expected_rms, analyzer_->ComputeRMS()); double large_value_root = std::sqrt(large_value_f) * large_weight; double small_value_root = std::sqrt(small_value_f) * small_weight; @@ -304,7 +308,7 @@ double expected_smr = client_.TransformResult(mean_root * mean_root); EXPECT_ABS_LT(expected_smr * .001, expected_smr - naive_analyzer.ComputeSMR()); - EXPECT_NEAR_SMR(expected_smr, analyzer_->ComputeSMR(), 1); + EXPECT_NEAR_SQRT_APPROX(expected_smr, analyzer_->ComputeSMR()); } } // namespace
diff --git a/ui/latency/windowed_analyzer.cc b/ui/latency/windowed_analyzer.cc index a78d003..cd718d87 100644 --- a/ui/latency/windowed_analyzer.cc +++ b/ui/latency/windowed_analyzer.cc
@@ -4,6 +4,8 @@ #include "ui/latency/windowed_analyzer.h" +#include "ui/latency/frame_metrics.h" + namespace ui { void FrameRegionResult::AsValueInto( @@ -57,9 +59,10 @@ accumulator_ -= static_cast<uint64_t>(old_weight) * old_value; // Casting the whole rhs is important to ensure rounding happens at a place // equivalent to when it was added. - root_accumulator_ -= static_cast<uint64_t>( - old_weight * - std::sqrt(static_cast<uint64_t>(old_value) << kFixedPointRootShift)); + root_accumulator_ -= + static_cast<uint64_t>(old_weight * FrameMetrics::FastApproximateSqrt( + static_cast<uint64_t>(old_value) + << kFixedPointRootShift)); square_accumulator_.Subtract(Accumulator96b(old_value, old_weight)); } @@ -107,7 +110,8 @@ } else { UpdateWorst(square_accumulator_, &result, true); } - result.value = client_->TransformResult(std::sqrt(result.value)); + result.value = + client_->TransformResult(FrameMetrics::FastApproximateSqrt(result.value)); return result; }
diff --git a/ui/latency/windowed_analyzer_unittest.cc b/ui/latency/windowed_analyzer_unittest.cc index f60eb82..5aa05034 100644 --- a/ui/latency/windowed_analyzer_unittest.cc +++ b/ui/latency/windowed_analyzer_unittest.cc
@@ -36,10 +36,11 @@ value * TestWindowedAnalyzerClient::result_scale; EXPECT_EQ(analyzer.ComputeWorstMean().value, expected_value) << value << " x " << weight; - EXPECT_EQ(analyzer.ComputeWorstRMS().value, expected_value) + EXPECT_NEAR_SQRT_APPROX(analyzer.ComputeWorstRMS().value, + expected_value) << value << " x " << weight; - EXPECT_NEAR_SMR(analyzer.ComputeWorstSMR().value, expected_value, - weight) + EXPECT_NEAR_SQRT_APPROX(analyzer.ComputeWorstSMR().value, + expected_value) << value << " x " << weight; } } @@ -58,9 +59,9 @@ // Makes sure our precision is good enough. EXPECT_EQ(analyzer.ComputeWorstMean().value, expected_value) << value << " x " << weight; - EXPECT_EQ(analyzer.ComputeWorstRMS().value, expected_value) + EXPECT_NEAR_SQRT_APPROX(analyzer.ComputeWorstRMS().value, expected_value) << value << " x " << weight; - EXPECT_NEAR_SMR(analyzer.ComputeWorstSMR().value, expected_value, weight) + EXPECT_NEAR_SQRT_APPROX(analyzer.ComputeWorstSMR().value, expected_value) << value << " x " << weight; } } @@ -126,12 +127,12 @@ EXPECT_EQ(worst_mean_client.window_end, worst_mean.window_end); FrameRegionResult worst_smr = analyzer.ComputeWorstSMR(); - EXPECT_NEAR_SMR(expected_worst_smr, worst_smr.value, kSampleWeight); + EXPECT_NEAR_SQRT_APPROX(expected_worst_smr, worst_smr.value); EXPECT_EQ(worst_smr_client.window_begin, worst_smr.window_begin); EXPECT_EQ(worst_smr_client.window_end, worst_smr.window_end); FrameRegionResult worst_rms = analyzer.ComputeWorstRMS(); - EXPECT_DOUBLE_EQ(expected_worst_rms, worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(expected_worst_rms, worst_rms.value); EXPECT_EQ(worst_rms_client.window_begin, worst_rms.window_begin); EXPECT_EQ(worst_rms_client.window_end, worst_rms.window_end); } @@ -160,12 +161,12 @@ EXPECT_EQ(short_client.window_end, worst_mean.window_end); FrameRegionResult worst_smr = analyzer.ComputeWorstSMR(); - EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight); + EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_smr.value); EXPECT_EQ(short_client.window_begin, worst_smr.window_begin); EXPECT_EQ(short_client.window_end, worst_smr.window_end); FrameRegionResult worst_rms = analyzer.ComputeWorstRMS(); - EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_rms.value); EXPECT_EQ(short_client.window_begin, worst_rms.window_begin); EXPECT_EQ(short_client.window_end, worst_rms.window_end); } @@ -197,12 +198,12 @@ EXPECT_EQ(short_client.window_end, worst_mean.window_end); worst_smr = analyzer.ComputeWorstSMR(); - EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight); + EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_smr.value); EXPECT_EQ(short_client.window_begin, worst_smr.window_begin); EXPECT_EQ(short_client.window_end, worst_smr.window_end); worst_rms = analyzer.ComputeWorstRMS(); - EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_rms.value); EXPECT_EQ(short_client.window_begin, worst_rms.window_begin); EXPECT_EQ(short_client.window_end, worst_rms.window_end); @@ -223,12 +224,12 @@ EXPECT_EQ(long_client.window_end, worst_mean.window_end); worst_smr = analyzer.ComputeWorstSMR(); - EXPECT_NEAR_SMR(expected_final_value, worst_smr.value, kSampleWeight); + EXPECT_NEAR_SQRT_APPROX(expected_final_value, worst_smr.value); EXPECT_EQ(long_client.window_begin, worst_smr.window_begin); EXPECT_EQ(long_client.window_end, worst_smr.window_end); worst_rms = analyzer.ComputeWorstRMS(); - EXPECT_DOUBLE_EQ(expected_final_value, worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(expected_final_value, worst_rms.value); EXPECT_EQ(long_client.window_begin, worst_rms.window_begin); EXPECT_EQ(long_client.window_end, worst_rms.window_end); } @@ -258,12 +259,12 @@ EXPECT_EQ(initial_client.window_end, worst_mean.window_end); worst_smr = analyzer.ComputeWorstSMR(); - EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight); + EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_smr.value); EXPECT_EQ(initial_client.window_begin, worst_smr.window_begin); EXPECT_EQ(initial_client.window_end, worst_smr.window_end); worst_rms = analyzer.ComputeWorstRMS(); - EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_rms.value); EXPECT_EQ(initial_client.window_begin, worst_rms.window_begin); EXPECT_EQ(initial_client.window_end, worst_rms.window_end); @@ -278,12 +279,12 @@ EXPECT_EQ(initial_client.window_end, worst_mean.window_end); worst_smr = analyzer.ComputeWorstSMR(); - EXPECT_NEAR_SMR(expected_initial_value, worst_smr.value, kSampleWeight); + EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_smr.value); EXPECT_EQ(initial_client.window_begin, worst_smr.window_begin); EXPECT_EQ(initial_client.window_end, worst_smr.window_end); worst_rms = analyzer.ComputeWorstRMS(); - EXPECT_DOUBLE_EQ(expected_initial_value, worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(expected_initial_value, worst_rms.value); EXPECT_EQ(initial_client.window_begin, worst_rms.window_begin); EXPECT_EQ(initial_client.window_end, worst_rms.window_end); @@ -309,12 +310,12 @@ EXPECT_EQ(final_client.window_end, worst_mean.window_end); worst_smr = analyzer.ComputeWorstSMR(); - EXPECT_NEAR_SMR(expected_final_value, worst_smr.value, kSampleWeight); + EXPECT_NEAR_SQRT_APPROX(expected_final_value, worst_smr.value); EXPECT_EQ(final_client.window_begin, worst_smr.window_begin); EXPECT_EQ(final_client.window_end, worst_smr.window_end); worst_rms = analyzer.ComputeWorstRMS(); - EXPECT_DOUBLE_EQ(expected_final_value, worst_rms.value); + EXPECT_NEAR_SQRT_APPROX(expected_final_value, worst_rms.value); EXPECT_EQ(final_client.window_begin, worst_rms.window_begin); EXPECT_EQ(final_client.window_end, worst_rms.window_end); }
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn index 76dcdb5..7d3c40afd 100644 --- a/ui/ozone/platform/wayland/BUILD.gn +++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -37,6 +37,10 @@ "wayland_data_offer.h", "wayland_data_source.cc", "wayland_data_source.h", + "wayland_input_method_context.cc", + "wayland_input_method_context.h", + "wayland_input_method_context_factory.cc", + "wayland_input_method_context_factory.h", "wayland_keyboard.cc", "wayland_keyboard.h", "wayland_native_display_delegate.cc", @@ -66,6 +70,9 @@ "xdg_surface_wrapper_v5.h", "xdg_surface_wrapper_v6.cc", "xdg_surface_wrapper_v6.h", + "zwp_text_input_wrapper.h", + "zwp_text_input_wrapper_v1.cc", + "zwp_text_input_wrapper_v1.h", ] import("//ui/base/ui_features.gni") @@ -86,12 +93,15 @@ "//third_party/wayland:wayland_client", "//third_party/wayland-protocols:linux_dmabuf_protocol", "//third_party/wayland-protocols:presentation_time_protocol", + "//third_party/wayland-protocols:text_input_protocol", "//third_party/wayland-protocols:xdg_shell_protocol", "//ui/base", "//ui/base:ui_features", + "//ui/base/ime/linux", "//ui/display/manager", "//ui/events", "//ui/events:dom_keycode_converter", + "//ui/events/keycodes:xkb", "//ui/events/ozone:events_ozone", "//ui/events/ozone:events_ozone_evdev", "//ui/events/ozone:events_ozone_layout", @@ -143,6 +153,7 @@ "fake_server.h", "wayland_connection_unittest.cc", "wayland_data_device_unittest.cc", + "wayland_input_method_context_unittest.cc", "wayland_keyboard_unittest.cc", "wayland_pointer_unittest.cc", "wayland_surface_factory_unittest.cc", @@ -160,6 +171,7 @@ "//third_party/wayland-protocols:xdg_shell_protocol", "//ui/base", "//ui/base:ui_features", + "//ui/base/ime/linux", "//ui/events/ozone:events_ozone_layout", "//ui/ozone:platform", "//ui/ozone:test_support",
diff --git a/ui/ozone/platform/wayland/DEPS b/ui/ozone/platform/wayland/DEPS index 42e7c86b..73360bcf 100644 --- a/ui/ozone/platform/wayland/DEPS +++ b/ui/ozone/platform/wayland/DEPS
@@ -1,5 +1,8 @@ include_rules = [ "+ui/base/ui_features.h", # UI features doesn't bring in all of ui/base. + "+ui/base/ime/composition_text.h", + "+ui/base/ime/linux/linux_input_method_context.h", + "+ui/base/ime/linux/linux_input_method_context_factory.h", "+mojo/public", "+ui/base/dragdrop/drag_drop_types.h", "+ui/base/dragdrop/os_exchange_data.h",
diff --git a/ui/ozone/platform/wayland/fake_server.cc b/ui/ozone/platform/wayland/fake_server.cc index 2bd0f9c..d9edf99f 100644 --- a/ui/ozone/platform/wayland/fake_server.cc +++ b/ui/ozone/platform/wayland/fake_server.cc
@@ -3,7 +3,9 @@ // found in the LICENSE file. #include "ui/ozone/platform/wayland/fake_server.h" + #include <sys/socket.h> +#include <text-input-unstable-v1-server-protocol.h> #include <wayland-server.h> #include <xdg-shell-unstable-v5-server-protocol.h> #include <xdg-shell-unstable-v6-server-protocol.h> @@ -21,11 +23,12 @@ namespace wl { namespace { -const uint32_t kCompositorVersion = 4; -const uint32_t kOutputVersion = 2; -const uint32_t kDataDeviceManagerVersion = 3; -const uint32_t kSeatVersion = 4; -const uint32_t kXdgShellVersion = 1; +constexpr uint32_t kCompositorVersion = 4; +constexpr uint32_t kOutputVersion = 2; +constexpr uint32_t kDataDeviceManagerVersion = 3; +constexpr uint32_t kSeatVersion = 4; +constexpr uint32_t kTextInputManagerVersion = 1; +constexpr uint32_t kXdgShellVersion = 1; bool ResourceHasImplementation(wl_resource* resource, const wl_interface* interface, @@ -471,6 +474,84 @@ &DestroyResource, // release }; +// zwp_text_input_v1 + +void TextInputV1Activate(wl_client* client, + wl_resource* resource, + wl_resource* seat, + wl_resource* surface) { + static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource)) + ->Activate(surface); +} + +void TextInputV1Deactivate(wl_client* client, + wl_resource* resource, + wl_resource* seat) { + static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource)) + ->Deactivate(); +} + +void TextInputV1ShowInputPanel(wl_client* client, wl_resource* resource) { + static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource)) + ->ShowInputPanel(); +} + +void TextInputV1HideInputPanel(wl_client* client, wl_resource* resource) { + static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource)) + ->HideInputPanel(); +} + +void TextInputV1Reset(wl_client* client, wl_resource* resource) { + static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource))->Reset(); +} + +void TextInputV1SetCursorRectangle(wl_client* client, + wl_resource* resource, + int32_t x, + int32_t y, + int32_t width, + int32_t height) { + static_cast<MockZwpTextInput*>(wl_resource_get_user_data(resource)) + ->SetCursorRect(x, y, width, height); +} + +const struct zwp_text_input_v1_interface zwp_text_input_v1_impl = { + &TextInputV1Activate, // activate + &TextInputV1Deactivate, // deactivate + &TextInputV1ShowInputPanel, // show_input_panel + &TextInputV1HideInputPanel, // hide_input_panel + &TextInputV1Reset, // reset + nullptr, // set_surrounding_text + nullptr, // set_content_type + &TextInputV1SetCursorRectangle, // set_cursor_rectangle + nullptr, // set_preferred_language + nullptr, // commit_state + nullptr, // invoke_action +}; + +// zwp_text_input_manager_v1 + +void CreateTextInput(struct wl_client* client, + struct wl_resource* resource, + uint32_t id) { + auto* im = + static_cast<MockTextInputManagerV1*>(wl_resource_get_user_data(resource)); + wl_resource* text_resource = + wl_resource_create(client, &zwp_text_input_v1_interface, + wl_resource_get_version(resource), id); + if (!text_resource) { + wl_client_post_no_memory(client); + return; + } + im->text_input.reset( + new MockZwpTextInput(text_resource, &zwp_text_input_v1_impl)); +} + +const struct zwp_text_input_manager_v1_interface + zwp_text_input_manager_v1_impl = { + &CreateTextInput, // create_text_input +}; + // xdg_surface, zxdg_surface_v6 and zxdg_toplevel shared methods. void SetTitle(wl_client* client, wl_resource* resource, const char* title) { @@ -800,6 +881,15 @@ MockTouch::~MockTouch() {} +MockZwpTextInput::MockZwpTextInput(wl_resource* resource, + const void* implementation) + : ServerObject(resource) { + wl_resource_set_implementation(resource, implementation, this, + &ServerObject::OnResourceDestroyed); +} + +MockZwpTextInput::~MockZwpTextInput() {} + MockDataOffer::MockDataOffer(wl_resource* resource) : ServerObject(resource), io_thread_("Worker thread"), @@ -1006,6 +1096,13 @@ MockXdgShellV6::~MockXdgShellV6() {} +MockTextInputManagerV1::MockTextInputManagerV1() + : Global(&zwp_text_input_manager_v1_interface, + &zwp_text_input_manager_v1_impl, + kTextInputManagerVersion) {} + +MockTextInputManagerV1::~MockTextInputManagerV1() {} + void DisplayDeleter::operator()(wl_display* display) { wl_display_destroy(display); } @@ -1052,6 +1149,8 @@ if (!zxdg_shell_v6_.Initialize(display_.get())) return false; } + if (!zwp_text_input_manager_v1_.Initialize(display_.get())) + return false; client_ = wl_client_create(display_.get(), server_fd.get()); if (!client_)
diff --git a/ui/ozone/platform/wayland/fake_server.h b/ui/ozone/platform/wayland/fake_server.h index 4ee8348..27b8f07 100644 --- a/ui/ozone/platform/wayland/fake_server.h +++ b/ui/ozone/platform/wayland/fake_server.h
@@ -182,6 +182,24 @@ DISALLOW_COPY_AND_ASSIGN(MockTouch); }; +// Manage zwp_text_input_v1. +class MockZwpTextInput : public ServerObject { + public: + MockZwpTextInput(wl_resource* resource, const void* implementation); + ~MockZwpTextInput() override; + + MOCK_METHOD0(Reset, void()); + MOCK_METHOD1(Activate, void(wl_resource* window)); + MOCK_METHOD0(Deactivate, void()); + MOCK_METHOD0(ShowInputPanel, void()); + MOCK_METHOD0(HideInputPanel, void()); + MOCK_METHOD4(SetCursorRect, + void(int32_t x, int32_t y, int32_t width, int32_t height)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockZwpTextInput); +}; + class MockDataOffer : public ServerObject { public: explicit MockDataOffer(wl_resource* resource); @@ -392,6 +410,18 @@ DISALLOW_COPY_AND_ASSIGN(MockXdgShellV6); }; +// Manage zwp_text_input_manager_v1 object. +class MockTextInputManagerV1 : public Global { + public: + MockTextInputManagerV1(); + ~MockTextInputManagerV1() override; + + std::unique_ptr<MockZwpTextInput> text_input; + + private: + DISALLOW_COPY_AND_ASSIGN(MockTextInputManagerV1); +}; + struct DisplayDeleter { void operator()(wl_display* display); }; @@ -425,6 +455,9 @@ MockSeat* seat() { return &seat_; } MockXdgShell* xdg_shell() { return &xdg_shell_; } MockOutput* output() { return &output_; } + MockTextInputManagerV1* text_input_manager_v1() { + return &zwp_text_input_manager_v1_; + } private: void DoPause(); @@ -449,6 +482,7 @@ MockSeat seat_; MockXdgShell xdg_shell_; MockXdgShellV6 zxdg_shell_v6_; + MockTextInputManagerV1 zwp_text_input_manager_v1_; base::MessagePumpLibevent::FdWatchController controller_;
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc index 4476357..c19c251 100644 --- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc +++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -14,6 +14,7 @@ #include "ui/ozone/platform/wayland/gpu/wayland_connection_proxy.h" #include "ui/ozone/platform/wayland/wayland_connection.h" #include "ui/ozone/platform/wayland/wayland_connection_connector.h" +#include "ui/ozone/platform/wayland/wayland_input_method_context_factory.h" #include "ui/ozone/platform/wayland/wayland_native_display_delegate.h" #include "ui/ozone/platform/wayland/wayland_surface_factory.h" #include "ui/ozone/platform/wayland/wayland_window.h" @@ -80,6 +81,15 @@ std::unique_ptr<PlatformWindow> CreatePlatformWindow( PlatformWindowDelegate* delegate, PlatformWindowInitProperties properties) override { + // Some unit tests may try to set custom input method context factory + // after InitializeUI. Thus instead of creating factory in InitializeUI + // it is set at this point if none exists + if (!LinuxInputMethodContextFactory::instance() && + !wayland_input_method_context_factory_) { + wayland_input_method_context_factory_.reset( + new WaylandInputMethodContextFactory(connection_.get())); + } + auto window = std::make_unique<WaylandWindow>(delegate, connection_.get()); if (!window->Initialize(std::move(properties))) return nullptr; @@ -168,6 +178,8 @@ std::unique_ptr<StubOverlayManager> overlay_manager_; std::unique_ptr<InputController> input_controller_; std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_; + std::unique_ptr<WaylandInputMethodContextFactory> + wayland_input_method_context_factory_; #if BUILDFLAG(USE_XKBCOMMON) XkbEvdevCodes xkb_evdev_code_converter_;
diff --git a/ui/ozone/platform/wayland/wayland_connection.cc b/ui/ozone/platform/wayland/wayland_connection.cc index b0cd50e3..0ddacd8 100644 --- a/ui/ozone/platform/wayland/wayland_connection.cc +++ b/ui/ozone/platform/wayland/wayland_connection.cc
@@ -16,6 +16,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "ui/gfx/swap_result.h" #include "ui/ozone/platform/wayland/wayland_buffer_manager.h" +#include "ui/ozone/platform/wayland/wayland_input_method_context.h" #include "ui/ozone/platform/wayland/wayland_object.h" #include "ui/ozone/platform/wayland/wayland_window.h" @@ -31,6 +32,7 @@ constexpr uint32_t kMaxXdgShellVersion = 1; constexpr uint32_t kMaxDeviceManagerVersion = 3; constexpr uint32_t kMaxWpPresentationVersion = 1; +constexpr uint32_t kMaxTextInputManagerVersion = 1; std::unique_ptr<WaylandDataSource> CreateWaylandDataSource( WaylandDataDeviceManager* data_device_manager, @@ -128,6 +130,15 @@ return nullptr; } +WaylandWindow* WaylandConnection::GetCurrentKeyboardFocusedWindow() { + for (auto entry : window_map_) { + WaylandWindow* window = entry.second; + if (window->has_keyboard_focus()) + return window; + } + return nullptr; +} + void WaylandConnection::AddWindow(gfx::AcceleratedWidget widget, WaylandWindow* window) { window_map_[widget] = window; @@ -445,6 +456,14 @@ (strcmp(interface, "wp_presentation") == 0)) { connection->presentation_ = wl::Bind<wp_presentation>(registry, name, kMaxWpPresentationVersion); + } else if (!connection->text_input_manager_v1_ && + strcmp(interface, "zwp_text_input_manager_v1") == 0) { + connection->text_input_manager_v1_ = wl::Bind<zwp_text_input_manager_v1>( + registry, name, std::min(version, kMaxTextInputManagerVersion)); + if (!connection->text_input_manager_v1_) { + LOG(ERROR) << "Failed to bind to zwp_text_input_manager_v1 global"; + return; + } } connection->ScheduleFlush();
diff --git a/ui/ozone/platform/wayland/wayland_connection.h b/ui/ozone/platform/wayland/wayland_connection.h index 961bf6f..15eecf7 100644 --- a/ui/ozone/platform/wayland/wayland_connection.h +++ b/ui/ozone/platform/wayland/wayland_connection.h
@@ -76,9 +76,13 @@ wl_seat* seat() { return seat_.get(); } wl_data_device* data_device() { return data_device_->data_device(); } wp_presentation* presentation() const { return presentation_.get(); } + zwp_text_input_manager_v1* text_input_manager_v1() { + return text_input_manager_v1_.get(); + } WaylandWindow* GetWindow(gfx::AcceleratedWidget widget); WaylandWindow* GetCurrentFocusedWindow(); + WaylandWindow* GetCurrentKeyboardFocusedWindow(); void AddWindow(gfx::AcceleratedWidget widget, WaylandWindow* window); void RemoveWindow(gfx::AcceleratedWidget widget); @@ -143,6 +147,9 @@ base::OnceCallback<void(const std::string&)> callback); private: + // WaylandInputMethodContextFactory needs access to DispatchUiEvent + friend class WaylandInputMethodContextFactory; + void Flush(); void DispatchUiEvent(Event* event); @@ -185,6 +192,7 @@ wl::Object<xdg_shell> shell_; wl::Object<zxdg_shell_v6> shell_v6_; wl::Object<wp_presentation> presentation_; + wl::Object<zwp_text_input_manager_v1> text_input_manager_v1_; std::unique_ptr<WaylandDataDeviceManager> data_device_manager_; std::unique_ptr<WaylandDataDevice> data_device_;
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context.cc b/ui/ozone/platform/wayland/wayland_input_method_context.cc new file mode 100644 index 0000000..959a8e3 --- /dev/null +++ b/ui/ozone/platform/wayland/wayland_input_method_context.cc
@@ -0,0 +1,151 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/ozone/platform/wayland/wayland_input_method_context.h" + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/memory/ptr_util.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/ime/composition_text.h" +#include "ui/events/base_event_utils.h" +#include "ui/events/event.h" +#include "ui/events/keycodes/dom/dom_code.h" +#include "ui/events/keycodes/dom/keycode_converter.h" +#include "ui/events/keycodes/keyboard_code_conversion.h" +#include "ui/events/keycodes/keyboard_code_conversion_xkb.h" +#include "ui/events/ozone/layout/keyboard_layout_engine.h" +#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h" +#include "ui/gfx/range/range.h" +#include "ui/ozone/platform/wayland/wayland_connection.h" +#include "ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h" +#include "ui/ozone/public/ozone_switches.h" + +namespace ui { + +namespace { + +constexpr int kXkbKeycodeOffset = 8; + +} // namespace + +WaylandInputMethodContext::WaylandInputMethodContext( + WaylandConnection* connection, + LinuxInputMethodContextDelegate* delegate, + bool is_simple, + const EventDispatchCallback& callback) + : connection_(connection), + delegate_(delegate), + is_simple_(is_simple), + callback_(callback), + text_input_(nullptr) { + Init(); +} + +WaylandInputMethodContext::~WaylandInputMethodContext() { + if (text_input_) { + text_input_->Deactivate(); + text_input_->HideInputPanel(); + } +} + +void WaylandInputMethodContext::Init(bool initialize_for_testing) { + bool use_ozone_wayland_vkb = + initialize_for_testing || + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableWaylandIme); + + // If text input instance is not created then all ime context operations + // are noop. This option is because in some environments someone might not + // want to enable ime/virtual keyboard even if it's available. + if (use_ozone_wayland_vkb && !is_simple_ && !text_input_ && + connection_->text_input_manager_v1()) { + text_input_ = std::make_unique<ZWPTextInputWrapperV1>( + connection_->text_input_manager_v1()); + text_input_->Initialize(connection_, this); + } +} + +bool WaylandInputMethodContext::DispatchKeyEvent( + const ui::KeyEvent& key_event) { + return false; +} + +void WaylandInputMethodContext::Reset() { + if (text_input_) + text_input_->Reset(); +} + +void WaylandInputMethodContext::Focus() { + WaylandWindow* window = connection_->GetCurrentKeyboardFocusedWindow(); + if (!text_input_ || !window) + return; + + text_input_->Activate(window); + text_input_->ShowInputPanel(); +} + +void WaylandInputMethodContext::Blur() { + if (text_input_) { + text_input_->Deactivate(); + text_input_->HideInputPanel(); + } +} + +void WaylandInputMethodContext::SetCursorLocation(const gfx::Rect& rect) { + if (text_input_) + text_input_->SetCursorRect(rect); +} + +void WaylandInputMethodContext::SetSurroundingText( + const base::string16& text, + const gfx::Range& selection_range) { + if (text_input_) + text_input_->SetSurroundingText(text, selection_range); +} + +void WaylandInputMethodContext::OnPreeditString(const std::string& text, + int preedit_cursor) { + gfx::Range selection_range = gfx::Range::InvalidRange(); + + if (!selection_range.IsValid()) { + int cursor_pos = (preedit_cursor) ? text.length() : preedit_cursor; + selection_range.set_start(cursor_pos); + selection_range.set_end(cursor_pos); + } + + ui::CompositionText composition_text; + composition_text.text = base::UTF8ToUTF16(text); + composition_text.selection = selection_range; + delegate_->OnPreeditChanged(composition_text); +} + +void WaylandInputMethodContext::OnCommitString(const std::string& text) { + delegate_->OnCommit(base::UTF8ToUTF16(text)); +} + +void WaylandInputMethodContext::OnDeleteSurroundingText(int32_t index, + uint32_t length) { + delegate_->OnDeleteSurroundingText(index, length); +} + +void WaylandInputMethodContext::OnKeysym(uint32_t key, + uint32_t state, + uint32_t modifiers) { + uint8_t flags = 0; // for now ignore modifiers + DomKey dom_key = NonPrintableXKeySymToDomKey(key); + KeyboardCode key_code = NonPrintableDomKeyToKeyboardCode(dom_key); + DomCode dom_code = + KeycodeConverter::NativeKeycodeToDomCode(key_code + kXkbKeycodeOffset); + if (dom_code == ui::DomCode::NONE) + return; + + bool down = state == WL_KEYBOARD_KEY_STATE_PRESSED; + ui::KeyEvent event(down ? ET_KEY_PRESSED : ET_KEY_RELEASED, key_code, + dom_code, flags, dom_key, EventTimeForNow()); + callback_.Run(&event); +} + +} // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context.h b/ui/ozone/platform/wayland/wayland_input_method_context.h new file mode 100644 index 0000000..1023ecc --- /dev/null +++ b/ui/ozone/platform/wayland/wayland_input_method_context.h
@@ -0,0 +1,59 @@ +// 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 UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_H_ +#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_H_ + +#include "base/macros.h" +#include "ui/base/ime/linux/linux_input_method_context.h" +#include "ui/events/ozone/evdev/event_dispatch_callback.h" +#include "ui/ozone/platform/wayland/zwp_text_input_wrapper.h" + +namespace ui { + +class WaylandConnection; +class ZWPTextInputWrapper; + +class WaylandInputMethodContext : public LinuxInputMethodContext, + public ZWPTextInputWrapperClient { + public: + WaylandInputMethodContext(WaylandConnection* connection, + LinuxInputMethodContextDelegate* delegate, + bool is_simple, + const EventDispatchCallback& callback); + ~WaylandInputMethodContext() override; + + void Init(bool initialize_for_testing = false); + + // LinuxInputMethodContext overrides: + bool DispatchKeyEvent(const ui::KeyEvent& key_event) override; + void SetCursorLocation(const gfx::Rect& rect) override; + void SetSurroundingText(const base::string16& text, + const gfx::Range& selection_range) override; + void Reset() override; + void Focus() override; + void Blur() override; + + // ui::ZWPTextInputWrapperClient + void OnPreeditString(const std::string& text, int preedit_cursor) override; + void OnCommitString(const std::string& text) override; + void OnDeleteSurroundingText(int32_t index, uint32_t length) override; + void OnKeysym(uint32_t key, uint32_t state, uint32_t modifiers) override; + + private: + WaylandConnection* connection_ = nullptr; // TODO(jani) Handle this better + + // Delegate interface back to IME code in ui. + LinuxInputMethodContextDelegate* delegate_; + bool is_simple_; + EventDispatchCallback callback_; + + std::unique_ptr<ZWPTextInputWrapper> text_input_; + + DISALLOW_COPY_AND_ASSIGN(WaylandInputMethodContext); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_H_
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc b/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc new file mode 100644 index 0000000..1eaf6fa --- /dev/null +++ b/ui/ozone/platform/wayland/wayland_input_method_context_factory.cc
@@ -0,0 +1,39 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/ozone/platform/wayland/wayland_input_method_context_factory.h" + +#include "ui/ozone/platform/wayland/wayland_connection.h" +#include "ui/ozone/platform/wayland/wayland_input_method_context.h" + +namespace ui { + +WaylandInputMethodContextFactory::WaylandInputMethodContextFactory( + WaylandConnection* connection) + : connection_(connection) { + LinuxInputMethodContextFactory::SetInstance(this); +} + +WaylandInputMethodContextFactory::~WaylandInputMethodContextFactory() { + LinuxInputMethodContextFactory::SetInstance(nullptr); +} + +std::unique_ptr<LinuxInputMethodContext> +WaylandInputMethodContextFactory::CreateInputMethodContext( + LinuxInputMethodContextDelegate* delegate, + bool is_simple) const { + return CreateWaylandInputMethodContext(delegate, is_simple); +} + +std::unique_ptr<WaylandInputMethodContext> +WaylandInputMethodContextFactory::CreateWaylandInputMethodContext( + ui::LinuxInputMethodContextDelegate* delegate, + bool is_simple) const { + return std::make_unique<WaylandInputMethodContext>( + connection_, delegate, is_simple, + base::BindRepeating(&WaylandConnection::DispatchUiEvent, + base::Unretained(connection_))); +} + +} // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_factory.h b/ui/ozone/platform/wayland/wayland_input_method_context_factory.h new file mode 100644 index 0000000..413f3a4 --- /dev/null +++ b/ui/ozone/platform/wayland/wayland_input_method_context_factory.h
@@ -0,0 +1,38 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_ +#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_ + +#include "base/macros.h" +#include "ui/base/ime/linux/linux_input_method_context_factory.h" + +namespace ui { + +class WaylandConnection; +class WaylandInputMethodContext; + +class WaylandInputMethodContextFactory : public LinuxInputMethodContextFactory { + public: + explicit WaylandInputMethodContextFactory(WaylandConnection* connection); + ~WaylandInputMethodContextFactory() override; + + std::unique_ptr<LinuxInputMethodContext> CreateInputMethodContext( + ui::LinuxInputMethodContextDelegate* delegate, + bool is_simple) const override; + + // Exposed for unit tests but also called by CreateInputMethodContext + std::unique_ptr<WaylandInputMethodContext> CreateWaylandInputMethodContext( + ui::LinuxInputMethodContextDelegate* delegate, + bool is_simple) const; + + private: + WaylandConnection* connection_; + + DISALLOW_COPY_AND_ASSIGN(WaylandInputMethodContextFactory); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_INPUT_METHOD_CONTEXT_FACTORY_H_
diff --git a/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc b/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc new file mode 100644 index 0000000..666910c --- /dev/null +++ b/ui/ozone/platform/wayland/wayland_input_method_context_unittest.cc
@@ -0,0 +1,140 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <text-input-unstable-v1-server-protocol.h> +#include <wayland-server.h> + +#include "mojo/public/cpp/bindings/binding.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/ime/linux/linux_input_method_context.h" +#include "ui/events/event.h" +#include "ui/ozone/platform/wayland/fake_server.h" +#include "ui/ozone/platform/wayland/wayland_input_method_context.h" +#include "ui/ozone/platform/wayland/wayland_input_method_context_factory.h" +#include "ui/ozone/platform/wayland/wayland_test.h" +#include "ui/ozone/platform/wayland/wayland_window.h" + +using ::testing::SaveArg; +using ::testing::_; + +namespace ui { + +class TestInputMethodContextDelegate : public LinuxInputMethodContextDelegate { + public: + TestInputMethodContextDelegate() {} + ~TestInputMethodContextDelegate() override {} + + void OnCommit(const base::string16& text) override { + was_on_commit_called_ = true; + } + void OnPreeditChanged(const ui::CompositionText& composition_text) override { + was_on_preedit_changed_called_ = true; + } + void OnPreeditEnd() override {} + void OnPreeditStart() override {} + void OnDeleteSurroundingText(int32_t index, uint32_t length) override{}; + + bool was_on_commit_called() { return was_on_commit_called_; } + + bool was_on_preedit_changed_called() { + return was_on_preedit_changed_called_; + } + + private: + bool was_on_commit_called_ = false; + bool was_on_preedit_changed_called_ = false; + + DISALLOW_COPY_AND_ASSIGN(TestInputMethodContextDelegate); +}; + +class WaylandInputMethodContextTest : public WaylandTest { + public: + WaylandInputMethodContextTest() {} + + void SetUp() override { + WaylandTest::SetUp(); + + Sync(); + + input_method_context_delegate_ = + std::make_unique<TestInputMethodContextDelegate>(); + + WaylandInputMethodContextFactory factory(connection_.get()); + input_method_context_ = factory.CreateWaylandInputMethodContext( + input_method_context_delegate_.get(), false); + input_method_context_->Init(true); + connection_->ScheduleFlush(); + + Sync(); + + zwp_text_input_ = server_.text_input_manager_v1()->text_input.get(); + window_->set_keyboard_focus(true); + + ASSERT_TRUE(connection_->text_input_manager_v1()); + ASSERT_TRUE(zwp_text_input_); + } + + protected: + std::unique_ptr<TestInputMethodContextDelegate> + input_method_context_delegate_; + std::unique_ptr<WaylandInputMethodContext> input_method_context_; + wl::MockZwpTextInput* zwp_text_input_ = nullptr; + + private: + DISALLOW_COPY_AND_ASSIGN(WaylandInputMethodContextTest); +}; + +TEST_P(WaylandInputMethodContextTest, Focus) { + EXPECT_CALL(*zwp_text_input_, Activate(surface_->resource())); + EXPECT_CALL(*zwp_text_input_, ShowInputPanel()); + input_method_context_->Focus(); + connection_->ScheduleFlush(); + Sync(); +} + +TEST_P(WaylandInputMethodContextTest, Blur) { + EXPECT_CALL(*zwp_text_input_, Deactivate()); + EXPECT_CALL(*zwp_text_input_, HideInputPanel()); + input_method_context_->Blur(); + connection_->ScheduleFlush(); + Sync(); +} + +TEST_P(WaylandInputMethodContextTest, Reset) { + EXPECT_CALL(*zwp_text_input_, Reset()); + input_method_context_->Reset(); + connection_->ScheduleFlush(); + Sync(); +} + +TEST_P(WaylandInputMethodContextTest, SetCursorLocation) { + EXPECT_CALL(*zwp_text_input_, SetCursorRect(50, 0, 1, 1)); + input_method_context_->SetCursorLocation(gfx::Rect(50, 0, 1, 1)); + connection_->ScheduleFlush(); + Sync(); +} + +TEST_P(WaylandInputMethodContextTest, OnPreeditChanged) { + zwp_text_input_v1_send_preedit_string(zwp_text_input_->resource(), 0, + "PreeditString", ""); + Sync(); + EXPECT_TRUE(input_method_context_delegate_->was_on_preedit_changed_called()); +} + +TEST_P(WaylandInputMethodContextTest, OnCommit) { + zwp_text_input_v1_send_commit_string(zwp_text_input_->resource(), 0, + "CommitString"); + Sync(); + EXPECT_TRUE(input_method_context_delegate_->was_on_commit_called()); +} + +INSTANTIATE_TEST_CASE_P(XdgVersionV5Test, + WaylandInputMethodContextTest, + ::testing::Values(kXdgShellV5)); +INSTANTIATE_TEST_CASE_P(XdgVersionV6Test, + WaylandInputMethodContextTest, + ::testing::Values(kXdgShellV6)); + +} // namespace ui
diff --git a/ui/ozone/platform/wayland/wayland_object.cc b/ui/ozone/platform/wayland/wayland_object.cc index c3cbb08..ed4de39 100644 --- a/ui/ozone/platform/wayland/wayland_object.cc +++ b/ui/ozone/platform/wayland/wayland_object.cc
@@ -6,6 +6,7 @@ #include <linux-dmabuf-unstable-v1-client-protocol.h> #include <presentation-time-client-protocol.h> +#include <text-input-unstable-v1-client-protocol.h> #include <wayland-client.h> #include <xdg-shell-unstable-v5-client-protocol.h> #include <xdg-shell-unstable-v6-client-protocol.h> @@ -177,4 +178,14 @@ void (*ObjectTraits<zxdg_positioner_v6>::deleter)(zxdg_positioner_v6*) = &zxdg_positioner_v6_destroy; +const wl_interface* ObjectTraits<zwp_text_input_manager_v1>::interface = + &zwp_text_input_manager_v1_interface; +void (*ObjectTraits<zwp_text_input_manager_v1>::deleter)( + zwp_text_input_manager_v1*) = &zwp_text_input_manager_v1_destroy; + +const wl_interface* ObjectTraits<zwp_text_input_v1>::interface = + &zwp_text_input_v1_interface; +void (*ObjectTraits<zwp_text_input_v1>::deleter)(zwp_text_input_v1*) = + &zwp_text_input_v1_destroy; + } // namespace wl
diff --git a/ui/ozone/platform/wayland/wayland_object.h b/ui/ozone/platform/wayland/wayland_object.h index 62890452..34984d3 100644 --- a/ui/ozone/platform/wayland/wayland_object.h +++ b/ui/ozone/platform/wayland/wayland_object.h
@@ -38,6 +38,8 @@ struct zxdg_toplevel_v6; struct zxdg_popup_v6; struct zxdg_positioner_v6; +struct zwp_text_input_manager_v1; +struct zwp_text_input_v1; namespace wl { @@ -224,6 +226,18 @@ static void (*deleter)(zxdg_positioner_v6*); }; +template <> +struct ObjectTraits<zwp_text_input_manager_v1> { + static const wl_interface* interface; + static void (*deleter)(zwp_text_input_manager_v1*); +}; + +template <> +struct ObjectTraits<zwp_text_input_v1> { + static const wl_interface* interface; + static void (*deleter)(zwp_text_input_v1*); +}; + struct Deleter { template <typename T> void operator()(T* obj) {
diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/wayland_window.cc index 9b251587..cb5e40b 100644 --- a/ui/ozone/platform/wayland/wayland_window.cc +++ b/ui/ozone/platform/wayland/wayland_window.cc
@@ -197,6 +197,9 @@ } void WaylandWindow::Show() { + if (!is_tooltip_) // Tooltip windows should not get keyboard focus + set_keyboard_focus(true); + if (xdg_surface_) return; if (is_tooltip_) {
diff --git a/ui/ozone/platform/wayland/wayland_window.h b/ui/ozone/platform/wayland/wayland_window.h index 4cd69ff..4148648 100644 --- a/ui/ozone/platform/wayland/wayland_window.h +++ b/ui/ozone/platform/wayland/wayland_window.h
@@ -57,6 +57,8 @@ // Set whether this window has keyboard focus and should dispatch key events. void set_keyboard_focus(bool focus) { has_keyboard_focus_ = focus; } + bool has_keyboard_focus() const { return has_keyboard_focus_; } + // Set whether this window has touch focus and should dispatch touch events. void set_touch_focus(bool focus) { has_touch_focus_ = focus; }
diff --git a/ui/ozone/platform/wayland/zwp_text_input_wrapper.h b/ui/ozone/platform/wayland/zwp_text_input_wrapper.h new file mode 100644 index 0000000..8b11a95b7 --- /dev/null +++ b/ui/ozone/platform/wayland/zwp_text_input_wrapper.h
@@ -0,0 +1,74 @@ +// 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 UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_H_ +#define UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_H_ + +#include "ui/ozone/platform/wayland/wayland_object.h" + +#include "base/strings/string16.h" + +namespace gfx { +class Rect; +class Range; +} // namespace gfx + +namespace ui { + +class WaylandConnection; +class WaylandWindow; + +// Client interface which handles wayland text input callbacks +class ZWPTextInputWrapperClient { + public: + virtual ~ZWPTextInputWrapperClient() {} + + // Called when a new composing text (pre-edit) should be set around the + // current cursor position. Any previously set composing text should + // be removed. + virtual void OnPreeditString(const std::string& text, + int32_t preedit_cursor) = 0; + + // Called when a complete input sequence has been entered. The text to + // commit could be either just a single character after a key press or the + // result of some composing (pre-edit). + virtual void OnCommitString(const std::string& text) = 0; + + // Called when client needs to delete all or part of the text surrounding + // the cursor + virtual void OnDeleteSurroundingText(int32_t index, uint32_t length) = 0; + + // Notify when a key event was sent. Key events should not be used + // for normal text input operations, which should be done with + // commit_string, delete_surrounding_text, etc. + virtual void OnKeysym(uint32_t key, uint32_t state, uint32_t modifiers) = 0; +}; + +// A wrapper around different versions of wayland text input protocols. +// Wayland compositors support various different text input protocols which +// all from Chromium point of view provide the functionality needed by Chromium +// IME. This interface collects the functionality behind one wrapper API. +class ZWPTextInputWrapper { + public: + virtual ~ZWPTextInputWrapper() {} + + virtual void Initialize(WaylandConnection* connection, + ZWPTextInputWrapperClient* client) = 0; + + virtual void Reset() = 0; + + virtual void Activate(WaylandWindow* window) = 0; + virtual void Deactivate() = 0; + + virtual void ShowInputPanel() = 0; + virtual void HideInputPanel() = 0; + + virtual void SetCursorRect(const gfx::Rect& rect) = 0; + virtual void SetSurroundingText(const base::string16& text, + const gfx::Range& selection_range) = 0; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_H_
diff --git a/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.cc b/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.cc new file mode 100644 index 0000000..4a12ace --- /dev/null +++ b/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.cc
@@ -0,0 +1,197 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h" + +#include "base/memory/ptr_util.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/gfx/range/range.h" +#include "ui/ozone/platform/wayland/wayland_connection.h" +#include "ui/ozone/platform/wayland/wayland_window.h" + +namespace ui { + +ZWPTextInputWrapperV1::ZWPTextInputWrapperV1( + zwp_text_input_manager_v1* text_input_manager) + : client_(nullptr) { + static const zwp_text_input_v1_listener text_input_listener = { + &ZWPTextInputWrapperV1::OnEnter, // text_input_enter, + &ZWPTextInputWrapperV1::OnLeave, // text_input_leave, + &ZWPTextInputWrapperV1::OnModifiersMap, // text_input_modifiers_map, + &ZWPTextInputWrapperV1:: + OnInputPanelState, // text_input_input_panel_state, + &ZWPTextInputWrapperV1::OnPreeditString, // text_input_preedit_string, + &ZWPTextInputWrapperV1::OnPreeditStyling, // text_input_preedit_styling, + &ZWPTextInputWrapperV1::OnPreeditCursor, // text_input_preedit_cursor, + &ZWPTextInputWrapperV1::OnCommitString, // text_input_commit_string, + &ZWPTextInputWrapperV1::OnCursorPosition, // text_input_cursor_position, + &ZWPTextInputWrapperV1:: + OnDeleteSurroundingText, // text_input_delete_surrounding_text, + &ZWPTextInputWrapperV1::OnKeysym, // text_input_keysym, + &ZWPTextInputWrapperV1::OnLanguage, // text_input_language, + &ZWPTextInputWrapperV1::OnTextDirection, // text_input_text_direction + }; + ResetInputEventState(); + + zwp_text_input_v1* text_input = + zwp_text_input_manager_v1_create_text_input(text_input_manager); + obj_ = wl::Object<zwp_text_input_v1>(text_input); + + zwp_text_input_v1_add_listener(text_input, &text_input_listener, this); +} + +ZWPTextInputWrapperV1::~ZWPTextInputWrapperV1() {} + +void ZWPTextInputWrapperV1::Initialize(WaylandConnection* connection, + ZWPTextInputWrapperClient* client) { + connection_ = connection; + client_ = client; +} + +void ZWPTextInputWrapperV1::Reset() { + ResetInputEventState(); + zwp_text_input_v1_reset(obj_.get()); +} + +void ZWPTextInputWrapperV1::Activate(WaylandWindow* window) { + zwp_text_input_v1_activate(obj_.get(), connection_->seat(), + window->surface()); +} + +void ZWPTextInputWrapperV1::Deactivate() { + zwp_text_input_v1_deactivate(obj_.get(), connection_->seat()); +} + +void ZWPTextInputWrapperV1::ShowInputPanel() { + zwp_text_input_v1_show_input_panel(obj_.get()); +} + +void ZWPTextInputWrapperV1::HideInputPanel() { + zwp_text_input_v1_hide_input_panel(obj_.get()); +} + +void ZWPTextInputWrapperV1::SetCursorRect(const gfx::Rect& rect) { + zwp_text_input_v1_set_cursor_rectangle(obj_.get(), rect.x(), rect.y(), + rect.width(), rect.height()); +} + +void ZWPTextInputWrapperV1::SetSurroundingText( + const base::string16& text, + const gfx::Range& selection_range) { + const std::string text_utf8 = base::UTF16ToUTF8(text); + zwp_text_input_v1_set_surrounding_text(obj_.get(), text_utf8.c_str(), + selection_range.start(), + selection_range.end()); +} + +void ZWPTextInputWrapperV1::ResetInputEventState() { + preedit_cursor_ = -1; +} + +void ZWPTextInputWrapperV1::OnEnter(void* data, + struct zwp_text_input_v1* text_input, + struct wl_surface* surface) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void ZWPTextInputWrapperV1::OnLeave(void* data, + struct zwp_text_input_v1* text_input) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void ZWPTextInputWrapperV1::OnModifiersMap(void* data, + struct zwp_text_input_v1* text_input, + struct wl_array* map) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void ZWPTextInputWrapperV1::OnInputPanelState( + void* data, + struct zwp_text_input_v1* text_input, + uint32_t state) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void ZWPTextInputWrapperV1::OnPreeditString( + void* data, + struct zwp_text_input_v1* text_input, + uint32_t serial, + const char* text, + const char* commit) { + ZWPTextInputWrapperV1* wti = static_cast<ZWPTextInputWrapperV1*>(data); + wti->ResetInputEventState(); + wti->client_->OnPreeditString(std::string(text), wti->preedit_cursor_); +} + +void ZWPTextInputWrapperV1::OnPreeditStyling( + void* data, + struct zwp_text_input_v1* text_input, + uint32_t index, + uint32_t length, + uint32_t style) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void ZWPTextInputWrapperV1::OnPreeditCursor( + void* data, + struct zwp_text_input_v1* text_input, + int32_t index) { + ZWPTextInputWrapperV1* wti = static_cast<ZWPTextInputWrapperV1*>(data); + wti->preedit_cursor_ = index; +} + +void ZWPTextInputWrapperV1::OnCommitString(void* data, + struct zwp_text_input_v1* text_input, + uint32_t serial, + const char* text) { + ZWPTextInputWrapperV1* wti = static_cast<ZWPTextInputWrapperV1*>(data); + wti->ResetInputEventState(); + wti->client_->OnCommitString(std::string(text)); +} + +void ZWPTextInputWrapperV1::OnCursorPosition( + void* data, + struct zwp_text_input_v1* text_input, + int32_t index, + int32_t anchor) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void ZWPTextInputWrapperV1::OnDeleteSurroundingText( + void* data, + struct zwp_text_input_v1* text_input, + int32_t index, + uint32_t length) { + ZWPTextInputWrapperV1* wti = static_cast<ZWPTextInputWrapperV1*>(data); + wti->client_->OnDeleteSurroundingText(index, length); +} + +void ZWPTextInputWrapperV1::OnKeysym(void* data, + struct zwp_text_input_v1* text_input, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state, + uint32_t modifiers) { + ZWPTextInputWrapperV1* wti = static_cast<ZWPTextInputWrapperV1*>(data); + wti->client_->OnKeysym(key, state, modifiers); +} + +void ZWPTextInputWrapperV1::OnLanguage(void* data, + struct zwp_text_input_v1* text_input, + uint32_t serial, + const char* language) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +void ZWPTextInputWrapperV1::OnTextDirection( + void* data, + struct zwp_text_input_v1* text_input, + uint32_t serial, + uint32_t direction) { + NOTIMPLEMENTED_LOG_ONCE(); +} + +} // namespace ui
diff --git a/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h b/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h new file mode 100644 index 0000000..62cfaa6 --- /dev/null +++ b/ui/ozone/platform/wayland/zwp_text_input_wrapper_v1.h
@@ -0,0 +1,106 @@ +// 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 UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_V1_H_ +#define UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_V1_H_ + +#include <text-input-unstable-v1-client-protocol.h> +#include <string> + +#include "ui/ozone/platform/wayland/zwp_text_input_wrapper.h" + +namespace gfx { +class Rect; +} + +namespace ui { + +class WaylandConnection; +class WaylandWindow; + +class ZWPTextInputWrapperV1 : public ZWPTextInputWrapper { + public: + explicit ZWPTextInputWrapperV1(zwp_text_input_manager_v1* text_input_manager); + ~ZWPTextInputWrapperV1() override; + + void Initialize(WaylandConnection* connection, + ZWPTextInputWrapperClient* client) override; + + void Reset() override; + + void Activate(WaylandWindow* window) override; + void Deactivate() override; + + void ShowInputPanel() override; + void HideInputPanel() override; + + void SetCursorRect(const gfx::Rect& rect) override; + void SetSurroundingText(const base::string16& text, + const gfx::Range& selection_range) override; + + private: + void ResetInputEventState(); + + // zwp_text_input_v1_listener + static void OnEnter(void* data, + struct zwp_text_input_v1* text_input, + struct wl_surface* surface); + static void OnLeave(void* data, struct zwp_text_input_v1* text_input); + static void OnModifiersMap(void* data, + struct zwp_text_input_v1* text_input, + struct wl_array* map); + static void OnInputPanelState(void* data, + struct zwp_text_input_v1* text_input, + uint32_t state); + static void OnPreeditString(void* data, + struct zwp_text_input_v1* text_input, + uint32_t serial, + const char* text, + const char* commit); + static void OnPreeditStyling(void* data, + struct zwp_text_input_v1* text_input, + uint32_t index, + uint32_t length, + uint32_t style); + static void OnPreeditCursor(void* data, + struct zwp_text_input_v1* text_input, + int32_t index); + static void OnCommitString(void* data, + struct zwp_text_input_v1* text_input, + uint32_t serial, + const char* text); + static void OnCursorPosition(void* data, + struct zwp_text_input_v1* text_input, + int32_t index, + int32_t anchor); + static void OnDeleteSurroundingText(void* data, + struct zwp_text_input_v1* text_input, + int32_t index, + uint32_t length); + static void OnKeysym(void* data, + struct zwp_text_input_v1* text_input, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state, + uint32_t modifiers); + static void OnLanguage(void* data, + struct zwp_text_input_v1* text_input, + uint32_t serial, + const char* language); + static void OnTextDirection(void* data, + struct zwp_text_input_v1* text_input, + uint32_t serial, + uint32_t direction); + + WaylandConnection* connection_ = nullptr; + wl::Object<zwp_text_input_v1> obj_; + ZWPTextInputWrapperClient* client_; + + int32_t preedit_cursor_; +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_WAYLAND_ZWP_TEXT_INPUT_WRAPPER_V1_H_
diff --git a/ui/ozone/public/ozone_switches.cc b/ui/ozone/public/ozone_switches.cc index 0a9b3ab32..7bec0b7e 100644 --- a/ui/ozone/public/ozone_switches.cc +++ b/ui/ozone/public/ozone_switches.cc
@@ -12,4 +12,7 @@ // Specify location for image dumps. const char kOzoneDumpFile[] = "ozone-dump-file"; +// Try to enable wayland input method editor. +const char kEnableWaylandIme[] = "enable-wayland-ime"; + } // namespace switches
diff --git a/ui/ozone/public/ozone_switches.h b/ui/ozone/public/ozone_switches.h index b062e67..d7e7d8a 100644 --- a/ui/ozone/public/ozone_switches.h +++ b/ui/ozone/public/ozone_switches.h
@@ -14,6 +14,8 @@ OZONE_BASE_EXPORT extern const char kOzoneDumpFile[]; +OZONE_BASE_EXPORT extern const char kEnableWaylandIme[]; + } // namespace switches #endif // UI_OZONE_PUBLIC_OZONE_SWITCHES_H_
diff --git a/ui/views/accessibility/ax_aura_obj_cache.cc b/ui/views/accessibility/ax_aura_obj_cache.cc index 9fffbd6..5811bf2 100644 --- a/ui/views/accessibility/ax_aura_obj_cache.cc +++ b/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -31,6 +31,7 @@ } AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(View* view) { + // Avoid problems with transient focus events. https://crbug.com/729449 if (!view->GetWidget()) return nullptr; return CreateInternal<AXViewObjWrapper>(view, view_to_id_map_);
diff --git a/ui/views/accessibility/ax_aura_obj_cache.h b/ui/views/accessibility/ax_aura_obj_cache.h index 83f3155..3a4a448 100644 --- a/ui/views/accessibility/ax_aura_obj_cache.h +++ b/ui/views/accessibility/ax_aura_obj_cache.h
@@ -45,8 +45,11 @@ ax::mojom::Event event_type) = 0; }; - // Get or create an entry in the cache based on an Aura view. + // Get or create an entry in the cache. May return null if the View is not + // associated with a Widget. AXAuraObjWrapper* GetOrCreate(View* view); + + // Get or create an entry in the cache. AXAuraObjWrapper* GetOrCreate(Widget* widget); AXAuraObjWrapper* GetOrCreate(aura::Window* window);
diff --git a/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc b/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc index 84b893f..2e78f27 100644 --- a/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc +++ b/ui/views/accessibility/ax_system_caret_win_interactive_uitest.cc
@@ -21,6 +21,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" #include "ui/gl/test/gl_surface_test_support.h" +#include "ui/views/controls/button/label_button.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/controls/textfield/textfield_test_api.h" #include "ui/views/test/widget_test.h" @@ -74,6 +75,132 @@ DISALLOW_COPY_AND_ASSIGN(AXSystemCaretWinTest); }; +class WinAccessibilityCaretEventMonitor { + public: + WinAccessibilityCaretEventMonitor(UINT event_min, UINT event_max); + ~WinAccessibilityCaretEventMonitor(); + + // Blocks until the next event is received. When it's received, it + // queries accessibility information about the object that fired the + // event and populates the event, hwnd, role, state, and name in the + // passed arguments. + void WaitForNextEvent(DWORD* out_event, UINT* out_role, UINT* out_state); + + private: + void OnWinEventHook(HWINEVENTHOOK handle, + DWORD event, + HWND hwnd, + LONG obj_id, + LONG child_id, + DWORD event_thread, + DWORD event_time); + + static void CALLBACK WinEventHookThunk(HWINEVENTHOOK handle, + DWORD event, + HWND hwnd, + LONG obj_id, + LONG child_id, + DWORD event_thread, + DWORD event_time); + + struct EventInfo { + DWORD event; + HWND hwnd; + LONG obj_id; + LONG child_id; + }; + + base::circular_deque<EventInfo> event_queue_; + base::RunLoop loop_runner_; + HWINEVENTHOOK win_event_hook_handle_; + static WinAccessibilityCaretEventMonitor* instance_; + + DISALLOW_COPY_AND_ASSIGN(WinAccessibilityCaretEventMonitor); +}; + +// static +WinAccessibilityCaretEventMonitor* + WinAccessibilityCaretEventMonitor::instance_ = NULL; + +WinAccessibilityCaretEventMonitor::WinAccessibilityCaretEventMonitor( + UINT event_min, + UINT event_max) { + CHECK(!instance_) << "There can be only one instance of" + << " WinAccessibilityCaretEventMonitor at a time."; + instance_ = this; + win_event_hook_handle_ = + SetWinEventHook(event_min, event_max, NULL, + &WinAccessibilityCaretEventMonitor::WinEventHookThunk, + GetCurrentProcessId(), + 0, // Hook all threads + WINEVENT_OUTOFCONTEXT); +} + +WinAccessibilityCaretEventMonitor::~WinAccessibilityCaretEventMonitor() { + UnhookWinEvent(win_event_hook_handle_); + instance_ = NULL; +} + +void WinAccessibilityCaretEventMonitor::WaitForNextEvent(DWORD* out_event, + UINT* out_role, + UINT* out_state) { + if (event_queue_.empty()) + loop_runner_.Run(); + + EventInfo event_info = event_queue_.front(); + event_queue_.pop_front(); + + *out_event = event_info.event; + + Microsoft::WRL::ComPtr<IAccessible> acc_obj; + base::win::ScopedVariant child_variant; + CHECK(S_OK == AccessibleObjectFromEvent( + event_info.hwnd, event_info.obj_id, event_info.child_id, + acc_obj.GetAddressOf(), child_variant.Receive())); + + base::win::ScopedVariant role_variant; + if (S_OK == acc_obj->get_accRole(child_variant, role_variant.Receive())) + *out_role = V_I4(role_variant.ptr()); + else + *out_role = 0; + + base::win::ScopedVariant state_variant; + if (S_OK == acc_obj->get_accState(child_variant, state_variant.Receive())) + *out_state = V_I4(state_variant.ptr()); + else + *out_state = 0; +} + +void WinAccessibilityCaretEventMonitor::OnWinEventHook(HWINEVENTHOOK handle, + DWORD event, + HWND hwnd, + LONG obj_id, + LONG child_id, + DWORD event_thread, + DWORD event_time) { + EventInfo event_info; + event_info.event = event; + event_info.hwnd = hwnd; + event_info.obj_id = obj_id; + event_info.child_id = child_id; + event_queue_.push_back(event_info); + loop_runner_.Quit(); +} + +// static +void CALLBACK +WinAccessibilityCaretEventMonitor::WinEventHookThunk(HWINEVENTHOOK handle, + DWORD event, + HWND hwnd, + LONG obj_id, + LONG child_id, + DWORD event_thread, + DWORD event_time) { + if (instance_ && obj_id == OBJID_CARET) { + instance_->OnWinEventHook(handle, event, hwnd, obj_id, child_id, + event_thread, event_time); + } +} } // namespace TEST_F(AXSystemCaretWinTest, DISABLED_TestOnCaretBoundsChangeInTextField) { @@ -183,4 +310,81 @@ EXPECT_EQ(height, height3); } +TEST_F(AXSystemCaretWinTest, TestCaretMSAAEvents) { + TextfieldTestApi textfield_test_api(textfield_); + Microsoft::WRL::ComPtr<IAccessible> caret_accessible; + gfx::NativeWindow native_window = widget_->GetNativeWindow(); + ASSERT_NE(nullptr, native_window); + HWND hwnd = native_window->GetHost()->GetAcceleratedWidget(); + EXPECT_HRESULT_SUCCEEDED(AccessibleObjectFromWindow( + hwnd, static_cast<DWORD>(OBJID_CARET), IID_IAccessible, + reinterpret_cast<void**>(caret_accessible.GetAddressOf()))); + + DWORD event; + UINT role; + UINT state; + + { + // Set caret to start of textfield. + WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW, + EVENT_OBJECT_LOCATIONCHANGE); + textfield_test_api.ExecuteTextEditCommand( + ui::TextEditCommand::MOVE_TO_BEGINNING_OF_DOCUMENT); + monitor.WaitForNextEvent(&event, &role, &state); + ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_LOCATIONCHANGE)) + << "Event should be EVENT_OBJECT_LOCATIONCHANGE"; + ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET)) + << "Role should be ROLE_SYSTEM_CARET"; + ASSERT_EQ(state, static_cast<UINT>(0)) << "State should be 0"; + } + + { + // Set caret to end of textfield. + WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW, + EVENT_OBJECT_LOCATIONCHANGE); + textfield_test_api.ExecuteTextEditCommand( + ui::TextEditCommand::MOVE_TO_END_OF_DOCUMENT); + monitor.WaitForNextEvent(&event, &role, &state); + ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_LOCATIONCHANGE)) + << "Event should be EVENT_OBJECT_LOCATIONCHANGE"; + ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET)) + << "Role should be ROLE_SYSTEM_CARET"; + ASSERT_EQ(state, static_cast<UINT>(0)) << "State should be 0"; + } + + { + // Move focus to a button. + LabelButton button(nullptr, base::string16()); + button.SetBounds(500, 0, 200, 20); + widget_->GetRootView()->AddChildView(&button); + test::WidgetActivationWaiter waiter(widget_, true); + WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW, + EVENT_OBJECT_LOCATIONCHANGE); + widget_->Show(); + waiter.Wait(); + button.SetFocusBehavior(View::FocusBehavior::ALWAYS); + button.RequestFocus(); + monitor.WaitForNextEvent(&event, &role, &state); + ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_HIDE)) + << "Event should be EVENT_OBJECT_HIDE"; + ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET)) + << "Role should be ROLE_SYSTEM_CARET"; + ASSERT_EQ(state, static_cast<UINT>(STATE_SYSTEM_INVISIBLE)) + << "State should be STATE_SYSTEM_INVISIBLE"; + } + + { + // Move focus back to the text field. + WinAccessibilityCaretEventMonitor monitor(EVENT_OBJECT_SHOW, + EVENT_OBJECT_LOCATIONCHANGE); + textfield_->RequestFocus(); + monitor.WaitForNextEvent(&event, &role, &state); + ASSERT_EQ(event, static_cast<DWORD>(EVENT_OBJECT_SHOW)) + << "Event should be EVENT_OBJECT_SHOW"; + ASSERT_EQ(role, static_cast<UINT>(ROLE_SYSTEM_CARET)) + << "Role should be ROLE_SYSTEM_CARET"; + ASSERT_EQ(state, static_cast<UINT>(0)) << "State should be 0"; + } +} + } // namespace views
diff --git a/ui/views/cocoa/bridge_factory_impl.mm b/ui/views/cocoa/bridge_factory_impl.mm index 5861321..f909e24 100644 --- a/ui/views/cocoa/bridge_factory_impl.mm +++ b/ui/views/cocoa/bridge_factory_impl.mm
@@ -40,6 +40,10 @@ *found_word = false; } double SheetPositionY() override { return 0; } + views_bridge_mac::DragDropClient* GetDragDropClient() override { + // Drag-drop only doesn't work across mojo yet. + return nullptr; + } mojom::BridgedNativeWidgetHostPtr host_ptr_; std::unique_ptr<BridgedNativeWidgetImpl> bridge_impl_;
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm index bf1a9c71..89b149b 100644 --- a/ui/views/cocoa/bridged_content_view.mm +++ b/ui/views/cocoa/bridged_content_view.mm
@@ -252,7 +252,7 @@ - (void)insertTextInternal:(id)text; // Returns the native Widget's drag drop client. Possibly null. -- (views::DragDropClientMac*)dragDropClient; +- (views_bridge_mac::DragDropClient*)dragDropClient; // Menu action handlers. - (void)undo:(id)sender; @@ -621,7 +621,7 @@ } } -- (views::DragDropClientMac*)dragDropClient { +- (views_bridge_mac::DragDropClient*)dragDropClient { return bridge_ ? bridge_->drag_drop_client() : nullptr; } @@ -769,18 +769,18 @@ } - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { - views::DragDropClientMac* client = [self dragDropClient]; + views_bridge_mac::DragDropClient* client = [self dragDropClient]; return client ? client->DragUpdate(sender) : ui::DragDropTypes::DRAG_NONE; } - (void)draggingExited:(id<NSDraggingInfo>)sender { - views::DragDropClientMac* client = [self dragDropClient]; + views_bridge_mac::DragDropClient* client = [self dragDropClient]; if (client) client->DragExit(); } - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { - views::DragDropClientMac* client = [self dragDropClient]; + views_bridge_mac::DragDropClient* client = [self dragDropClient]; return client && client->Drop(sender) != NSDragOperationNone; } @@ -1541,7 +1541,7 @@ - (void)draggingSession:(NSDraggingSession*)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation { - views::DragDropClientMac* client = [self dragDropClient]; + views_bridge_mac::DragDropClient* client = [self dragDropClient]; if (client) client->EndDrag(); }
diff --git a/ui/views/cocoa/bridged_native_widget.h b/ui/views/cocoa/bridged_native_widget.h index 20c93f6..bcee3c0 100644 --- a/ui/views/cocoa/bridged_native_widget.h +++ b/ui/views/cocoa/bridged_native_widget.h
@@ -19,7 +19,6 @@ #include "ui/base/ime/text_input_client.h" #include "ui/display/display_observer.h" #import "ui/views/cocoa/bridged_native_widget_owner.h" -#import "ui/views/focus/focus_manager.h" #include "ui/views/views_export.h" #include "ui/views/widget/widget.h" #import "ui/views_bridge_mac/cocoa_mouse_capture_delegate.h" @@ -36,8 +35,9 @@ class BridgedNativeWidgetHost; } // namespace mojom -class CocoaMouseCapture; class BridgedNativeWidgetHostHelper; +class CocoaMouseCapture; +class DragDropClient; } // namespace views_bridge_mac @@ -47,8 +47,6 @@ } class CocoaWindowMoveLoop; -class DragDropClientMac; -class View; using views_bridge_mac::mojom::BridgedNativeWidgetHost; using views_bridge_mac::BridgedNativeWidgetHostHelper; @@ -94,12 +92,6 @@ // this way. void SetWindow(base::scoped_nsobject<NativeWidgetMacNSWindow> window); - // Create the drag drop client for this widget. - // TODO(ccameron): This function takes a views::View (and is not rolled into - // CreateContentView) because drag-drop has not been routed through |host_| - // yet. - void CreateDragDropClient(views::View* view); - // Set the parent NSView for the widget. // TODO(ccameron): Like SetWindow, this will need to pass a handle instead of // an NSView across processes. @@ -170,7 +162,7 @@ BridgedNativeWidgetHostHelper* host_helper() { return host_helper_; } NSWindow* ns_window(); - DragDropClientMac* drag_drop_client() { return drag_drop_client_.get(); } + views_bridge_mac::DragDropClient* drag_drop_client(); bool is_translucent_window() const { return is_translucent_window_; } // The parent widget specified in Widget::InitParams::parent. If non-null, the @@ -267,9 +259,6 @@ // Notify descendants of a visibility change. void NotifyVisibilityChangeDown(); - // Installs the NSView for hosting the composited layer. - void AddCompositorSuperview(); - // Query the display properties of the monitor that |window_| is on, and // forward them to |host_|. void UpdateWindowDisplay(); @@ -304,7 +293,6 @@ base::scoped_nsobject<ModalShowAnimationWithLayer> show_animation_; std::unique_ptr<CocoaMouseCapture> mouse_capture_; std::unique_ptr<CocoaWindowMoveLoop> window_move_loop_; - std::unique_ptr<DragDropClientMac> drag_drop_client_; ui::ModalType modal_type_ = ui::MODAL_TYPE_NONE; bool is_translucent_window_ = false; bool widget_is_top_level_ = false; @@ -321,7 +309,6 @@ // |content_dip_size_|, which is the frame size most recently *sent to* the // compositor. gfx::Size compositor_frame_dip_size_; - base::scoped_nsobject<NSView> compositor_superview_; std::unique_ptr<ui::DisplayCALayerTree> display_ca_layer_tree_; // Tracks the bounds when the window last started entering fullscreen. Used to
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm index fafbe54..ffc6669 100644 --- a/ui/views/cocoa/bridged_native_widget.mm +++ b/ui/views/cocoa/bridged_native_widget.mm
@@ -16,6 +16,7 @@ #include "base/no_destructor.h" #include "base/single_thread_task_runner.h" #include "base/strings/sys_string_conversions.h" +#include "ui/accelerated_widget_mac/window_resize_helper_mac.h" #include "ui/base/cocoa/cocoa_base_utils.h" #import "ui/base/cocoa/constrained_window/constrained_window_animation.h" #import "ui/base/cocoa/window_size_constants.h" @@ -78,18 +79,6 @@ } @end -// The NSView that hosts the composited CALayer drawing the UI. It fills the -// window but is not hittable so that accessibility hit tests always go to the -// BridgedContentView. -@interface ViewsCompositorSuperview : NSView -@end - -@implementation ViewsCompositorSuperview -- (NSView*)hitTest:(NSPoint)aPoint { - return nil; -} -@end - // This class overrides NSAnimation methods to invalidate the shadow for each // frame. It is required because the show animation uses CGSSetWindowWarp() // which is touchy about the consistency of the points it is given. The show @@ -295,7 +284,8 @@ void BridgedNativeWidgetImpl::BindRequest( views_bridge_mac::mojom::BridgedNativeWidgetRequest request) { - bridge_mojo_binding_.Bind(std::move(request)); + bridge_mojo_binding_.Bind(std::move(request), + ui::WindowResizeHelperMac::Get()->task_runner()); } void BridgedNativeWidgetImpl::SetWindow( @@ -454,7 +444,6 @@ void BridgedNativeWidgetImpl::DestroyContentView() { if (!bridged_view_) return; - drag_drop_client_.reset(); [bridged_view_ clearView]; bridged_view_.reset(); [window_ setContentView:nil]; @@ -462,8 +451,6 @@ void BridgedNativeWidgetImpl::CreateContentView(const gfx::Rect& bounds) { DCHECK(!bridged_view_); - // The compositor needs to point at the new content view created here. - DCHECK(!compositor_superview_); bridged_view_.reset( [[BridgedContentView alloc] initWithBridge:this bounds:bounds]); @@ -472,17 +459,17 @@ // this should be treated as an error and caught early. CHECK(bridged_view_); - // Layer backing the content view improves resize performance, reduces memory - // use (no backing store), and clips sublayers to rounded window corners. + // Set the layer first to create a layer-hosting view (not layer-backed), and + // set the compositor output to go to that layer. + base::scoped_nsobject<CALayer> background_layer([[CALayer alloc] init]); + display_ca_layer_tree_ = + std::make_unique<ui::DisplayCALayerTree>(background_layer.get()); + [bridged_view_ setLayer:background_layer]; [bridged_view_ setWantsLayer:YES]; [window_ setContentView:bridged_view_]; } -void BridgedNativeWidgetImpl::CreateDragDropClient(View* view) { - drag_drop_client_.reset(new DragDropClientMac(this, view)); -} - void BridgedNativeWidgetImpl::CloseWindow() { // Keep |window| on the stack so that the ObjectiveC block below can capture // it and properly increment the reference count bound to the posted task. @@ -889,8 +876,6 @@ } void BridgedNativeWidgetImpl::InitCompositorView() { - AddCompositorSuperview(); - // Use the regular window background for window modal sheets. The layer will // still paint over most of it, but the native -[NSApp beginSheet:] animation // blocks the UI thread, so there's no way to invalidate the shadow to match @@ -922,12 +907,6 @@ // orderOut: in Close(), which notifies visibility changes to Views. if (!bridged_view_) return; - - // Unassociated NSViews should be ordered above associated ones. The exception - // is the UI compositor's superview, which should always be on the very - // bottom, so give it an explicit negative rank. - if (compositor_superview_) - rank[compositor_superview_] = -1; [bridged_view_ sortSubviewsUsingFunction:&SubviewSorter context:&rank]; } @@ -1003,6 +982,10 @@ return window_.get(); } +views_bridge_mac::DragDropClient* BridgedNativeWidgetImpl::drag_drop_client() { + return host_helper_->GetDragDropClient(); +} + //////////////////////////////////////////////////////////////////////////////// // BridgedNativeWidgetImpl, ui::CATransactionObserver @@ -1020,7 +1003,7 @@ return false; if (ca_transaction_sync_suppressed_) return false; - if (!compositor_superview_) + if (!bridged_view_) return false; return content_dip_size_ != compositor_frame_dip_size_; } @@ -1226,35 +1209,6 @@ CountBridgedWindows([window_ childWindows])); } -void BridgedNativeWidgetImpl::AddCompositorSuperview() { - DCHECK(!compositor_superview_); - compositor_superview_.reset( - [[ViewsCompositorSuperview alloc] initWithFrame:[bridged_view_ bounds]]); - - // Size and resize automatically with |bridged_view_|. - [compositor_superview_ - setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - - // Enable HiDPI backing when supported (only on 10.7+). - if ([compositor_superview_ respondsToSelector: - @selector(setWantsBestResolutionOpenGLSurface:)]) { - [compositor_superview_ setWantsBestResolutionOpenGLSurface:YES]; - } - - // Set the layer first to create a layer-hosting view (not layer-backed), and - // set the compositor output to go to that layer. - base::scoped_nsobject<CALayer> background_layer([[CALayer alloc] init]); - display_ca_layer_tree_ = - std::make_unique<ui::DisplayCALayerTree>(background_layer.get()); - [compositor_superview_ setLayer:background_layer]; - [compositor_superview_ setWantsLayer:YES]; - - // The UI compositor should always be the first subview, to ensure webviews - // are drawn on top of it. - DCHECK_EQ(0u, [[bridged_view_ subviews] count]); - [bridged_view_ addSubview:compositor_superview_]; -} - void BridgedNativeWidgetImpl::UpdateWindowGeometry() { gfx::Rect window_in_screen = gfx::ScreenRectFromNSRect([window_ frame]); gfx::Rect content_in_screen = gfx::ScreenRectFromNSRect(
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.h b/ui/views/cocoa/bridged_native_widget_host_impl.h index 2e08c03..91a2e35a 100644 --- a/ui/views/cocoa/bridged_native_widget_host_impl.h +++ b/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -15,6 +15,7 @@ #include "ui/base/ime/input_method_delegate.h" #include "ui/compositor/layer_owner.h" #include "ui/views/cocoa/bridge_factory_host.h" +#include "ui/views/cocoa/drag_drop_client_mac.h" #include "ui/views/focus/focus_manager.h" #include "ui/views/views_export.h" #include "ui/views/widget/widget.h" @@ -92,6 +93,10 @@ TooltipManager* tooltip_manager() { return tooltip_manager_.get(); } + DragDropClientMac* drag_drop_client() const { + return drag_drop_client_.get(); + } + // Create and set the bridge object to be in this process. void CreateLocalBridge(base::scoped_nsobject<NativeWidgetMacNSWindow> window, NSView* parent); @@ -190,6 +195,7 @@ gfx::DecoratedText* decorated_word, gfx::Point* baseline_point) override; double SheetPositionY() override; + views_bridge_mac::DragDropClient* GetDragDropClient() override; // BridgeFactoryHost::Observer: void OnBridgeFactoryHostDestroying(BridgeFactoryHost* host) override; @@ -293,6 +299,7 @@ Widget::InitParams::Type widget_type_ = Widget::InitParams::TYPE_WINDOW; views::View* root_view_ = nullptr; // Weak. Owned by |native_widget_mac_|. + std::unique_ptr<DragDropClientMac> drag_drop_client_; // The mojo pointer to a BridgedNativeWidget, which may exist in another // process.
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.mm b/ui/views/cocoa/bridged_native_widget_host_impl.mm index 72405ed..d3e9d99e1 100644 --- a/ui/views/cocoa/bridged_native_widget_host_impl.mm +++ b/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -5,6 +5,7 @@ #include "ui/views/cocoa/bridged_native_widget_host_impl.h" #include "base/mac/foundation_util.h" +#include "ui/accelerated_widget_mac/window_resize_helper_mac.h" #include "ui/base/hit_test.h" #include "ui/base/ime/input_method.h" #include "ui/base/ime/input_method_factory.h" @@ -145,7 +146,8 @@ // Initialize |bridge_ptr_| to point to a bridge created by |factory|. views_bridge_mac::mojom::BridgedNativeWidgetHostPtr host_ptr; - host_mojo_binding_.Bind(mojo::MakeRequest(&host_ptr)); + host_mojo_binding_.Bind(mojo::MakeRequest(&host_ptr), + ui::WindowResizeHelperMac::Get()->task_runner()); bridge_factory_host_->GetFactory()->CreateBridge( id_, mojo::MakeRequest(&bridge_ptr_), std::move(host_ptr)); @@ -247,6 +249,15 @@ void BridgedNativeWidgetHostImpl::SetRootView(views::View* root_view) { root_view_ = root_view; + if (root_view_) { + // TODO(ccameron): Drag-drop functionality does not yet run over mojo. + if (bridge_impl_) { + drag_drop_client_.reset( + new DragDropClientMac(bridge_impl_.get(), root_view_)); + } + } else { + drag_drop_client_.reset(); + } } void BridgedNativeWidgetHostImpl::CreateCompositor( @@ -453,6 +464,11 @@ return native_widget_mac_->SheetPositionY(); } +views_bridge_mac::DragDropClient* +BridgedNativeWidgetHostImpl::GetDragDropClient() { + return drag_drop_client_.get(); +} + //////////////////////////////////////////////////////////////////////////////// // BridgedNativeWidgetHostImpl, BridgeFactoryHost::Observer: void BridgedNativeWidgetHostImpl::OnBridgeFactoryHostDestroying(
diff --git a/ui/views/cocoa/drag_drop_client_mac.h b/ui/views/cocoa/drag_drop_client_mac.h index f4044b7..e93d8a0 100644 --- a/ui/views/cocoa/drag_drop_client_mac.h +++ b/ui/views/cocoa/drag_drop_client_mac.h
@@ -14,6 +14,7 @@ #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/views/views_export.h" #include "ui/views/widget/drop_helper.h" +#include "ui/views_bridge_mac/drag_drop_client.h" // This class acts as a bridge between NSPasteboardItem and OSExchangeData by // implementing NSPasteboardItemDataProvider and writing data from @@ -38,10 +39,10 @@ // Implements drag and drop on MacViews. This class acts as a bridge between // the Views and native system's drag and drop. This class mimics // DesktopDragDropClientAuraX11. -class VIEWS_EXPORT DragDropClientMac { +class VIEWS_EXPORT DragDropClientMac : public views_bridge_mac::DragDropClient { public: DragDropClientMac(BridgedNativeWidgetImpl* bridge, View* root_view); - ~DragDropClientMac(); + ~DragDropClientMac() override; // Initiates a drag and drop session. Returns the drag operation that was // applied at the end of the drag drop session. @@ -50,20 +51,14 @@ int operation, ui::DragDropTypes::DragEventSource source); - // Called when mouse is dragged during a drag and drop. - NSDragOperation DragUpdate(id<NSDraggingInfo>); - - // Called when mouse is released during a drag and drop. - NSDragOperation Drop(id<NSDraggingInfo> sender); - - // Called when the drag and drop session has ended. - void EndDrag(); - - // Called when mouse leaves the drop area. - void DragExit(); - DropHelper* drop_helper() { return &drop_helper_; } + // views_bridge_mac::DragDropClient: + NSDragOperation DragUpdate(id<NSDraggingInfo>) override; + NSDragOperation Drop(id<NSDraggingInfo> sender) override; + void EndDrag() override; + void DragExit() override; + private: friend class test::DragDropClientMacTest;
diff --git a/ui/views/cocoa/drag_drop_client_mac_unittest.mm b/ui/views/cocoa/drag_drop_client_mac_unittest.mm index e91bb57..47c8ffe 100644 --- a/ui/views/cocoa/drag_drop_client_mac_unittest.mm +++ b/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -156,7 +156,9 @@ public: DragDropClientMacTest() : widget_(new Widget) {} - DragDropClientMac* drag_drop_client() { return bridge_->drag_drop_client(); } + DragDropClientMac* drag_drop_client() { + return bridge_host_->drag_drop_client(); + } NSDragOperation DragUpdate(NSPasteboard* pasteboard) { DragDropClientMac* client = drag_drop_client();
diff --git a/ui/views/controls/menu/menu_runner_cocoa_unittest.mm b/ui/views/controls/menu/menu_runner_cocoa_unittest.mm index 2cc6a8c..7acfc99f 100644 --- a/ui/views/controls/menu/menu_runner_cocoa_unittest.mm +++ b/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
@@ -106,6 +106,8 @@ gfx::Rect(kWindowOffset, kWindowOffset, kWindowWidth, kWindowHeight)); parent_->Show(); + native_view_subview_count_ = [[parent_->GetNativeView() subviews] count]; + base::Closure on_close = base::Bind(&MenuRunnerCocoaTest::MenuCloseCallback, base::Unretained(this)); if (GetParam() == MenuType::NATIVE) @@ -116,6 +118,9 @@ } void TearDown() override { + EXPECT_EQ(native_view_subview_count_, + [[parent_->GetNativeView() subviews] count]); + if (runner_) { runner_->Release(); runner_ = NULL; @@ -151,10 +156,6 @@ void RunMenuAt(const gfx::Rect& anchor) { last_anchor_frame_ = NSZeroRect; - // Should be one child (the compositor layer) before showing, and it should - // go up by one (the anchor view) while the menu is shown. - EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]); - base::OnceClosure callback = base::BindOnce(&MenuRunnerCocoaTest::ComboboxRunMenuAtCallback, base::Unretained(this)); @@ -168,9 +169,6 @@ runner_->RunMenuAt(parent_, nullptr, anchor, MENU_ANCHOR_TOPLEFT, MenuRunner::COMBOBOX); MaybeRunAsync(); - - // Ensure the anchor view is removed. - EXPECT_EQ(1u, [[parent_->GetNativeView() subviews] count]); } void MenuCancelCallback() { @@ -244,6 +242,7 @@ internal::MenuRunnerImplInterface* runner_ = nullptr; views::Widget* parent_ = nullptr; NSRect last_anchor_frame_ = NSZeroRect; + NSUInteger native_view_subview_count_ = 0; int menu_close_count_ = 0; private: @@ -256,10 +255,11 @@ NSArray* subviews = [parent_->GetNativeView() subviews]; // An anchor view should only be added for Native menus. if (GetParam() == MenuType::NATIVE) { - ASSERT_EQ(2u, [subviews count]); - last_anchor_frame_ = [[subviews objectAtIndex:1] frame]; + ASSERT_EQ(native_view_subview_count_ + 1, [subviews count]); + last_anchor_frame_ = + [[subviews objectAtIndex:native_view_subview_count_] frame]; } else { - EXPECT_EQ(1u, [subviews count]); + EXPECT_EQ(native_view_subview_count_, [subviews count]); } runner_->Cancel(); }
diff --git a/ui/views/mus/ax_remote_host.cc b/ui/views/mus/ax_remote_host.cc index edb77057..6fa87f1 100644 --- a/ui/views/mus/ax_remote_host.cc +++ b/ui/views/mus/ax_remote_host.cc
@@ -102,9 +102,15 @@ if (!enabled_) return; - AXAuraObjWrapper* aura_obj = - view ? AXAuraObjCache::GetInstance()->GetOrCreate(view) - : tree_source_->GetRoot(); + if (!view) { + SendEvent(tree_source_->GetRoot(), event_type); + return; + } + + // Can return null for views without a widget. + AXAuraObjWrapper* aura_obj = AXAuraObjCache::GetInstance()->GetOrCreate(view); + if (!aura_obj) + return; SendEvent(aura_obj, event_type); }
diff --git a/ui/views/mus/ax_remote_host_unittest.cc b/ui/views/mus/ax_remote_host_unittest.cc index f853363..359d057 100644 --- a/ui/views/mus/ax_remote_host_unittest.cc +++ b/ui/views/mus/ax_remote_host_unittest.cc
@@ -165,6 +165,20 @@ EXPECT_EQ(ax::mojom::Event::kLoadComplete, service.last_event_.event_type); } +// Verifies that a remote app doesn't crash if a View triggers an accessibility +// event before it is attached to a Widget. https://crbug.com/889121 +TEST_F(AXRemoteHostTest, SendEventOnViewWithNoWidget) { + TestAXHostService service(true /*automation_enabled*/); + AXRemoteHost* remote = CreateRemote(&service); + std::unique_ptr<Widget> widget = CreateTestWidget(); + remote->FlushForTesting(); + + // Create a view that is not yet associated with the widget. + views::View view; + remote->HandleEvent(&view, ax::mojom::Event::kLocationChanged); + // No crash. +} + // Verifies that the AXRemoteHost stops monitoring widgets that are closed // asynchronously, like when ash requests close via DesktopWindowTreeHostMus. // https://crbug.com/869608
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm index 3fa4df8..cba45a1a7 100644 --- a/ui/views/widget/native_widget_mac.mm +++ b/ui/views/widget/native_widget_mac.mm
@@ -145,8 +145,6 @@ DCHECK(GetWidget()->GetRootView()); bridge_host_->SetRootView(GetWidget()->GetRootView()); bridge()->CreateContentView(GetWidget()->GetRootView()->bounds()); - if (bridge_impl()) - bridge_impl()->CreateDragDropClient(GetWidget()->GetRootView()); if (auto* focus_manager = GetWidget()->GetFocusManager()) { bridge()->MakeFirstResponder(); bridge_host_->SetFocusManager(focus_manager); @@ -220,7 +218,7 @@ void NativeWidgetMac::ViewRemoved(View* view) { DragDropClientMac* client = - bridge_impl() ? bridge_impl()->drag_drop_client() : nullptr; + bridge_host_ ? bridge_host_->drag_drop_client() : nullptr; if (client) client->drop_helper()->ResetTargetViewIfEquals(view); } @@ -513,8 +511,8 @@ const gfx::Point& location, int operation, ui::DragDropTypes::DragEventSource source) { - bridge_impl()->drag_drop_client()->StartDragAndDrop(view, data, operation, - source); + bridge_host_->drag_drop_client()->StartDragAndDrop(view, data, operation, + source); } void NativeWidgetMac::SchedulePaintInRect(const gfx::Rect& rect) {
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm index 7436e30..b4ae028 100644 --- a/ui/views/widget/native_widget_mac_unittest.mm +++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -2180,8 +2180,10 @@ widget_ = CreateTopLevelPlatformWidget(); - ASSERT_EQ(1u, [[widget_->GetNativeView() subviews] count]); - compositor_view_ = [[widget_->GetNativeView() subviews] firstObject]; + // It's not a bug if the native view has a different number of subviews, + // but the rest of this test assumes it. It may or may not be worth + // removing that assumption at some point. + ASSERT_EQ(0u, [[widget_->GetNativeView() subviews] count]); native_host_parent_ = new View(); widget_->GetContentsView()->AddChildView(native_host_parent_); @@ -2194,10 +2196,8 @@ hosts_.push_back(std::move(holder)); } EXPECT_EQ(kNativeViewCount, native_host_parent_->child_count()); - EXPECT_NSEQ([widget_->GetNativeView() subviews], (@[ - compositor_view_, hosts_[0]->view(), hosts_[1]->view(), - hosts_[2]->view() - ])); + EXPECT_NSEQ([widget_->GetNativeView() subviews], + (@[ hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view() ])); } void TearDown() override { @@ -2209,7 +2209,6 @@ Widget* widget_ = nullptr; View* native_host_parent_ = nullptr; - NSView* compositor_view_ = nil; std::vector<std::unique_ptr<NativeHostHolder>> hosts_; private: @@ -2221,58 +2220,50 @@ TEST_F(NativeWidgetMacViewsOrderTest, NativeViewAttached) { hosts_[1]->Detach(); EXPECT_NSEQ([GetContentNativeView() subviews], - (@[ compositor_view_, hosts_[0]->view(), hosts_[2]->view() ])); + (@[ hosts_[0]->view(), hosts_[2]->view() ])); hosts_[1]->AttachNativeView(); - EXPECT_NSEQ([GetContentNativeView() subviews], (@[ - compositor_view_, hosts_[0]->view(), hosts_[1]->view(), - hosts_[2]->view() - ])); + EXPECT_NSEQ([GetContentNativeView() subviews], + (@[ hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view() ])); } // Tests that NativeViews order changes according to views::View hierarchy. TEST_F(NativeWidgetMacViewsOrderTest, ReorderViews) { native_host_parent_->ReorderChildView(hosts_[2]->host(), 1); - EXPECT_NSEQ([GetContentNativeView() subviews], (@[ - compositor_view_, hosts_[0]->view(), hosts_[2]->view(), - hosts_[1]->view() - ])); + EXPECT_NSEQ([GetContentNativeView() subviews], + (@[ hosts_[0]->view(), hosts_[2]->view(), hosts_[1]->view() ])); native_host_parent_->RemoveChildView(hosts_[2]->host()); EXPECT_NSEQ([GetContentNativeView() subviews], - (@[ compositor_view_, hosts_[0]->view(), hosts_[1]->view() ])); + (@[ hosts_[0]->view(), hosts_[1]->view() ])); View* new_parent = new View(); native_host_parent_->RemoveChildView(hosts_[1]->host()); native_host_parent_->AddChildView(new_parent); new_parent->AddChildView(hosts_[1]->host()); new_parent->AddChildView(hosts_[2]->host()); - EXPECT_NSEQ([GetContentNativeView() subviews], (@[ - compositor_view_, hosts_[0]->view(), hosts_[1]->view(), - hosts_[2]->view() - ])); + EXPECT_NSEQ([GetContentNativeView() subviews], + (@[ hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view() ])); native_host_parent_->ReorderChildView(new_parent, 0); - EXPECT_NSEQ([GetContentNativeView() subviews], (@[ - compositor_view_, hosts_[1]->view(), hosts_[2]->view(), - hosts_[0]->view() - ])); + EXPECT_NSEQ([GetContentNativeView() subviews], + (@[ hosts_[1]->view(), hosts_[2]->view(), hosts_[0]->view() ])); } // Test that unassociated native views stay on top after reordering. TEST_F(NativeWidgetMacViewsOrderTest, UnassociatedViewsIsAbove) { base::scoped_nsobject<NSView> child_view([[NSView alloc] init]); [GetContentNativeView() addSubview:child_view]; - EXPECT_NSEQ([GetContentNativeView() subviews], (@[ - compositor_view_, hosts_[0]->view(), hosts_[1]->view(), - hosts_[2]->view(), child_view - ])); + EXPECT_NSEQ( + [GetContentNativeView() subviews], (@[ + hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view(), child_view + ])); native_host_parent_->ReorderChildView(hosts_[2]->host(), 1); - EXPECT_NSEQ([GetContentNativeView() subviews], (@[ - compositor_view_, hosts_[0]->view(), hosts_[2]->view(), - hosts_[1]->view(), child_view - ])); + EXPECT_NSEQ( + [GetContentNativeView() subviews], (@[ + hosts_[0]->view(), hosts_[2]->view(), hosts_[1]->view(), child_view + ])); } // Test -[NSWindowDelegate windowShouldClose:].
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index 9ca4bdad..2841eb8b 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc
@@ -1017,7 +1017,10 @@ } void HWNDMessageHandler::OnTextInputStateChanged( - const ui::TextInputClient* client) {} + const ui::TextInputClient* client) { + if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) + OnCaretBoundsChanged(client); +} void HWNDMessageHandler::OnInputMethodDestroyed( const ui::InputMethod* input_method) {
diff --git a/ui/views_bridge_mac/BUILD.gn b/ui/views_bridge_mac/BUILD.gn index 30af4801..1043a8a 100644 --- a/ui/views_bridge_mac/BUILD.gn +++ b/ui/views_bridge_mac/BUILD.gn
@@ -12,6 +12,7 @@ "cocoa_mouse_capture.h", "cocoa_mouse_capture.mm", "cocoa_mouse_capture_delegate.h", + "drag_drop_client.h", "views_bridge_mac_export.h", ] defines = [ "VIEWS_BRIDGE_MAC_IMPLEMENTATION" ]
diff --git a/ui/views_bridge_mac/bridged_native_widget_host_helper.h b/ui/views_bridge_mac/bridged_native_widget_host_helper.h index 39457d5..4fe8218c 100644 --- a/ui/views_bridge_mac/bridged_native_widget_host_helper.h +++ b/ui/views_bridge_mac/bridged_native_widget_host_helper.h
@@ -15,6 +15,8 @@ namespace views_bridge_mac { +class DragDropClient; + // This is a helper class for the mojo interface BridgedNativeWidgetHost. // This provides an easier-to-use interface than the mojo for selected // functions. It also is temporarily exposing functionality that is not yet @@ -54,6 +56,10 @@ // TODO(ccameron): This should be either moved to the mojo interface or // separated out in such a way as to avoid needing to go through mojo. virtual double SheetPositionY() = 0; + + // Return a pointer to host's DragDropClientMac. + // TODO(ccameron): Drag-drop behavior needs to be implemented over mojo. + virtual DragDropClient* GetDragDropClient() = 0; }; } // namespace views_bridge_mac
diff --git a/ui/views_bridge_mac/drag_drop_client.h b/ui/views_bridge_mac/drag_drop_client.h new file mode 100644 index 0000000..3efa842 --- /dev/null +++ b/ui/views_bridge_mac/drag_drop_client.h
@@ -0,0 +1,37 @@ +// 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 UI_VIEWS_BRIDGE_MAC_DRAG_DROP_CLIENT_H_ +#define UI_VIEWS_BRIDGE_MAC_DRAG_DROP_CLIENT_H_ + +#import <Cocoa/Cocoa.h> + +#include "ui/views_bridge_mac/views_bridge_mac_export.h" + +namespace views_bridge_mac { + +// Interface between the content view of a BridgedNativeWidgetImpl and a +// DragDropClientMac in the browser process. This interface should eventually +// become mojo-ified, but at the moment only passes raw pointers (consequently, +// drag-drop behavior does not work in RemoteMacViews). +class VIEWS_BRIDGE_MAC_EXPORT DragDropClient { + public: + virtual ~DragDropClient() {} + + // Called when mouse is dragged during a drag and drop. + virtual NSDragOperation DragUpdate(id<NSDraggingInfo>) = 0; + + // Called when mouse is released during a drag and drop. + virtual NSDragOperation Drop(id<NSDraggingInfo> sender) = 0; + + // Called when the drag and drop session has ended. + virtual void EndDrag() = 0; + + // Called when mouse leaves the drop area. + virtual void DragExit() = 0; +}; + +} // namespace views_bridge_mac + +#endif // UI_VIEWS_BRIDGE_MAC_DRAG_DROP_CLIENT_H_