diff --git a/DEPS b/DEPS index 0d75b7d2..f13a8c6 100644 --- a/DEPS +++ b/DEPS
@@ -196,7 +196,7 @@ Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0', 'src/third_party/webgl/src': - Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'c91689d6df5536fefaa07a459c80c210bd580a1b', + Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '73b300f24942adf7013de30ccdc6a2cc88105e72', 'src/third_party/webdriver/pylib': Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 60d2237..1b1de9f 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -402,6 +402,10 @@ "system/network/vpn_list_view.h", "system/networking_config_delegate.cc", "system/networking_config_delegate.h", + "system/night_light/night_light_controller.cc", + "system/night_light/night_light_controller.h", + "system/night_light/tray_night_light.cc", + "system/night_light/tray_night_light.h", "system/overview/overview_button_tray.cc", "system/overview/overview_button_tray.h", "system/palette/common_palette_tool.cc", @@ -1193,6 +1197,8 @@ "system/network/sms_observer_unittest.cc", "system/network/tray_network_unittest.cc", "system/network/vpn_list_unittest.cc", + "system/night_light/night_light_controller_unittest.cc", + "system/night_light/tray_night_light_unittest.cc", "system/overview/overview_button_tray_unittest.cc", "system/palette/mock_palette_tool_delegate.cc", "system/palette/mock_palette_tool_delegate.h",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 34a9e15..b41d8ad 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -213,7 +213,9 @@ <message name="IDS_ASH_STATUS_TRAY_MESSAGE_OUT_OF_USERS" desc="The error message when all the users are added into multi-profile session."> All available users have already been added to this session. </message> - + <message name="IDS_ASH_STATUS_TRAY_NIGHT_LIGHT" desc="The label used for the button in the status tray to toggle the Night Light feature (which controls the color temperature of the screen) on or off."> + Toggle Night Light + </message> <message name="IDS_ASH_STATUS_TRAY_CAST" desc="The label used as the header in the cast popup."> Cast screen </message>
diff --git a/ash/metrics/user_metrics_action.h b/ash/metrics/user_metrics_action.h index 6fa1dd4..ea297ff 100644 --- a/ash/metrics/user_metrics_action.h +++ b/ash/metrics/user_metrics_action.h
@@ -124,6 +124,7 @@ UMA_TOUCHSCREEN_TAP_DOWN, UMA_TRAY_HELP, UMA_TRAY_LOCK_SCREEN, + UMA_TRAY_NIGHT_LIGHT, UMA_TRAY_OVERVIEW, UMA_TRAY_SETTINGS, UMA_TRAY_SHUT_DOWN,
diff --git a/ash/metrics/user_metrics_recorder.cc b/ash/metrics/user_metrics_recorder.cc index a6ff35ea..a28b656b 100644 --- a/ash/metrics/user_metrics_recorder.cc +++ b/ash/metrics/user_metrics_recorder.cc
@@ -547,6 +547,9 @@ case UMA_TRAY_LOCK_SCREEN: RecordAction(UserMetricsAction("Tray_LockScreen")); break; + case UMA_TRAY_NIGHT_LIGHT: + RecordAction(UserMetricsAction("Tray_NightLight")); + break; case UMA_TRAY_OVERVIEW: RecordAction(UserMetricsAction("Tray_Overview")); break;
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn index 622ffc4a..1e57c91da 100644 --- a/ash/resources/vector_icons/BUILD.gn +++ b/ash/resources/vector_icons/BUILD.gn
@@ -176,6 +176,10 @@ "system_menu_update.icon", "system_menu_new_user.1x.icon", "system_menu_new_user.icon", + "system_menu_night_light_off.1x.icon", + "system_menu_night_light_off.icon", + "system_menu_night_light_on.1x.icon", + "system_menu_night_light_on.icon", "system_menu_usb.1x.icon", "system_menu_usb.icon", "system_menu_videocam.1x.icon", @@ -204,6 +208,8 @@ "system_tray_caps_lock.icon", "system_tray_cast.1x.icon", "system_tray_cast.icon", + "system_tray_night_light.1x.icon", + "system_tray_night_light.icon", "system_tray_recording.1x.icon", "system_tray_recording.icon", "system_tray_rotation_lock_auto.1x.icon",
diff --git a/ash/resources/vector_icons/system_menu_night_light_off.1x.icon b/ash/resources/vector_icons/system_menu_night_light_off.1x.icon new file mode 100644 index 0000000..e7f4aa3 --- /dev/null +++ b/ash/resources/vector_icons/system_menu_night_light_off.1x.icon
@@ -0,0 +1,34 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 17.15f, 13.59f, +LINE_TO, 9.44f, 5.88f, +R_CUBIC_TO, 0.7f, -0.72f, 1.57f, -1.27f, 2.56f, -1.59f, +R_CUBIC_TO, -0.59f, -0.19f, -1.23f, -0.29f, -1.88f, -0.29f, +R_CUBIC_TO, -0.76f, 0, -1.49f, 0.14f, -2.17f, 0.39f, +LINE_TO, 6.41f, 2.85f, +CUBIC_TO, 7.49f, 2.31f, 8.71f, 2, 10, 2, +R_CUBIC_TO, 4.42f, 0, 8, 3.58f, 8, 8, +R_CUBIC_TO, 0, 1.29f, -0.31f, 2.51f, -0.85f, 3.59f, +CLOSE, +R_MOVE_TO, -1.78f, 2.34f, +CUBIC_TO, 13.95f, 17.22f, 12.06f, 18, 10, 18, +R_CUBIC_TO, -4.42f, 0, -8, -3.58f, -8, -8, +R_CUBIC_TO, 0, -2.06f, 0.78f, -3.95f, 2.07f, -5.37f, +R_LINE_TO, 1.43f, 1.43f, +CUBIC_TO, 4.57f, 7.12f, 4, 8.49f, 4, 10, +R_CUBIC_TO, 0, 3.31f, 2.74f, 6, 6.12f, 6, +R_CUBIC_TO, 0.66f, 0, 1.29f, -0.1f, 1.88f, -0.29f, +R_CUBIC_TO, -2.46f, -0.78f, -4.24f, -3.04f, -4.24f, -5.71f, +R_CUBIC_TO, 0, -0.51f, 0.07f, -1.01f, 0.19f, -1.49f, +R_LINE_TO, 7.41f, 7.42f, +CLOSE, +MOVE_TO, 2.5f, 3.06f, +LINE_TO, 3.56f, 2, +R_LINE_TO, 14.31f, 14.31f, +R_LINE_TO, -1.06f, 1.06f, +LINE_TO, 2.5f, 3.06f, +CLOSE, +END \ No newline at end of file
diff --git a/ash/resources/vector_icons/system_menu_night_light_off.icon b/ash/resources/vector_icons/system_menu_night_light_off.icon new file mode 100644 index 0000000..1e7bc9f --- /dev/null +++ b/ash/resources/vector_icons/system_menu_night_light_off.icon
@@ -0,0 +1,34 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 40, +MOVE_TO, 34.3f, 27.18f, +LINE_TO, 18.38f, 11.26f, +CUBIC_TO, 19.89f, 9.6f, 21.82f, 8.33f, 24, 7.63f, +CUBIC_TO, 22.74f, 7.22f, 21.4f, 7, 20, 7, +R_CUBIC_TO, -1.74f, 0, -3.4f, 0.34f, -4.92f, 0.96f, +LINE_TO, 12.82f, 5.7f, +CUBIC_TO, 14.98f, 4.61f, 17.42f, 4, 20, 4, +R_CUBIC_TO, 8.83f, 0, 16, 7.17f, 16, 16, +R_CUBIC_TO, 0, 2.58f, -0.61f, 5.02f, -1.7f, 7.18f, +CLOSE, +R_MOVE_TO, -3.56f, 4.68f, +CUBIC_TO, 27.9f, 34.43f, 24.13f, 36, 20, 36, +R_CUBIC_TO, -8.83f, 0, -16, -7.17f, -16, -16, +R_CUBIC_TO, 0, -4.13f, 1.57f, -7.9f, 4.14f, -10.74f, +R_LINE_TO, 2.12f, 2.12f, +CUBIC_TO, 8.23f, 13.68f, 7, 16.7f, 7, 20, +R_CUBIC_TO, 0, 7.18f, 5.82f, 13, 13, 13, +R_CUBIC_TO, 1.4f, 0, 2.74f, -0.22f, 4, -0.63f, +R_CUBIC_TO, -5.22f, -1.69f, -9, -6.59f, -9, -12.37f, +R_CUBIC_TO, 0, -1.18f, 0.16f, -2.33f, 0.46f, -3.42f, +LINE_TO, 30.74f, 31.86f, +CLOSE, +MOVE_TO, 5, 6.12f, +LINE_TO, 7.12f, 4, +R_LINE_TO, 28.63f, 28.63f, +R_LINE_TO, -2.12f, 2.12f, +LINE_TO, 5, 6.12f, +CLOSE, +END \ No newline at end of file
diff --git a/ash/resources/vector_icons/system_menu_night_light_on.1x.icon b/ash/resources/vector_icons/system_menu_night_light_on.1x.icon new file mode 100644 index 0000000..64623ec --- /dev/null +++ b/ash/resources/vector_icons/system_menu_night_light_on.1x.icon
@@ -0,0 +1,20 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 20, +MOVE_TO, 10, 2, +R_CUBIC_TO, 4.42f, 0, 8, 3.58f, 8, 8, +R_CUBIC_TO, 0, 4.42f, -3.58f, 8, -8, 8, +R_CUBIC_TO, -4.42f, 0, -8, -3.58f, -8, -8, +R_CUBIC_TO, 0, -4.42f, 3.58f, -8, 8, -8, +CLOSE, +R_MOVE_TO, -0.65f, 2, +CUBIC_TO, 6.4f, 4, 4, 6.69f, 4, 10, +R_CUBIC_TO, 0, 3.31f, 2.4f, 6, 5.35f, 6, +R_CUBIC_TO, 0.57f, 0, 1.13f, -0.1f, 1.65f, -0.29f, +CUBIC_TO, 8.85f, 14.93f, 7.29f, 12.67f, 7.29f, 10, +R_CUBIC_TO, 0, -2.67f, 1.56f, -4.93f, 3.71f, -5.71f, +CUBIC_TO, 10.48f, 4.1f, 9.93f, 4, 9.35f, 4, +CLOSE, +END \ No newline at end of file
diff --git a/ash/resources/vector_icons/system_menu_night_light_on.icon b/ash/resources/vector_icons/system_menu_night_light_on.icon new file mode 100644 index 0000000..df0d3c8 --- /dev/null +++ b/ash/resources/vector_icons/system_menu_night_light_on.icon
@@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 40, +MOVE_TO, 16, 0, +CUBIC_TO, 24.83f, 0, 32, 7.17f, 32, 16, +CUBIC_TO, 32, 24.83f, 24.83f, 32, 16, 32, +CUBIC_TO, 7.17f, 32, 0, 24.83f, 0, 16, +CUBIC_TO, 0, 7.17f, 7.17f, 0, 16, 0, +CLOSE, +MOVE_TO, 20, 3.63f, +CUBIC_TO, 18.74f, 3.22f, 17.4f, 3, 16, 3, +CUBIC_TO, 8.82f, 3, 3, 8.82f, 3, 16, +CUBIC_TO, 3, 23.18f, 8.82f, 29, 16, 29, +CUBIC_TO, 17.4f, 29, 18.74f, 28.78f, 20, 28.37f, +CUBIC_TO, 14.78f, 26.69f, 11, 21.78f, 11, 16, +CUBIC_TO, 11, 10.22f, 14.78f, 5.31f, 20, 3.63f, +LINE_TO, 20, 3.63f, +CLOSE, +END \ No newline at end of file
diff --git a/ash/resources/vector_icons/system_tray_night_light.1x.icon b/ash/resources/vector_icons/system_tray_night_light.1x.icon new file mode 100644 index 0000000..17b0c5c --- /dev/null +++ b/ash/resources/vector_icons/system_tray_night_light.1x.icon
@@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 16, +MOVE_TO, 7, 0, +CUBIC_TO, 10.86f, 0, 14, 3.14f, 14, 7, +CUBIC_TO, 14, 10.86f, 10.86f, 14, 7, 14, +CUBIC_TO, 3.14f, 14, 0, 10.86f, 0, 7, +CUBIC_TO, 0, 3.14f, 3.14f, 0, 7, 0, +CLOSE, +MOVE_TO, 9, 1.29f, +CUBIC_TO, 8.41f, 1.1f, 7.77f, 1, 7.12f, 1, +CUBIC_TO, 3.74f, 1, 1, 3.69f, 1, 7, +CUBIC_TO, 1, 10.31f, 3.74f, 13, 7.12f, 13, +CUBIC_TO, 7.77f, 13, 8.41f, 12.9f, 9, 12.71f, +CUBIC_TO, 6.54f, 11.93f, 4.76f, 9.67f, 4.76f, 7, +CUBIC_TO, 4.76f, 4.33f, 6.54f, 2.07f, 9, 1.29f, +LINE_TO, 9, 1.29f, +CLOSE, +END \ No newline at end of file
diff --git a/ash/resources/vector_icons/system_tray_night_light.icon b/ash/resources/vector_icons/system_tray_night_light.icon new file mode 100644 index 0000000..863ad1f --- /dev/null +++ b/ash/resources/vector_icons/system_tray_night_light.icon
@@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 32, +MOVE_TO, 13, 0, +CUBIC_TO, 20.18f, 0, 26, 5.82f, 26, 13, +CUBIC_TO, 26, 20.18f, 20.18f, 26, 13, 26, +CUBIC_TO, 5.82f, 26, 0, 20.18f, 0, 13, +CUBIC_TO, 0, 5.82f, 5.82f, 0, 13, 0, +CLOSE, +MOVE_TO, 16, 2.53f, +CUBIC_TO, 14.96f, 2.19f, 13.86f, 2, 12.71f, 2, +CUBIC_TO, 6.79f, 2, 2, 6.92f, 2, 13, +CUBIC_TO, 2, 19.08f, 6.79f, 24, 12.71f, 24, +CUBIC_TO, 13.86f, 24, 14.96f, 23.81f, 16, 23.47f, +CUBIC_TO, 11.7f, 22.04f, 8.59f, 17.89f, 8.59f, 13, +CUBIC_TO, 8.59f, 8.11f, 11.7f, 3.96f, 16, 2.53f, +LINE_TO, 16, 2.53f, +CLOSE, +END \ No newline at end of file
diff --git a/ash/shell.cc b/ash/shell.cc index 3988f49..525229c 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -74,6 +74,7 @@ #include "ash/system/locale/locale_notification_controller.h" #include "ash/system/network/sms_observer.h" #include "ash/system/network/vpn_list.h" +#include "ash/system/night_light/night_light_controller.h" #include "ash/system/power/power_event_observer.h" #include "ash/system/power/power_status.h" #include "ash/system/power/video_activity_notifier.h" @@ -319,6 +320,11 @@ switches::kUseIMEService)); } +// static +void Shell::RegisterPrefs(PrefRegistrySimple* registry) { + NightLightController::RegisterPrefs(registry); +} + views::NonClientFrameView* Shell::CreateDefaultNonClientFrameView( views::Widget* widget) { // Use translucent-style window frames for dialogs. @@ -562,6 +568,8 @@ media_controller_(base::MakeUnique<MediaController>()), new_window_controller_(base::MakeUnique<NewWindowController>()), session_controller_(base::MakeUnique<SessionController>()), + night_light_controller_( + base::MakeUnique<NightLightController>(session_controller_.get())), shelf_controller_(base::MakeUnique<ShelfController>()), shell_delegate_(std::move(shell_delegate)), shutdown_controller_(base::MakeUnique<ShutdownController>()),
diff --git a/ash/shell.h b/ash/shell.h index 94fc96da..53363db 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -25,6 +25,7 @@ #include "ui/wm/core/cursor_manager.h" #include "ui/wm/public/activation_change_observer.h" +class PrefRegistrySimple; class PrefService; namespace aura { @@ -121,6 +122,7 @@ class MouseCursorEventFilter; class MruWindowTracker; class NewWindowController; +class NightLightController; class OverlayEventFilter; class PaletteDelegate; class PartialMagnificationController; @@ -261,6 +263,9 @@ static Config GetAshConfig(); static bool ShouldUseIMEService(); + // Registers all ash related prefs to the given |registry|. + static void RegisterPrefs(PrefRegistrySimple* registry); + // Creates a default views::NonClientFrameView for use by windows in the // Ash environment. views::NonClientFrameView* CreateDefaultNonClientFrameView( @@ -327,6 +332,9 @@ NewWindowController* new_window_controller() { return new_window_controller_.get(); } + NightLightController* night_light_controller() { + return night_light_controller_.get(); + } SessionController* session_controller() { return session_controller_.get(); } ShelfController* shelf_controller() { return shelf_controller_.get(); } ShelfModel* shelf_model(); @@ -686,6 +694,7 @@ std::unique_ptr<PaletteDelegate> palette_delegate_; std::unique_ptr<ResizeShadowController> resize_shadow_controller_; std::unique_ptr<SessionController> session_controller_; + std::unique_ptr<NightLightController> night_light_controller_; std::unique_ptr<ShelfController> shelf_controller_; std::unique_ptr<ShelfWindowWatcher> shelf_window_watcher_; std::unique_ptr<ShellDelegate> shell_delegate_;
diff --git a/ash/system/night_light/night_light_controller.cc b/ash/system/night_light/night_light_controller.cc new file mode 100644 index 0000000..bf1cae4 --- /dev/null +++ b/ash/system/night_light/night_light_controller.cc
@@ -0,0 +1,142 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/night_light/night_light_controller.h" + +#include "ash/session/session_controller.h" +#include "ash/shell.h" +#include "base/time/time.h" +#include "base/values.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/scoped_user_pref_update.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" + +namespace ash { + +namespace { + +// The key of the dictionary value in the user's pref service that contains all +// the NightLight settings. +constexpr char kNightLightPrefsKey[] = "prefs.night_light_prefs"; + +// Keys to the various NightLight settings inside its dictionary value. +constexpr char kStatusKey[] = "night_light_status"; +constexpr char kColorTemperatureKey[] = "night_light_color_temperature"; + +// The duration of the temperature change animation when the change is a result +// of a manual user setting. +// TODO(afakhry): Add automatic schedule animation duration when you implement +// that part. It should be large enough (20 seconds as agreed) to give the user +// a nice smooth transition. +constexpr int kManualToggleAnimationDurationSec = 2; + +} // namespace + +NightLightController::NightLightController( + SessionController* session_controller) + : session_controller_(session_controller) { + session_controller_->AddObserver(this); +} + +NightLightController::~NightLightController() { + session_controller_->RemoveObserver(this); +} + +// static +void NightLightController::RegisterPrefs(PrefRegistrySimple* registry) { + registry->RegisterDictionaryPref(kNightLightPrefsKey); +} + +void NightLightController::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void NightLightController::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +void NightLightController::Toggle() { + SetEnabled(!enabled_); +} + +void NightLightController::SetEnabled(bool enabled) { + if (enabled_ == enabled) + return; + + enabled_ = enabled; + Refresh(); + NotifyStatusChanged(); + PersistUserPrefs(); +} + +void NightLightController::SetColorTemperature(float temperature) { + // TODO(afakhry): Spport changing the temperature when you implement the + // settings part of this feature. Right now we'll keep it fixed at the value + // |color_temperature_| whenever NightLight is turned on. + + for (aura::Window* root_window : Shell::GetAllRootWindows()) { + ui::Layer* layer = root_window->layer(); + + ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); + settings.SetTransitionDuration( + base::TimeDelta::FromSeconds(kManualToggleAnimationDurationSec)); + settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + + layer->SetLayerTemperature(temperature); + } +} + +void NightLightController::OnActiveUserSessionChanged( + const AccountId& account_id) { + // Initial login and user switching in multi profiles. + InitFromUserPrefs(); +} + +void NightLightController::Refresh() { + SetColorTemperature(enabled_ ? color_temperature_ : 0.0f); +} + +void NightLightController::InitFromUserPrefs() { + auto* pref_service = Shell::Get()->GetActiveUserPrefService(); + if (!pref_service) { + // The pref_service can be NULL in ash_unittests. + return; + } + + const base::DictionaryValue* night_light_prefs = + pref_service->GetDictionary(kNightLightPrefsKey); + bool enabled = false; + night_light_prefs->GetBoolean(kStatusKey, &enabled); + enabled_ = enabled; + + double color_temperature = 0.5; + night_light_prefs->GetDouble(kColorTemperatureKey, &color_temperature); + color_temperature_ = static_cast<float>(color_temperature); + + Refresh(); + NotifyStatusChanged(); +} + +void NightLightController::PersistUserPrefs() { + auto* pref_service = ash::Shell::Get()->GetActiveUserPrefService(); + if (!pref_service) { + // The pref_service can be NULL in ash_unittests. + return; + } + DictionaryPrefUpdate pref_updater(pref_service, kNightLightPrefsKey); + + base::DictionaryValue* dictionary = pref_updater.Get(); + dictionary->SetBoolean(kStatusKey, enabled_); + dictionary->SetDouble(kColorTemperatureKey, + static_cast<double>(color_temperature_)); +} + +void NightLightController::NotifyStatusChanged() { + for (auto& observer : observers_) + observer.OnNightLightEnabledChanged(enabled_); +} + +} // namespace ash
diff --git a/ash/system/night_light/night_light_controller.h b/ash/system/night_light/night_light_controller.h new file mode 100644 index 0000000..0b0e5c1b --- /dev/null +++ b/ash/system/night_light/night_light_controller.h
@@ -0,0 +1,79 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_NIGHT_LIGHT_NIGHT_LIGHT_CONTROLLER_H_ +#define ASH_SYSTEM_NIGHT_LIGHT_NIGHT_LIGHT_CONTROLLER_H_ + +#include "ash/ash_export.h" +#include "ash/session/session_observer.h" +#include "base/observer_list.h" + +class PrefRegistrySimple; + +namespace ash { + +class SessionController; + +// Controls the NightLight feature that adjusts the color temperature of the +// screen. +class ASH_EXPORT NightLightController : public SessionObserver { + public: + class Observer { + public: + // Emitted when the NightLight status is changed. + virtual void OnNightLightEnabledChanged(bool enabled) = 0; + + protected: + virtual ~Observer() {} + }; + + explicit NightLightController(SessionController* session_controller); + ~NightLightController() override; + + static void RegisterPrefs(PrefRegistrySimple* registry); + + float color_temperature() const { return color_temperature_; } + bool enabled() const { return enabled_; } + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + void Toggle(); + + void SetEnabled(bool enabled); + + // Set the screen color temperature. |temperature| should be a value from + // 0.0f (least warm) to 1.0f (most warm). + void SetColorTemperature(float temperature); + + // ash::SessionObserver: + void OnActiveUserSessionChanged(const AccountId& account_id) override; + + private: + void Refresh(); + + void InitFromUserPrefs(); + + void PersistUserPrefs(); + + void NotifyStatusChanged(); + + // The observed session controller instance from which we know when to + // initialize the NightLight settings from the user preferences. + SessionController* const session_controller_; + + // The applied color temperature value when NightLight is turned ON. It's a + // value from 0.0f (least warm, default display color) to 1.0f (most warm). + float color_temperature_ = 0.5f; + + bool enabled_ = false; + + base::ObserverList<Observer> observers_; + + DISALLOW_COPY_AND_ASSIGN(NightLightController); +}; + +} // namespace ash + +#endif // ASH_SYSTEM_NIGHT_LIGHT_NIGHT_LIGHT_CONTROLLER_H_
diff --git a/ash/system/night_light/night_light_controller_unittest.cc b/ash/system/night_light/night_light_controller_unittest.cc new file mode 100644 index 0000000..9f760448f --- /dev/null +++ b/ash/system/night_light/night_light_controller_unittest.cc
@@ -0,0 +1,137 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/night_light/night_light_controller.h" + +#include "ash/public/cpp/config.h" +#include "ash/public/cpp/session_types.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/ash_test_helper.h" +#include "ash/test/test_session_controller_client.h" +#include "ash/test/test_shell_delegate.h" +#include "base/macros.h" +#include "components/prefs/testing_pref_service.h" +#include "ui/compositor/layer.h" + +namespace ash { + +namespace { + +constexpr char user_1_email[] = "user1@nightlight"; +constexpr char user_2_email[] = "user2@nightlight"; + +NightLightController* GetController() { + return Shell::Get()->night_light_controller(); +} + +// Tests that the color temperatures of all root layers are equal to the given +// |expected_temperature| and returns true if so, or false otherwise. +bool TestLayersTemperature(float expected_temperature) { + for (aura::Window* root_window : ash::Shell::GetAllRootWindows()) { + ui::Layer* layer = root_window->layer(); + if (expected_temperature != layer->layer_temperature()) + return false; + } + + return true; +} + +class TestObserver : public NightLightController::Observer { + public: + TestObserver() { GetController()->AddObserver(this); } + ~TestObserver() override { GetController()->RemoveObserver(this); } + + // ash::NightLightController::Observer: + void OnNightLightEnabledChanged(bool enabled) override { status_ = enabled; } + + bool status() const { return status_; } + + private: + bool status_ = false; + + DISALLOW_COPY_AND_ASSIGN(TestObserver); +}; + +class NightLightTest : public test::AshTestBase { + public: + NightLightTest() = default; + ~NightLightTest() override = default; + + void CreateTestUserSessions() { + GetSessionControllerClient()->Reset(); + GetSessionControllerClient()->AddUserSession(user_1_email); + GetSessionControllerClient()->AddUserSession(user_2_email); + } + + void SwitchActiveUser(const std::string& email) { + GetSessionControllerClient()->SwitchActiveUser( + AccountId::FromUserEmail(email)); + } + + void InjectTestPrefService(PrefService* pref_service) { + ash_test_helper()->test_shell_delegate()->set_active_user_pref_service( + pref_service); + } + + private: + DISALLOW_COPY_AND_ASSIGN(NightLightTest); +}; + +// Tests toggling NightLight on / off and makes sure the observer is updated and +// the layer temperatures are modified. +TEST_F(NightLightTest, TestToggle) { + UpdateDisplay("800x600,800x600"); + + TestObserver observer; + NightLightController* controller = GetController(); + controller->SetEnabled(false); + ASSERT_FALSE(controller->enabled()); + EXPECT_TRUE(TestLayersTemperature(0.0f)); + controller->Toggle(); + EXPECT_TRUE(controller->enabled()); + EXPECT_TRUE(observer.status()); + EXPECT_TRUE(TestLayersTemperature(GetController()->color_temperature())); + controller->Toggle(); + EXPECT_FALSE(controller->enabled()); + EXPECT_FALSE(observer.status()); + EXPECT_TRUE(TestLayersTemperature(0.0f)); +} + +// Tests that switching users retrieves NightLight settings for the active +// user's prefs. +TEST_F(NightLightTest, TestUserSwitchAndSettingsPersistence) { + if (Shell::GetAshConfig() == Config::MASH) { + // User switching doesn't work on mash. + return; + } + + CreateTestUserSessions(); + TestingPrefServiceSimple user_1_pref_service; + TestingPrefServiceSimple user_2_pref_service; + NightLightController::RegisterPrefs(user_1_pref_service.registry()); + NightLightController::RegisterPrefs(user_2_pref_service.registry()); + + // Simulate user 1 login. + InjectTestPrefService(&user_1_pref_service); + SwitchActiveUser(user_1_email); + NightLightController* controller = GetController(); + controller->SetEnabled(true); + EXPECT_TRUE(GetController()->enabled()); + EXPECT_TRUE(TestLayersTemperature(GetController()->color_temperature())); + + // Switch to user 2, and expect NightLight to be disabled. + InjectTestPrefService(&user_2_pref_service); + SwitchActiveUser(user_2_email); + EXPECT_FALSE(controller->enabled()); + + // Switch back to user 1, to find NightLight is still enabled. + InjectTestPrefService(&user_1_pref_service); + SwitchActiveUser(user_1_email); + EXPECT_TRUE(controller->enabled()); +} + +} // namespace + +} // namespace ash
diff --git a/ash/system/night_light/tray_night_light.cc b/ash/system/night_light/tray_night_light.cc new file mode 100644 index 0000000..bbd64b3a --- /dev/null +++ b/ash/system/night_light/tray_night_light.cc
@@ -0,0 +1,31 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/night_light/tray_night_light.h" + +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/shell.h" +#include "ui/views/view.h" + +namespace ash { + +TrayNightLight::TrayNightLight(SystemTray* system_tray) + : TrayImageItem(system_tray, kSystemTrayNightLightIcon, UMA_NIGHT_LIGHT) { + Shell::Get()->night_light_controller()->AddObserver(this); +} + +TrayNightLight::~TrayNightLight() { + Shell::Get()->night_light_controller()->RemoveObserver(this); +} + +void TrayNightLight::OnNightLightEnabledChanged(bool enabled) { + if (tray_view()) + tray_view()->SetVisible(enabled); +} + +bool TrayNightLight::GetInitialVisibility() { + return Shell::Get()->night_light_controller()->enabled(); +} + +} // namespace ash
diff --git a/ash/system/night_light/tray_night_light.h b/ash/system/night_light/tray_night_light.h new file mode 100644 index 0000000..5a38d3f9 --- /dev/null +++ b/ash/system/night_light/tray_night_light.h
@@ -0,0 +1,34 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_NIGHT_LIGHT_TRAY_NIGHT_LIGHT_H_ +#define ASH_SYSTEM_NIGHT_LIGHT_TRAY_NIGHT_LIGHT_H_ + +#include "ash/system/night_light/night_light_controller.h" +#include "ash/system/tray/tray_image_item.h" +#include "base/macros.h" + +namespace ash { + +// Shows the NightLight icon in the system tray whenever NightLight is enabled +// and active. +class TrayNightLight : public TrayImageItem, + public NightLightController::Observer { + public: + explicit TrayNightLight(SystemTray* system_tray); + ~TrayNightLight() override; + + // ash::NightLightController::Observer: + void OnNightLightEnabledChanged(bool enabled) override; + + // ash::TrayImageItem: + bool GetInitialVisibility() override; + + private: + DISALLOW_COPY_AND_ASSIGN(TrayNightLight); +}; + +} // namespace ash + +#endif // ASH_SYSTEM_NIGHT_LIGHT_TRAY_NIGHT_LIGHT_H_
diff --git a/ash/system/night_light/tray_night_light_unittest.cc b/ash/system/night_light/tray_night_light_unittest.cc new file mode 100644 index 0000000..a99b68b --- /dev/null +++ b/ash/system/night_light/tray_night_light_unittest.cc
@@ -0,0 +1,33 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/night_light/tray_night_light.h" + +#include "ash/shell.h" +#include "ash/system/night_light/night_light_controller.h" +#include "ash/system/tray/system_tray.h" +#include "ash/test/ash_test_base.h" + +namespace ash { + +namespace { + +using TrayNightLightTest = test::AshTestBase; + +// Tests that when NightLight is active, its tray icon in the System Tray is +// visible. +TEST_F(TrayNightLightTest, TestNightLightTrayVisibility) { + SystemTray* tray = GetPrimarySystemTray(); + TrayNightLight* tray_night_light = tray->tray_night_light(); + NightLightController* controller = Shell::Get()->night_light_controller(); + controller->SetEnabled(false); + ASSERT_FALSE(controller->enabled()); + EXPECT_FALSE(tray_night_light->tray_view()->visible()); + controller->SetEnabled(true); + EXPECT_TRUE(tray_night_light->tray_view()->visible()); +} + +} // namespace + +} // namespace ash
diff --git a/ash/system/tiles/tiles_default_view.cc b/ash/system/tiles/tiles_default_view.cc index d5c51a7..11fd29ee6 100644 --- a/ash/system/tiles/tiles_default_view.cc +++ b/ash/system/tiles/tiles_default_view.cc
@@ -11,6 +11,7 @@ #include "ash/shell_port.h" #include "ash/shutdown_controller.h" #include "ash/strings/grit/ash_strings.h" +#include "ash/system/night_light/night_light_controller.h" #include "ash/system/tray/system_menu_button.h" #include "ash/system/tray/system_tray.h" #include "ash/system/tray/system_tray_controller.h" @@ -41,6 +42,7 @@ : owner_(owner), settings_button_(nullptr), help_button_(nullptr), + night_light_button_(nullptr), lock_button_(nullptr), power_button_(nullptr) { DCHECK(owner_); @@ -60,13 +62,12 @@ // Show the buttons in this row as disabled if the user is at the login // screen, lock screen, or in a secondary account flow. The exception is // |power_button_| which is always shown as enabled. - const bool disable_buttons = !TrayPopupUtils::CanOpenWebUISettings(); + const bool can_show_web_ui = TrayPopupUtils::CanOpenWebUISettings(); settings_button_ = new SystemMenuButton( this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, IDS_ASH_STATUS_TRAY_SETTINGS); - if (disable_buttons) - settings_button_->SetEnabled(false); + settings_button_->SetEnabled(can_show_web_ui); AddChildView(settings_button_); AddChildView(TrayPopupUtils::CreateVerticalSeparator()); @@ -80,16 +81,25 @@ // flipping must be disabled. (crbug.com/475237) help_button_->EnableCanvasFlippingForRTLUI(false); } - if (disable_buttons) - help_button_->SetEnabled(false); + help_button_->SetEnabled(can_show_web_ui); AddChildView(help_button_); AddChildView(TrayPopupUtils::CreateVerticalSeparator()); + night_light_button_ = + new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, + Shell::Get()->night_light_controller()->enabled() + ? kSystemMenuNightLightOnIcon + : kSystemMenuNightLightOffIcon, + IDS_ASH_STATUS_TRAY_NIGHT_LIGHT); + night_light_button_->SetEnabled(can_show_web_ui); + AddChildView(night_light_button_); + AddChildView(TrayPopupUtils::CreateVerticalSeparator()); + lock_button_ = new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuLockIcon, IDS_ASH_STATUS_TRAY_LOCK); - if (disable_buttons || !Shell::Get()->session_controller()->CanLockScreen()) - lock_button_->SetEnabled(false); + lock_button_->SetEnabled(can_show_web_ui && + Shell::Get()->session_controller()->CanLockScreen()); AddChildView(lock_button_); AddChildView(TrayPopupUtils::CreateVerticalSeparator()); @@ -114,6 +124,9 @@ } else if (sender == help_button_) { ShellPort::Get()->RecordUserMetricsAction(UMA_TRAY_HELP); Shell::Get()->system_tray_controller()->ShowHelp(); + } else if (sender == night_light_button_) { + ShellPort::Get()->RecordUserMetricsAction(UMA_TRAY_NIGHT_LIGHT); + Shell::Get()->night_light_controller()->Toggle(); } else if (sender == lock_button_) { ShellPort::Get()->RecordUserMetricsAction(UMA_TRAY_LOCK_SCREEN); chromeos::DBusThreadManager::Get()
diff --git a/ash/system/tiles/tiles_default_view.h b/ash/system/tiles/tiles_default_view.h index d6fe3a8a8..d3b1ff24 100644 --- a/ash/system/tiles/tiles_default_view.h +++ b/ash/system/tiles/tiles_default_view.h
@@ -48,6 +48,7 @@ // which case the corresponding pointer will be null. views::CustomButton* settings_button_; views::CustomButton* help_button_; + views::CustomButton* night_light_button_; views::CustomButton* lock_button_; views::CustomButton* power_button_;
diff --git a/ash/system/tiles/tray_tiles_unittest.cc b/ash/system/tiles/tray_tiles_unittest.cc index 30fa094..48d5d1c6 100644 --- a/ash/system/tiles/tray_tiles_unittest.cc +++ b/ash/system/tiles/tray_tiles_unittest.cc
@@ -39,6 +39,10 @@ return tray_tiles()->default_view_->help_button_; } + views::CustomButton* GetNightLightButton() { + return tray_tiles()->default_view_->night_light_button_; + } + views::CustomButton* GetLockButton() { return tray_tiles()->default_view_->lock_button_; } @@ -61,6 +65,7 @@ tray_tiles()->CreateDefaultViewForTesting()); EXPECT_EQ(Button::STATE_DISABLED, GetSettingsButton()->state()); EXPECT_EQ(Button::STATE_DISABLED, GetHelpButton()->state()); + EXPECT_EQ(Button::STATE_DISABLED, GetNightLightButton()->state()); EXPECT_EQ(Button::STATE_DISABLED, GetLockButton()->state()); EXPECT_EQ(Button::STATE_NORMAL, GetPowerButton()->state()); } @@ -72,6 +77,7 @@ tray_tiles()->CreateDefaultViewForTesting()); EXPECT_EQ(Button::STATE_NORMAL, GetSettingsButton()->state()); EXPECT_EQ(Button::STATE_NORMAL, GetHelpButton()->state()); + EXPECT_EQ(Button::STATE_NORMAL, GetNightLightButton()->state()); EXPECT_EQ(Button::STATE_NORMAL, GetLockButton()->state()); EXPECT_EQ(Button::STATE_NORMAL, GetPowerButton()->state()); } @@ -83,6 +89,7 @@ tray_tiles()->CreateDefaultViewForTesting()); EXPECT_EQ(Button::STATE_DISABLED, GetSettingsButton()->state()); EXPECT_EQ(Button::STATE_DISABLED, GetHelpButton()->state()); + EXPECT_EQ(Button::STATE_DISABLED, GetNightLightButton()->state()); EXPECT_EQ(Button::STATE_DISABLED, GetLockButton()->state()); EXPECT_EQ(Button::STATE_NORMAL, GetPowerButton()->state()); } @@ -94,6 +101,7 @@ tray_tiles()->CreateDefaultViewForTesting()); EXPECT_EQ(Button::STATE_DISABLED, GetSettingsButton()->state()); EXPECT_EQ(Button::STATE_DISABLED, GetHelpButton()->state()); + EXPECT_EQ(Button::STATE_DISABLED, GetNightLightButton()->state()); EXPECT_EQ(Button::STATE_DISABLED, GetLockButton()->state()); EXPECT_EQ(Button::STATE_NORMAL, GetPowerButton()->state()); } @@ -109,6 +117,7 @@ tray_tiles()->CreateDefaultViewForTesting()); EXPECT_EQ(Button::STATE_DISABLED, GetSettingsButton()->state()); EXPECT_EQ(Button::STATE_DISABLED, GetHelpButton()->state()); + EXPECT_EQ(Button::STATE_DISABLED, GetNightLightButton()->state()); EXPECT_EQ(Button::STATE_DISABLED, GetLockButton()->state()); EXPECT_EQ(Button::STATE_NORMAL, GetPowerButton()->state()); }
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc index f16a8991..80c2694 100644 --- a/ash/system/tray/system_tray.cc +++ b/ash/system/tray/system_tray.cc
@@ -27,6 +27,7 @@ #include "ash/system/media_security/multi_profile_media_tray_item.h" #include "ash/system/network/tray_network.h" #include "ash/system/network/tray_vpn.h" +#include "ash/system/night_light/tray_night_light.h" #include "ash/system/power/power_status.h" #include "ash/system/power/tray_power.h" #include "ash/system/screen_security/screen_capture_tray_item.h" @@ -273,6 +274,8 @@ AddTrayItem(base::WrapUnique(tray_audio_)); AddTrayItem(base::MakeUnique<TrayBrightness>(this)); AddTrayItem(base::MakeUnique<TrayCapsLock>(this)); + tray_night_light_ = new TrayNightLight(this); + AddTrayItem(base::WrapUnique(tray_night_light_)); // TODO(jamescook): Remove this when mus has support for display management // and we have a DisplayManager equivalent. See http://crbug.com/548429 std::unique_ptr<SystemTrayItem> tray_rotation_lock =
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h index 5e5244d..bffa9e7 100644 --- a/ash/system/tray/system_tray.h +++ b/ash/system/tray/system_tray.h
@@ -29,6 +29,7 @@ class TrayCast; class TrayEnterprise; class TrayNetwork; +class TrayNightLight; class TraySupervisedUser; class TraySystemInfo; class TrayTiles; @@ -49,6 +50,8 @@ TrayUpdate* tray_update() { return tray_update_; } + TrayNightLight* tray_night_light() { return tray_night_light_; } + // Calls TrayBackgroundView::Initialize(), creates the tray items, and // adds them to SystemTrayNotifier. void InitializeTrayItems(SystemTrayDelegate* delegate, @@ -234,6 +237,7 @@ TraySupervisedUser* tray_supervised_user_ = nullptr; TraySystemInfo* tray_system_info_ = nullptr; TrayUpdate* tray_update_ = nullptr; + TrayNightLight* tray_night_light_ = nullptr; // A reference to the Screen share and capture item. ScreenTrayItem* screen_capture_tray_item_ = nullptr; // not owned
diff --git a/ash/system/tray/system_tray_item.h b/ash/system/tray/system_tray_item.h index 9b3f5cc4..41f12b19 100644 --- a/ash/system/tray/system_tray_item.h +++ b/ash/system/tray/system_tray_item.h
@@ -61,7 +61,8 @@ UMA_TRACING = 23, UMA_USER = 24, UMA_VPN = 25, - UMA_COUNT = 26, + UMA_NIGHT_LIGHT = 26, + UMA_COUNT = 27, }; SystemTrayItem(SystemTray* system_tray, UmaType type);
diff --git a/base/task_scheduler/post_task.cc b/base/task_scheduler/post_task.cc index 6da11bd8..ec4bfb5 100644 --- a/base/task_scheduler/post_task.cc +++ b/base/task_scheduler/post_task.cc
@@ -34,10 +34,10 @@ // explicitly in |traits|, the returned TaskTraits have the current // TaskPriority. TaskTraits GetTaskTraitsWithExplicitPriority(const TaskTraits& traits) { - return traits.priority_set_explicitly() - ? traits - : TaskTraits(traits).WithPriority( - internal::GetTaskPriorityForCurrentThread()); + if (traits.priority_set_explicitly()) + return traits; + return TaskTraits::Override(traits, + {internal::GetTaskPriorityForCurrentThread()}); } } // namespace
diff --git a/base/task_scheduler/task.cc b/base/task_scheduler/task.cc index fc513e3..3cf26be 100644 --- a/base/task_scheduler/task.cc +++ b/base/task_scheduler/task.cc
@@ -24,11 +24,12 @@ false), // Not nestable. // Prevent a delayed BLOCK_SHUTDOWN task from blocking shutdown before // being scheduled by changing its shutdown behavior to SKIP_ON_SHUTDOWN. - traits(!delay.is_zero() && traits.shutdown_behavior() == - TaskShutdownBehavior::BLOCK_SHUTDOWN - ? TaskTraits(traits).WithShutdownBehavior( - TaskShutdownBehavior::SKIP_ON_SHUTDOWN) - : traits), + traits( + (!delay.is_zero() && + traits.shutdown_behavior() == TaskShutdownBehavior::BLOCK_SHUTDOWN) + ? TaskTraits::Override(traits, + {TaskShutdownBehavior::SKIP_ON_SHUTDOWN}) + : traits), delay(delay) {} Task::~Task() = default;
diff --git a/base/task_scheduler/task_traits.h b/base/task_scheduler/task_traits.h index cd1d7ccf..a403a96 100644 --- a/base/task_scheduler/task_traits.h +++ b/base/task_scheduler/task_traits.h
@@ -157,6 +157,9 @@ internal::EnumArgGetter<base::TaskPriority, base::TaskPriority::USER_VISIBLE>(), args...)), + shutdown_behavior_set_explicitly_( + internal::HasArgOfType<base::TaskShutdownBehavior, + ArgTypes...>::value), shutdown_behavior_(internal::GetValueFromArgList( internal::EnumArgGetter< base::TaskShutdownBehavior, @@ -172,6 +175,14 @@ constexpr TaskTraits(const TaskTraits& other) = default; TaskTraits& operator=(const TaskTraits& other) = default; + // Returns TaskTraits constructed by combining |left| and |right|. If a trait + // is specified in both |left| and |right|, the returned TaskTraits will have + // the value from |right|. + static constexpr TaskTraits Override(const TaskTraits& left, + const TaskTraits& right) { + return TaskTraits(left, right); + } + // Deprecated. Prefer constexpr construction to builder paradigm as // documented above. // TODO(fdoray): Remove these methods. https://crbug.com/713683 @@ -188,6 +199,11 @@ // Returns the priority of tasks with these traits. constexpr TaskPriority priority() const { return priority_; } + // Returns true if the shutdown behavior was set explicitly. + constexpr bool shutdown_behavior_set_explicitly() const { + return shutdown_behavior_set_explicitly_; + } + // Returns the shutdown behavior of tasks with these traits. constexpr TaskShutdownBehavior shutdown_behavior() const { return shutdown_behavior_; @@ -202,10 +218,26 @@ } private: + constexpr TaskTraits(const TaskTraits& left, const TaskTraits& right) + : priority_set_explicitly_(left.priority_set_explicitly_ || + right.priority_set_explicitly_), + priority_(right.priority_set_explicitly_ ? right.priority_ + : left.priority_), + shutdown_behavior_set_explicitly_( + left.shutdown_behavior_set_explicitly_ || + right.shutdown_behavior_set_explicitly_), + shutdown_behavior_(right.shutdown_behavior_set_explicitly_ + ? right.shutdown_behavior_ + : left.shutdown_behavior_), + may_block_(left.may_block_ || right.may_block_), + with_base_sync_primitives_(left.with_base_sync_primitives_ || + right.with_base_sync_primitives_) {} + // TODO(fdoray): Make these const after refactoring away deprecated builder // pattern. bool priority_set_explicitly_; TaskPriority priority_; + bool shutdown_behavior_set_explicitly_; TaskShutdownBehavior shutdown_behavior_; bool may_block_; bool with_base_sync_primitives_;
diff --git a/base/task_scheduler/task_traits_unittest.cc b/base/task_scheduler/task_traits_unittest.cc index ed9065f7..2a350484 100644 --- a/base/task_scheduler/task_traits_unittest.cc +++ b/base/task_scheduler/task_traits_unittest.cc
@@ -78,4 +78,98 @@ traits_copy.with_base_sync_primitives()); } +TEST(TaskSchedulerTaskTraitsTest, OverridePriority) { + constexpr TaskTraits left = {TaskPriority::BACKGROUND}; + constexpr TaskTraits right = {TaskPriority::USER_BLOCKING}; + constexpr TaskTraits overridden = TaskTraits::Override(left, right); + EXPECT_TRUE(overridden.priority_set_explicitly()); + EXPECT_EQ(TaskPriority::USER_BLOCKING, overridden.priority()); + EXPECT_FALSE(overridden.shutdown_behavior_set_explicitly()); + EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, + overridden.shutdown_behavior()); + EXPECT_FALSE(overridden.may_block()); + EXPECT_FALSE(overridden.with_base_sync_primitives()); +} + +TEST(TaskSchedulerTaskTraitsTest, OverrideShutdownBehavior) { + constexpr TaskTraits left = {TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}; + constexpr TaskTraits right = {TaskShutdownBehavior::BLOCK_SHUTDOWN}; + constexpr TaskTraits overridden = TaskTraits::Override(left, right); + EXPECT_FALSE(overridden.priority_set_explicitly()); + EXPECT_EQ(TaskPriority::USER_VISIBLE, overridden.priority()); + EXPECT_TRUE(overridden.shutdown_behavior_set_explicitly()); + EXPECT_EQ(TaskShutdownBehavior::BLOCK_SHUTDOWN, + overridden.shutdown_behavior()); + EXPECT_FALSE(overridden.may_block()); + EXPECT_FALSE(overridden.with_base_sync_primitives()); +} + +TEST(TaskSchedulerTaskTraitsTest, OverrideMayBlock) { + { + constexpr TaskTraits left = {MayBlock()}; + constexpr TaskTraits right = {}; + constexpr TaskTraits overridden = TaskTraits::Override(left, right); + EXPECT_FALSE(overridden.priority_set_explicitly()); + EXPECT_EQ(TaskPriority::USER_VISIBLE, overridden.priority()); + EXPECT_FALSE(overridden.shutdown_behavior_set_explicitly()); + EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, + overridden.shutdown_behavior()); + EXPECT_TRUE(overridden.may_block()); + EXPECT_FALSE(overridden.with_base_sync_primitives()); + } + { + constexpr TaskTraits left = {}; + constexpr TaskTraits right = {MayBlock()}; + constexpr TaskTraits overridden = TaskTraits::Override(left, right); + EXPECT_FALSE(overridden.priority_set_explicitly()); + EXPECT_EQ(TaskPriority::USER_VISIBLE, overridden.priority()); + EXPECT_FALSE(overridden.shutdown_behavior_set_explicitly()); + EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, + overridden.shutdown_behavior()); + EXPECT_TRUE(overridden.may_block()); + EXPECT_FALSE(overridden.with_base_sync_primitives()); + } +} + +TEST(TaskSchedulerTaskTraitsTest, OverrideWithBaseSyncPrimitives) { + { + constexpr TaskTraits left = {WithBaseSyncPrimitives()}; + constexpr TaskTraits right = {}; + constexpr TaskTraits overridden = TaskTraits::Override(left, right); + EXPECT_FALSE(overridden.priority_set_explicitly()); + EXPECT_EQ(TaskPriority::USER_VISIBLE, overridden.priority()); + EXPECT_FALSE(overridden.shutdown_behavior_set_explicitly()); + EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, + overridden.shutdown_behavior()); + EXPECT_FALSE(overridden.may_block()); + EXPECT_TRUE(overridden.with_base_sync_primitives()); + } + { + constexpr TaskTraits left = {}; + constexpr TaskTraits right = {WithBaseSyncPrimitives()}; + constexpr TaskTraits overridden = TaskTraits::Override(left, right); + EXPECT_FALSE(overridden.priority_set_explicitly()); + EXPECT_EQ(TaskPriority::USER_VISIBLE, overridden.priority()); + EXPECT_FALSE(overridden.shutdown_behavior_set_explicitly()); + EXPECT_EQ(TaskShutdownBehavior::SKIP_ON_SHUTDOWN, + overridden.shutdown_behavior()); + EXPECT_FALSE(overridden.may_block()); + EXPECT_TRUE(overridden.with_base_sync_primitives()); + } +} + +TEST(TaskSchedulerTaskTraitsTest, OverrideMultipleTraits) { + constexpr TaskTraits left = {MayBlock(), TaskPriority::BACKGROUND, + TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}; + constexpr TaskTraits right = {WithBaseSyncPrimitives(), + TaskPriority::USER_BLOCKING}; + constexpr TaskTraits overridden = TaskTraits::Override(left, right); + EXPECT_TRUE(overridden.priority_set_explicitly()); + EXPECT_EQ(right.priority(), overridden.priority()); + EXPECT_TRUE(overridden.shutdown_behavior_set_explicitly()); + EXPECT_EQ(left.shutdown_behavior(), overridden.shutdown_behavior()); + EXPECT_TRUE(overridden.may_block()); + EXPECT_TRUE(overridden.with_base_sync_primitives()); +} + } // namespace base
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml index e864b66b..5b06714 100644 --- a/build/android/lint/suppressions.xml +++ b/build/android/lint/suppressions.xml
@@ -440,8 +440,6 @@ <issue id="UseCompoundDrawables"> <!-- Upscaling 24dp to 48dp doesn't work as expected with a TextView compound drawable. --> <ignore regexp="chrome/android/java/res/layout/photo_picker_bitmap_view.xml"/> - <!-- TODO(crbug.com/669629): Remove this when the Chromecast dependency on old layout code is removed. --> - <ignore regexp="chromecast/internal/android/prebuilt/settings/res/layout-v17/setup_activity_progress.xml"/> </issue> <issue id="UselessParent"> <ignore regexp="android_webview/tools/system_webview_shell/apk/res/layout/activity_webview_browser.xml"/>
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 183654c..90fbb3cc 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -99,7 +99,9 @@ # branches) optimize_for_fuzzing = false - # Optimize symbol files for maximizing goma cache hit rate. + # Optimize symbol files for maximizing goma cache hit rate. This isn't + # on by default when goma is enabled because setting this to true may make + # it harder to debug binaries. strip_absolute_paths_from_debug_symbols = false }
diff --git a/cc/debug/debug_colors.cc b/cc/debug/debug_colors.cc index db0fbd7..89e3d0bc 100644 --- a/cc/debug/debug_colors.cc +++ b/cc/debug/debug_colors.cc
@@ -78,7 +78,7 @@ return SkColorSetARGB(100, 80, 200, 200); } int DebugColors::HighResTileBorderWidth(float device_scale_factor) { - return Scale(1, device_scale_factor); + return Scale(3, device_scale_factor); } // Low-res tile borders are purple.
diff --git a/cc/paint/discardable_image_map_unittest.cc b/cc/paint/discardable_image_map_unittest.cc index d9ab8fd1..015e539 100644 --- a/cc/paint/discardable_image_map_unittest.cc +++ b/cc/paint/discardable_image_map_unittest.cc
@@ -39,9 +39,8 @@ SkSize scale; }; -sk_sp<PaintRecord> CreateRecording( - const sk_sp<const SkImage>& discardable_image, - const gfx::Rect& visible_rect) { +sk_sp<PaintRecord> CreateRecording(const sk_sp<SkImage>& discardable_image, + const gfx::Rect& visible_rect) { PaintRecorder recorder; PaintCanvas* canvas = recorder.beginRecording(visible_rect.width(), visible_rect.height()); @@ -651,7 +650,7 @@ TEST_F(DiscardableImageMapTest, ClipsImageRects) { gfx::Rect visible_rect(500, 500); - sk_sp<const SkImage> discardable_image = + sk_sp<SkImage> discardable_image = CreateDiscardableImage(gfx::Size(500, 500)); sk_sp<PaintRecord> record = CreateRecording(discardable_image, visible_rect);
diff --git a/cc/paint/paint_image.cc b/cc/paint/paint_image.cc index d4e01f7..846b3bee 100644 --- a/cc/paint/paint_image.cc +++ b/cc/paint/paint_image.cc
@@ -7,14 +7,12 @@ namespace cc { PaintImage::PaintImage() = default; -PaintImage::PaintImage(sk_sp<const SkImage> sk_image, +PaintImage::PaintImage(sk_sp<SkImage> sk_image, AnimationType animation_type, CompletionState completion_state) : sk_image_(std::move(sk_image)), animation_type_(animation_type), - completion_state_(completion_state) { - DCHECK(sk_image_); -} + completion_state_(completion_state) {} PaintImage::PaintImage(const PaintImage& other) = default; PaintImage::PaintImage(PaintImage&& other) = default; PaintImage::~PaintImage() = default;
diff --git a/cc/paint/paint_image.h b/cc/paint/paint_image.h index df0f82ee..a79bcf02 100644 --- a/cc/paint/paint_image.h +++ b/cc/paint/paint_image.h
@@ -21,7 +21,7 @@ enum class CompletionState { UNKNOWN, DONE, PARTIALLY_DONE }; PaintImage(); - explicit PaintImage(sk_sp<const SkImage> sk_image, + explicit PaintImage(sk_sp<SkImage> sk_image, AnimationType animation_type = AnimationType::STATIC, CompletionState completion_state = CompletionState::DONE); PaintImage(const PaintImage& other); @@ -32,13 +32,14 @@ PaintImage& operator=(PaintImage&& other); bool operator==(const PaintImage& other); + explicit operator bool() const { return sk_image_; } - const sk_sp<const SkImage>& sk_image() const { return sk_image_; } + const sk_sp<SkImage>& sk_image() const { return sk_image_; } AnimationType animation_type() const { return animation_type_; } CompletionState completion_state() const { return completion_state_; } private: - sk_sp<const SkImage> sk_image_; + sk_sp<SkImage> sk_image_; AnimationType animation_type_ = AnimationType::UNKNOWN; CompletionState completion_state_ = CompletionState::UNKNOWN; };
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc index dd67f0e..1881a978 100644 --- a/cc/test/fake_content_layer_client.cc +++ b/cc/test/fake_content_layer_client.cc
@@ -16,12 +16,12 @@ namespace cc { -FakeContentLayerClient::ImageData::ImageData(sk_sp<const SkImage> img, +FakeContentLayerClient::ImageData::ImageData(sk_sp<SkImage> img, const gfx::Point& point, const PaintFlags& flags) : image(std::move(img)), point(point), flags(flags) {} -FakeContentLayerClient::ImageData::ImageData(sk_sp<const SkImage> img, +FakeContentLayerClient::ImageData::ImageData(sk_sp<SkImage> img, const gfx::Transform& transform, const PaintFlags& flags) : image(std::move(img)), transform(transform), flags(flags) {}
diff --git a/cc/test/fake_content_layer_client.h b/cc/test/fake_content_layer_client.h index d35f8b7..b644087 100644 --- a/cc/test/fake_content_layer_client.h +++ b/cc/test/fake_content_layer_client.h
@@ -24,15 +24,15 @@ class FakeContentLayerClient : public ContentLayerClient { public: struct ImageData { - ImageData(sk_sp<const SkImage> image, + ImageData(sk_sp<SkImage> image, const gfx::Point& point, const PaintFlags& flags); - ImageData(sk_sp<const SkImage> image, + ImageData(sk_sp<SkImage> image, const gfx::Transform& transform, const PaintFlags& flags); ImageData(const ImageData& other); ~ImageData(); - sk_sp<const SkImage> image; + sk_sp<SkImage> image; gfx::Point point; gfx::Transform transform; PaintFlags flags; @@ -59,14 +59,14 @@ draw_rects_.push_back(std::make_pair(rect, flags)); } - void add_draw_image(sk_sp<const SkImage> image, + void add_draw_image(sk_sp<SkImage> image, const gfx::Point& point, const PaintFlags& flags) { ImageData data(std::move(image), point, flags); draw_images_.push_back(data); } - void add_draw_image_with_transform(sk_sp<const SkImage> image, + void add_draw_image_with_transform(sk_sp<SkImage> image, const gfx::Transform& transform, const PaintFlags& flags) { ImageData data(std::move(image), transform, flags);
diff --git a/cc/test/fake_recording_source.h b/cc/test/fake_recording_source.h index 57142534..90711128 100644 --- a/cc/test/fake_recording_source.h +++ b/cc/test/fake_recording_source.h
@@ -99,17 +99,17 @@ client_.add_draw_rectf(rect, flags); } - void add_draw_image(sk_sp<const SkImage> image, const gfx::Point& point) { + void add_draw_image(sk_sp<SkImage> image, const gfx::Point& point) { client_.add_draw_image(std::move(image), point, default_flags_); } - void add_draw_image_with_transform(sk_sp<const SkImage> image, + void add_draw_image_with_transform(sk_sp<SkImage> image, const gfx::Transform& transform) { client_.add_draw_image_with_transform(std::move(image), transform, default_flags_); } - void add_draw_image_with_flags(sk_sp<const SkImage> image, + void add_draw_image_with_flags(sk_sp<SkImage> image, const gfx::Point& point, const PaintFlags& flags) { client_.add_draw_image(std::move(image), point, flags);
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 342678d..df7b1cf 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -374,6 +374,7 @@ <dimen name="photo_picker_label_gap">10dp</dimen> <dimen name="photo_picker_tile_min_size">100dp</dimen> <dimen name="photo_picker_tile_gap">4dp</dimen> + <dimen name="photo_picker_grainy_thumbnail_size">12dp</dimen> <!-- Account chooser dialog dimensions --> <dimen name="account_chooser_dialog_margin">24dp</dimen> @@ -471,7 +472,7 @@ <!-- Context Menu Dimensions --> <dimen name="context_menu_header_image_min_size">56dp</dimen> <dimen name="context_menu_header_image_max_size">56dp</dimen> - + <!-- Divider Dimensions --> <dimen name="divider_height">1dp</dimen>
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 771ca11f..3a91d289 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -117,6 +117,7 @@ import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.chrome.browser.vr_shell.VrShellDelegate; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetMetrics; import org.chromium.chrome.browser.widget.emptybackground.EmptyBackgroundViewWrapper; import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager; import org.chromium.chrome.browser.widget.textbubble.ViewAnchoredTextBubble; @@ -992,6 +993,8 @@ if (getBottomSheet() != null) { // Either a new tab is opening, a tab is being clobbered, or a tab is being brought // to the front. In all scenarios, the bottom sheet should be closed. + getBottomSheet().getBottomSheetMetrics().setSheetCloseReason( + BottomSheetMetrics.CLOSED_BY_NAVIGATION); getBottomSheet().setSheetState(BottomSheet.SHEET_STATE_PEEK, true); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ReaderModeInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ReaderModeInfoBar.java new file mode 100644 index 0000000..23e115f2 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ReaderModeInfoBar.java
@@ -0,0 +1,84 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.infobar; + +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.TextView; + +import org.chromium.base.ApiCompatibilityUtils; +import org.chromium.base.annotations.CalledByNative; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.dom_distiller.ReaderModeManager; +import org.chromium.chrome.browser.tab.Tab; + +/** + * This is the InfoBar implementation of the Reader Mode UI. This is used in place of the + * {@link OverlayPanel} implementation when Chrome Home is enabled. + */ +public class ReaderModeInfoBar extends InfoBar { + /** A handle to the {@link ReaderModeManager} to trigger page navigations. */ + private static ReaderModeManager sManager; + + /** + * Default constructor. + */ + private ReaderModeInfoBar() { + super(R.drawable.infobar_mobile_friendly, null, null); + } + + @Override + protected boolean usesCompactLayout() { + return true; + } + + @Override + protected void createCompactLayoutContent(InfoBarCompactLayout layout) { + TextView prompt = new TextView(getContext()); + prompt.setText(R.string.reader_view_text); + prompt.setSingleLine(); + prompt.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getContext().getResources().getDimension(R.dimen.infobar_text_size)); + prompt.setTextColor( + ApiCompatibilityUtils.getColor(layout.getResources(), R.color.default_text_color)); + prompt.setGravity(Gravity.CENTER_VERTICAL); + + prompt.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // TODO(mdjones): Trigger navigation from manager. + } + }); + + layout.addContent(prompt, 1f); + } + + public void onCloseButtonClicked() { + super.onCloseButtonClicked(); + + // TODO(mdjones): Notifiy the manager that the infobar was closed. + } + + /** + * Create and show the Reader Mode {@link InfoBar}. + * @param tab The tab that the {@link InfoBar} should be shown in. + * @param manager The {@link ReaderModeManager} for this instance of Chrome. + */ + public static void showReaderModeInfoBar(Tab tab, ReaderModeManager manager) { + sManager = manager; + nativeCreate(tab); + } + + /** + * @return An instance of the {@link ReaderModeInfoBar}. + */ + @CalledByNative + private static ReaderModeInfoBar create() { + return new ReaderModeInfoBar(); + } + + private static native void nativeCreate(Tab tab); +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java index 1d4204c61..f93b4396 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
@@ -90,6 +90,16 @@ "WebApk.Install.GooglePlayInstallResult", result, GOOGLE_PLAY_INSTALL_RESULT_MAX); } + /** + * Records whether updating a WebAPK from Google Play succeeded. If not, records the reason + * that the update failed. + */ + public static void recordGooglePlayUpdateResult(int result) { + assert result >= 0 && result < GOOGLE_PLAY_INSTALL_RESULT_MAX; + RecordHistogram.recordEnumeratedHistogram( + "WebApk.Update.GooglePlayUpdateResult", result, GOOGLE_PLAY_INSTALL_RESULT_MAX); + } + /** Records the duration of a WebAPK session (from launch/foreground to background). */ public static void recordWebApkSessionDuration(long duration) { RecordHistogram.recordLongTimesHistogram(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java index 0b4018db..214fb2ec 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java
@@ -96,6 +96,8 @@ // If the NTP is loading, the sheet state will be set to SHEET_STATE_HALF. if (TextUtils.equals(tab.getUrl(), getUrl())) return; + mBottomSheet.getBottomSheetMetrics().setSheetCloseReason( + BottomSheetMetrics.CLOSED_BY_NAVIGATION); mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true); } }; @@ -166,6 +168,8 @@ mCloseButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + mBottomSheet.getBottomSheetMetrics().setSheetCloseReason( + BottomSheetMetrics.CLOSED_BY_NTP_CLOSE_BUTTON); mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true); if (mShowOverviewOnClose && getLayoutManager() != null) { getLayoutManager().showOverview(false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java index 7909168..4396fb2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -41,6 +41,7 @@ import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver; import org.chromium.chrome.browser.suggestions.SuggestionsEventReporter; import org.chromium.chrome.browser.suggestions.SuggestionsEventReporterBridge; +import org.chromium.chrome.browser.suggestions.SuggestionsMetrics; import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate; import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegateImpl; import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegateImpl; @@ -343,7 +344,7 @@ @Override public void onHidden(Tab tab) { - if (mIsLoaded) recordNTPInteractionTime(); + if (mIsLoaded) recordNTPHidden(); } @Override @@ -496,11 +497,14 @@ private void recordNTPShown() { mLastShownTimeNs = System.nanoTime(); RecordUserAction.record("MobileNTPShown"); + SuggestionsMetrics.recordSurfaceVisible(); } - private void recordNTPInteractionTime() { + /** Records UMA for the NTP being hidden and the time spent on it. */ + private void recordNTPHidden() { RecordHistogram.recordMediumTimesHistogram( "NewTabPage.TimeSpent", System.nanoTime() - mLastShownTimeNs, TimeUnit.NANOSECONDS); + SuggestionsMetrics.recordSurfaceHidden(); } /** @@ -548,7 +552,7 @@ assert !mIsDestroyed; assert !ViewCompat .isAttachedToWindow(getView()) : "Destroy called before removed from window"; - if (mIsLoaded && !mTab.isHidden()) recordNTPInteractionTime(); + if (mIsLoaded && !mTab.isHidden()) recordNTPHidden(); if (mSnippetsBridge != null) { mSnippetsBridge.onDestroy();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java index 5b48f40..781c1cf5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java
@@ -18,6 +18,7 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.UrlUtilities; import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.ui.base.PageTransition; @@ -363,7 +364,7 @@ assert !NewTabPage.isNTPUrl(url); return; } - if (NewTabPage.isNTPUrl(url)) { + if (NewTabPage.isNTPUrl(url) && !FeatureUtilities.isChromeHomeEnabled()) { RecordUserAction.record("MobileNTP.Snippets.VisitEndBackInNTP"); } endRecording(tab);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java index 8738ba3..d188446 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ActionItem.java
@@ -11,6 +11,7 @@ import org.chromium.chrome.browser.ntp.ContextMenuManager; import org.chromium.chrome.browser.ntp.snippets.CategoryInt; import org.chromium.chrome.browser.suggestions.ContentSuggestionsAdditionalAction; +import org.chromium.chrome.browser.suggestions.SuggestionsMetrics; import org.chromium.chrome.browser.suggestions.SuggestionsRanker; import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView; import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate; @@ -65,6 +66,7 @@ switch (mCategoryInfo.getAdditionalAction()) { case ContentSuggestionsAdditionalAction.VIEW_ALL: + SuggestionsMetrics.recordActionViewAll(); mCategoryInfo.performViewAllAction(uiDelegate.getNavigationDelegate()); return; case ContentSuggestionsAdditionalAction.FETCH:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusCardViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusCardViewHolder.java index 8d88eef..b36f4c8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusCardViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/StatusCardViewHolder.java
@@ -13,6 +13,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.ntp.ContextMenuManager; +import org.chromium.chrome.browser.suggestions.SuggestionsMetrics; import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView; import org.chromium.chrome.browser.widget.displaystyle.UiConfig; @@ -75,6 +76,7 @@ @Override public void onClick(View v) { + SuggestionsMetrics.recordCardActionTapped(); item.performAction(v.getContext()); } });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java index 0181087..3b3f9c51 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
@@ -40,6 +40,7 @@ import org.chromium.chrome.browser.ntp.cards.ImpressionTracker; import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder; import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo; +import org.chromium.chrome.browser.suggestions.SuggestionsMetrics; import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView; import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate; import org.chromium.chrome.browser.widget.TintedImageView; @@ -147,6 +148,7 @@ @Override public void onCardTapped() { + SuggestionsMetrics.recordCardTapped(); int windowDisposition = WindowOpenDisposition.CURRENT_TAB; mUiDelegate.getEventReporter().onSuggestionOpened( mArticle, windowDisposition, mUiDelegate.getSuggestionsRanker());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java index c1dff32..cd995bab 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java
@@ -171,7 +171,7 @@ @Override public void onUrlUpdated(Tab tab) { Log.d(TAG, "onUrlUpdated"); - if (!isOfflinePage(tab)) { + if (!OfflinePageUtils.isOfflinePage(tab)) { stopObservingTab(tab); } else { if (isObservingTab(tab)) { @@ -184,7 +184,7 @@ } void startObservingTab(Tab tab) { - if (!isOfflinePage(tab)) return; + if (!OfflinePageUtils.isOfflinePage(tab)) return; mCurrentTab = tab; @@ -240,15 +240,16 @@ // Methods from ConnectionTypeObserver. @Override public void onConnectionTypeChanged(int connectionType) { - Log.d(TAG, "Got connectivity event, connectionType: " + connectionType + ", is connected: " - + isConnected() + ", controller: " + mSnackbarController); + Log.d(TAG, + "Got connectivity event, connectionType: " + connectionType + ", is connected: " + + OfflinePageUtils.isConnected() + ", controller: " + mSnackbarController); maybeShowReloadSnackbar(mCurrentTab, true); // Since we are loosing the connection, next time we connect, we still want to show a // snackbar. This works in event that onConnectionTypeChanged happens, while Chrome is not // visible. Making it visible after that would not trigger the snackbar, even though // connection state changed. See http://crbug.com/651410 - if (!isConnected()) { + if (!OfflinePageUtils.isConnected()) { for (TabState tabState : mObservedTabs.values()) { tabState.wasSnackbarSeen = false; } @@ -275,26 +276,11 @@ return mIsObservingNetworkChanges; } - @VisibleForTesting - boolean isConnected() { - return OfflinePageUtils.isConnected(); - } - - @VisibleForTesting - boolean isShowingOfflinePreview(Tab tab) { - return OfflinePageUtils.isShowingOfflinePreview(tab); - } - - @VisibleForTesting - boolean isOfflinePage(Tab tab) { - return OfflinePageUtils.isOfflinePage(tab); - } - void maybeShowReloadSnackbar(Tab tab, boolean isNetworkEvent) { // Exclude Offline Previews, as there is a seperate UI for previews. - if (tab == null || tab.isFrozen() || tab.isHidden() || !isOfflinePage(tab) - || isShowingOfflinePreview(tab) || !isConnected() || !isLoadedTab(tab) - || (wasSnackbarSeen(tab) && !isNetworkEvent)) { + if (tab == null || tab.isFrozen() || tab.isHidden() || !OfflinePageUtils.isOfflinePage(tab) + || OfflinePageUtils.isShowingOfflinePreview(tab) || !OfflinePageUtils.isConnected() + || !isLoadedTab(tab) || (wasSnackbarSeen(tab) && !isNetworkEvent)) { // Conditions to show a snackbar are not met. return; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java index fb0f227..54e0c0e2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
@@ -76,7 +76,8 @@ // Used instead of the constant so tests can override the value. private static int sSnackbarDurationMs = DEFAULT_SNACKBAR_DURATION_MS; - private static OfflinePageUtils sInstance; + /** Instance carrying actual implementation of utility methods. */ + private static Internal sInstance; private static File sOfflineSharingDirectory; @@ -88,6 +89,88 @@ private static Map<ChromeActivity, RecentTabTracker> sTabModelObservers = new HashMap<>(); /** + * Interface for implementation of offline page utilities, that can be implemented for testing. + * We are using an internal interface, so that instance methods can have the same names as + * static methods. + */ + @VisibleForTesting + interface Internal { + /** Returns offline page bridge for specified profile. */ + OfflinePageBridge getOfflinePageBridge(Profile profile); + + /** Returns whether the network is connected. */ + boolean isConnected(); + + /** + * Checks if an offline page is shown for the tab. + * @param tab The tab to be reloaded. + * @return True if the offline page is opened. + */ + boolean isOfflinePage(Tab tab); + + /** + * Returns whether the tab is showing offline preview. + * @param tab The current tab. + */ + boolean isShowingOfflinePreview(Tab tab); + + /** + * Shows the "reload" snackbar for the given tab. + * @param context The application context. + * @param snackbarManager Class that shows the snackbar. + * @param snackbarController Class to control the snackbar. + * @param tabId Id of a tab that the snackbar is related to. + */ + void showReloadSnackbar(Context context, SnackbarManager snackbarManager, + final SnackbarController snackbarController, int tabId); + } + + private static class OfflinePageUtilsImpl implements Internal { + @Override + public OfflinePageBridge getOfflinePageBridge(Profile profile) { + return OfflinePageBridge.getForProfile(profile); + } + + @Override + public boolean isConnected() { + return NetworkChangeNotifier.isOnline(); + } + + @Override + public boolean isOfflinePage(Tab tab) { + WebContents webContents = tab.getWebContents(); + if (webContents == null) return false; + OfflinePageBridge offlinePageBridge = + getInstance().getOfflinePageBridge(tab.getProfile()); + if (offlinePageBridge == null) return false; + return offlinePageBridge.isOfflinePage(webContents); + } + + @Override + public boolean isShowingOfflinePreview(Tab tab) { + OfflinePageBridge offlinePageBridge = getOfflinePageBridge(tab.getProfile()); + if (offlinePageBridge == null) return false; + return offlinePageBridge.isShowingOfflinePreview(tab.getWebContents()); + } + + @Override + public void showReloadSnackbar(Context context, SnackbarManager snackbarManager, + final SnackbarController snackbarController, int tabId) { + if (tabId == Tab.INVALID_TAB_ID) return; + + Log.d(TAG, "showReloadSnackbar called with controller " + snackbarController); + Snackbar snackbar = + Snackbar.make(context.getString(R.string.offline_pages_viewing_offline_page), + snackbarController, Snackbar.TYPE_ACTION, + Snackbar.UMA_OFFLINE_PAGE_RELOAD) + .setSingleLine(false) + .setAction(context.getString(R.string.reload), tabId); + snackbar.setDuration(sSnackbarDurationMs); + snackbarManager.showSnackbar(snackbar); + } + } + + /** * Contains values from the histogram enum OfflinePagesTabRestoreType used for reporting the * OfflinePages.TabRestore metric. */ @@ -107,9 +190,9 @@ public static final int COUNT = 10; } - private static OfflinePageUtils getInstance() { + private static Internal getInstance() { if (sInstance == null) { - sInstance = new OfflinePageUtils(); + sInstance = new OfflinePageUtilsImpl(); } return sInstance; } @@ -128,11 +211,9 @@ return Environment.getDataDirectory().getTotalSpace(); } - /** - * Returns true if the network is connected. - */ + /** Returns whether the network is connected. */ public static boolean isConnected() { - return NetworkChangeNotifier.isOnline(); + return getInstance().isConnected(); } /* @@ -203,25 +284,21 @@ OfflinePageTabObserver.addObserverForTab(tab); } + protected void showReloadSnackbarInternal(Context context, SnackbarManager snackbarManager, + final SnackbarController snackbarController, int tabId) {} + /** * Shows the "reload" snackbar for the given tab. - * @param activity The activity owning the tab. - * @param snackbarController Class to show the snackbar. + * @param context The application context. + * @param snackbarManager Class that shows the snackbar. + * @param snackbarController Class to control the snackbar. + * @param tabId Id of a tab that the snackbar is related to. */ public static void showReloadSnackbar(Context context, SnackbarManager snackbarManager, final SnackbarController snackbarController, int tabId) { - if (tabId == Tab.INVALID_TAB_ID) return; - - Log.d(TAG, "showReloadSnackbar called with controller " + snackbarController); - Snackbar snackbar = - Snackbar.make(context.getString(R.string.offline_pages_viewing_offline_page), - snackbarController, Snackbar.TYPE_ACTION, Snackbar.UMA_OFFLINE_PAGE_RELOAD) - .setSingleLine(false).setAction(context.getString(R.string.reload), tabId); - snackbar.setDuration(sSnackbarDurationMs); - snackbarManager.showSnackbar(snackbar); + getInstance().showReloadSnackbar(context, snackbarManager, snackbarController, tabId); } - /** * Records UMA data when the Offline Pages Background Load service awakens. * @param context android context @@ -558,9 +635,7 @@ * @param tab The current tab. */ public static boolean isShowingOfflinePreview(Tab tab) { - OfflinePageBridge offlinePageBridge = getInstance().getOfflinePageBridge(tab.getProfile()); - if (offlinePageBridge == null) return false; - return offlinePageBridge.isShowingOfflinePreview(tab.getWebContents()); + return getInstance().isShowingOfflinePreview(tab); } /** @@ -569,11 +644,7 @@ * @return True if the offline page is opened. */ public static boolean isOfflinePage(Tab tab) { - WebContents webContents = tab.getWebContents(); - if (webContents == null) return false; - OfflinePageBridge offlinePageBridge = getInstance().getOfflinePageBridge(tab.getProfile()); - if (offlinePageBridge == null) return false; - return offlinePageBridge.isOfflinePage(webContents); + return getInstance().isOfflinePage(tab); } /** @@ -617,10 +688,6 @@ tab.loadUrl(params); } - protected OfflinePageBridge getOfflinePageBridge(Profile profile) { - return OfflinePageBridge.getForProfile(profile); - } - /** * Tracks tab creation and closure for the Recent Tabs feature. UI needs to stop showing * recent offline pages as soon as the tab is closed. The TabModel is used to get profile @@ -792,7 +859,7 @@ } @VisibleForTesting - static void setInstanceForTesting(OfflinePageUtils instance) { + static void setInstanceForTesting(Internal instance) { sInstance = instance; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java index 6045de0..ed2cbb94 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -944,7 +944,13 @@ // (since we apply spans when the URL is not focused, we only optimize this when the // URL is being edited). if (!TextUtils.equals(getEditableText(), text)) { - super.setText(text, type); + // Certain OEM implementations of setText trigger disk reads. crbug.com/633298 + StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); + try { + super.setText(text, type); + } finally { + StrictMode.setThreadPolicy(oldPolicy); + } } // Verify the autocomplete is still valid after the text change.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/BitmapScalerTask.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/BitmapScalerTask.java new file mode 100644 index 0000000..2fe1519 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/BitmapScalerTask.java
@@ -0,0 +1,56 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.photo_picker; + +import android.graphics.Bitmap; +import android.os.AsyncTask; +import android.util.LruCache; + +import org.chromium.base.ThreadUtils; + +/** + * A worker task to scale bitmaps in the background. + */ +class BitmapScalerTask extends AsyncTask<Bitmap, Void, Bitmap> { + private final LruCache<String, Bitmap> mCache; + private final String mFilePath; + private final int mSize; + + /** + * A BitmapScalerTask constructor. + */ + public BitmapScalerTask(LruCache<String, Bitmap> cache, String filePath, int size) { + mCache = cache; + mFilePath = filePath; + mSize = size; + } + + /** + * Scales the image provided. Called on a non-UI thread. + * @param params Ignored, do not use. + * @return A sorted list of images (by last-modified first). + */ + @Override + protected Bitmap doInBackground(Bitmap... bitmaps) { + assert !ThreadUtils.runningOnUiThread(); + + if (isCancelled()) return null; + + return BitmapUtils.scale(bitmaps[0], mSize, false); + } + + /** + * Communicates the results back to the client. Called on the UI thread. + * @param result The resulting scaled bitmap. + */ + @Override + protected void onPostExecute(Bitmap result) { + if (isCancelled()) { + return; + } + + mCache.put(mFilePath, result); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/BitmapUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/BitmapUtils.java index ddad8aa..f1e7620 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/BitmapUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/BitmapUtils.java
@@ -107,4 +107,20 @@ if (height > size) y = (height - size) / 2; return Bitmap.createBitmap(bitmap, x, y, size, size); } + + /** + * Scales a |bitmap| to a certain size. + * @param bitmap The bitmap to scale. + * @param scaleMaxSize What to scale it to. + * @param filter True if the source should be filtered. + * @return The resulting scaled bitmap. + */ + public static Bitmap scale(Bitmap bitmap, float scaleMaxSize, boolean filter) { + float ratio = Math.min((float) scaleMaxSize / bitmap.getWidth(), + (float) scaleMaxSize / bitmap.getHeight()); + int height = Math.round(ratio * bitmap.getHeight()); + int width = Math.round(ratio * bitmap.getWidth()); + + return Bitmap.createScaledBitmap(bitmap, width, height, filter); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapViewHolder.java index b4aa77b..4dd0886 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerBitmapViewHolder.java
@@ -4,10 +4,14 @@ package org.chromium.chrome.browser.photo_picker; +import android.content.res.Resources; import android.graphics.Bitmap; +import android.os.AsyncTask; import android.support.v7.widget.RecyclerView.ViewHolder; import android.text.TextUtils; +import org.chromium.chrome.R; + import java.util.List; /** @@ -41,6 +45,17 @@ return; } + if (mCategoryView.getHighResBitmaps().get(filePath) == null) { + mCategoryView.getHighResBitmaps().put(filePath, bitmap); + } + + if (mCategoryView.getLowResBitmaps().get(filePath) == null) { + Resources resources = mItemView.getContext().getResources(); + new BitmapScalerTask(mCategoryView.getLowResBitmaps(), filePath, + resources.getDimensionPixelSize(R.dimen.photo_picker_grainy_thumbnail_size)) + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, bitmap); + } + if (!TextUtils.equals(mBitmapDetails.getFilePath(), filePath)) { return; } @@ -67,12 +82,24 @@ return; } - // TODO(finnur): Use cached image, if available. - - mItemView.initialize(mBitmapDetails, null, true); + String filePath = mBitmapDetails.getFilePath(); + Bitmap original = mCategoryView.getHighResBitmaps().get(filePath); + if (original != null) { + mItemView.initialize(mBitmapDetails, original, false); + return; + } int size = mCategoryView.getImageSize(); - mCategoryView.getDecoderServiceHost().decodeImage(mBitmapDetails.getFilePath(), size, this); + Bitmap placeholder = mCategoryView.getLowResBitmaps().get(filePath); + if (placeholder != null) { + // For performance stats see http://crbug.com/719919. + placeholder = BitmapUtils.scale(placeholder, size, false); + mItemView.initialize(mBitmapDetails, placeholder, true); + } else { + mItemView.initialize(mBitmapDetails, null, true); + } + + mCategoryView.getDecoderServiceHost().decodeImage(filePath, size, this); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java index 62e4d58..84c2dda 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java
@@ -6,10 +6,12 @@ import android.app.Activity; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.Rect; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar.OnMenuItemClickListener; +import android.util.LruCache; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -30,6 +32,8 @@ public class PickerCategoryView extends RelativeLayout implements FileEnumWorkerTask.FilesEnumeratedCallback, RecyclerView.RecyclerListener, DecoderServiceHost.ServiceReadyCallback, OnMenuItemClickListener { + private static final int KILOBYTE = 1024; + // The dialog that owns us. private PhotoPickerDialog mDialog; @@ -60,6 +64,14 @@ // The {@link SelectionDelegate} keeping track of which images are selected. private SelectionDelegate<PickerBitmap> mSelectionDelegate; + // A low-resolution cache for images. Helpful for cache misses from the high-resolution cache + // to avoid showing gray squares (we show pixelated versions instead until image can be loaded + // off disk, which is much less jarring). + private LruCache<String, Bitmap> mLowResBitmaps; + + // A high-resolution cache for images. + private LruCache<String, Bitmap> mHighResBitmaps; + /** * The number of columns to show. Note: mColumns and mPadding (see below) should both be even * numbers or both odd, not a mix (the column padding will not be of uniform thickness if they @@ -118,7 +130,11 @@ mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.addItemDecoration(new GridSpacingItemDecoration(mColumns, mPadding)); - // TODO(finnur): Implement caching. + final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / KILOBYTE); + final int cacheSizeLarge = maxMemory / 2; // 1/2 of the available memory. + final int cacheSizeSmall = maxMemory / 8; // 1/8th of the available memory. + mLowResBitmaps = new LruCache<String, Bitmap>(cacheSizeSmall); + mHighResBitmaps = new LruCache<String, Bitmap>(cacheSizeLarge); } /** @@ -222,6 +238,14 @@ return mDecoderServiceHost; } + public LruCache<String, Bitmap> getLowResBitmaps() { + return mLowResBitmaps; + } + + public LruCache<String, Bitmap> getHighResBitmaps() { + return mHighResBitmaps; + } + public boolean isMultiSelectAllowed() { return mMultiSelectionAllowed; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java new file mode 100644 index 0000000..4ed88a7 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java
@@ -0,0 +1,49 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.rlz; + +import android.text.TextUtils; + +import org.chromium.base.Callback; +import org.chromium.base.ContextUtils; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.chrome.browser.identity.SettingsSecureBasedIdentificationGenerator; +import org.chromium.chrome.browser.profiles.Profile; + +import java.util.List; +import java.util.Locale; + +/** + * A handler for revenue related pings that needs customized brand and event codes. + */ +@JNINamespace("chrome::android") +public class RlzPingHandler { + private static final String ID_SALT = "RLZSalt"; + + private RlzPingHandler() {} + + /** + * Generates a network ping with multiple events and a custom brand code. The application id is + * always "chrome" and the language uses the default system language. The machine id is + * a 50 character long generated string through + * {@link SettingsSecureBasedIdentificationGenerator}. + * @param brand The custom brand to be used for the ping. + * @param events The list of events that should be sent with the ping. + * @param callback A callback to be notified of the validity of the response received. + */ + public static void startPing( + String brand, List<String> events, final Callback<Boolean> callback) { + String id = + new SettingsSecureBasedIdentificationGenerator(ContextUtils.getApplicationContext()) + .getUniqueId(ID_SALT); + id = id + id.substring(0, 50 - id.length() - 1); + + nativeStartPing(Profile.getLastUsedProfile().getOriginalProfile(), brand, + Locale.getDefault().getLanguage(), TextUtils.join(",", events), id, callback); + } + + private static native void nativeStartPing(Profile profile, String brand, String language, + String events, String id, Callback<Boolean> callback); +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java index 9fd7a66cd5..6c10e4a5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -35,9 +35,6 @@ /** * Provides content to be displayed inside of the Home tab of bottom sheet. - * - * TODO(dgn): If the bottom sheet view is not recreated across tab changes, it will have to be - * notified of it, at least when it is pulled up on the new tab. */ public class SuggestionsBottomSheetContent implements BottomSheet.BottomSheetContent { private static SuggestionsSource sSuggestionsSourceForTesting; @@ -92,17 +89,19 @@ @Override public void onSheetOpened() { mRecyclerView.scrollToPosition(0); - - // TODO(https://crbug.com/689962) Ensure this call does not discard all suggestions - // every time the sheet is opened. - adapter.refreshSuggestions(); - mSuggestionsUiDelegate.getEventReporter().onSurfaceOpened(); + prepareSuggestionsForReveal(adapter); } + + @Override + public void onSheetClosed() { + SuggestionsMetrics.recordSurfaceHidden(); + } + }; mBottomSheet = activity.getBottomSheet(); mBottomSheet.addObserver(mBottomSheetObserver); - adapter.refreshSuggestions(); - mSuggestionsUiDelegate.getEventReporter().onSurfaceOpened(); + + if (mBottomSheet.isSheetOpen()) prepareSuggestionsForReveal(adapter); mShadowView = (FadingShadowView) mView.findViewById(R.id.shadow); mShadowView.init( @@ -164,6 +163,13 @@ return BottomSheetContentController.TYPE_SUGGESTIONS; } + /** Called when the UI is revlealed, prepares the list of suggestions. */ + private void prepareSuggestionsForReveal(NewTabPageAdapter adapter) { + adapter.refreshSuggestions(); + mSuggestionsUiDelegate.getEventReporter().onSurfaceOpened(); + SuggestionsMetrics.recordSurfaceVisible(); + } + public static void setSuggestionsSourceForTesting(SuggestionsSource suggestionsSource) { sSuggestionsSourceForTesting = suggestionsSource; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java new file mode 100644 index 0000000..fa64959c --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java
@@ -0,0 +1,46 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.suggestions; + +import org.chromium.base.metrics.RecordUserAction; + +/** + * Exposes methods to report suggestions related events, for UMA or Fetch scheduling purposes. + */ +public abstract class SuggestionsMetrics { + private SuggestionsMetrics() {} + + // UI Element interactions + + public static void recordSurfaceVisible() { + RecordUserAction.record("Suggestions.SurfaceVisible"); + } + + public static void recordSurfaceHidden() { + RecordUserAction.record("Suggestions.SurfaceHidden"); + } + + public static void recordTileTapped() { + RecordUserAction.record("Suggestions.Tile.Tapped"); + } + + public static void recordCardTapped() { + RecordUserAction.record("Suggestions.Card.Tapped"); + } + + public static void recordCardActionTapped() { + RecordUserAction.record("Suggestions.Card.ActionTapped"); + } + + public static void recordCardSwipedAway() { + RecordUserAction.record("Suggestions.Card.SwipedAway"); + } + + // Effect/Purpose of the interactions. Most are recorded in |content_suggestions_metrics.h| + + public static void recordActionViewAll() { + RecordUserAction.record("Suggestions.Category.ViewAll"); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java index 2f521566..6fee021f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsRecyclerView.java
@@ -329,6 +329,7 @@ @Override public void onSwiped(ViewHolder viewHolder, int direction) { onItemDismissStarted(viewHolder); + SuggestionsMetrics.recordCardSwipedAway(); dismissItemInternal(viewHolder); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java index 460bb3b..c3d0f644 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
@@ -25,7 +25,6 @@ import org.chromium.base.Callback; import org.chromium.base.Log; import org.chromium.base.VisibleForTesting; -import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback; @@ -441,6 +440,7 @@ Tile tile = getTile(mUrl); if (tile == null) return; + SuggestionsMetrics.recordTileTapped(); mTileGroupDelegate.openMostVisitedItem(WindowOpenDisposition.CURRENT_TAB, tile); } @@ -487,8 +487,6 @@ @Override public void onResult(String restoredUrl) { mPendingInsertionUrl = restoredUrl; - - RecordUserAction.record("Suggestions.Tile.RemovalUndone"); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java index da233f30..cd3903aa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java
@@ -153,7 +153,6 @@ } private void recordOpenedTile(Tile tile) { - // TODO(mvanouwerkerk): Fix metrics to distinguish NTP from Home. NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_MOST_VISITED_TILE); RecordUserAction.record("MobileNTPMostVisited"); NewTabPageUma.recordExplicitUserNavigation(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java index 437c735..3cc5f37 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -340,6 +340,9 @@ @SheetState int targetState = getTargetSheetState( getSheetOffsetFromBottom() + getFlingDistance(-velocityY), -velocityY); + if (targetState == SHEET_STATE_PEEK) { + mMetrics.setSheetCloseReason(BottomSheetMetrics.CLOSED_BY_SWIPE); + } setSheetState(targetState, true); mIsScrolling = false; @@ -435,6 +438,9 @@ @SheetState int targetState = getTargetSheetState(getSheetOffsetFromBottom(), currentVelocity); + if (targetState == SHEET_STATE_PEEK) { + mMetrics.setSheetCloseReason(BottomSheetMetrics.CLOSED_BY_SWIPE); + } setSheetState(targetState, true); } } @@ -584,6 +590,7 @@ } // In all non-native cases, minimize the sheet. + mMetrics.setSheetCloseReason(BottomSheetMetrics.CLOSED_BY_NAVIGATION); setSheetState(SHEET_STATE_PEEK, true); assert mTabModelSelector != null; @@ -1119,6 +1126,7 @@ @Override public void onFadingViewClick() { + mMetrics.setSheetCloseReason(BottomSheetMetrics.CLOSED_BY_TAP_SCRIM); setSheetState(SHEET_STATE_PEEK, true); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java index e5136e0..8cbbd17 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetMetrics.java
@@ -32,12 +32,29 @@ public static final int OPENED_BY_EXPAND_BUTTON = 3; private static final int OPENED_BY_BOUNDARY = 4; + /** The different ways that the bottom sheet can be closed. */ + @IntDef({CLOSED_BY_NONE, CLOSED_BY_SWIPE, CLOSED_BY_NTP_CLOSE_BUTTON, CLOSED_BY_TAP_SCRIM, + CLOSED_BY_NAVIGATION}) + public @interface SheetCloseReason {} + private static final int CLOSED_BY_NONE = -1; + public static final int CLOSED_BY_SWIPE = 0; + public static final int CLOSED_BY_NTP_CLOSE_BUTTON = 1; + public static final int CLOSED_BY_TAP_SCRIM = 2; + public static final int CLOSED_BY_NAVIGATION = 3; + /** Whether the sheet is currently open. */ private boolean mIsSheetOpen; /** The last {@link BottomSheetContent} that was displayed. */ private BottomSheetContent mLastContent; + /** + * The current reason the sheet might become closed. This may change before the sheet actually + * reaches the closed state. + */ + @SheetCloseReason + private int mSheetCloseReason; + /** When this class was created. Used as a proxy for when the app was started. */ private long mCreationTime; @@ -54,7 +71,6 @@ @Override public void onSheetOpened() { mIsSheetOpen = true; - RecordUserAction.record("Android.ChromeHome.Opened"); boolean isFirstOpen = mLastOpenTime == 0; mLastOpenTime = System.currentTimeMillis(); @@ -72,7 +88,8 @@ @Override public void onSheetClosed() { mIsSheetOpen = false; - RecordUserAction.record("Android.ChromeHome.Closed"); + recordSheetCloseReason(mSheetCloseReason); + mSheetCloseReason = CLOSED_BY_NONE; mLastCloseTime = System.currentTimeMillis(); RecordHistogram.recordMediumTimesHistogram("Android.ChromeHome.DurationOpen", @@ -115,11 +132,62 @@ } /** + * Set the reason the bottom sheet is currently closing. This value is not recorded until after + * the sheet is actually closed. + * @param reason The {@link SheetCloseReason} that the sheet is closing. + */ + public void setSheetCloseReason(@SheetCloseReason int reason) { + mSheetCloseReason = reason; + } + + /** * Records the reason the sheet was opened. * @param reason The {@link SheetOpenReason} that caused the bottom sheet to open. */ public void recordSheetOpenReason(@SheetOpenReason int reason) { + switch (reason) { + case OPENED_BY_SWIPE: + RecordUserAction.record("Android.ChromeHome.OpenedBySwipe"); + break; + case OPENED_BY_OMNIBOX_FOCUS: + RecordUserAction.record("Android.ChromeHome.OpenedByOmnibox"); + break; + case OPENED_BY_NEW_TAB_CREATION: + RecordUserAction.record("Android.ChromeHome.OpenedByNTP"); + break; + case OPENED_BY_EXPAND_BUTTON: + RecordUserAction.record("Android.ChromeHome.OpenedByExpandButton"); + break; + default: + assert false; + } RecordHistogram.recordEnumeratedHistogram( "Android.ChromeHome.OpenReason", reason, OPENED_BY_BOUNDARY); } + + /** + * Records the reason the sheet was closed. + * @param reason The {@link SheetCloseReason} that cause the bottom sheet to close. + */ + public void recordSheetCloseReason(@SheetCloseReason int reason) { + switch (reason) { + case CLOSED_BY_SWIPE: + RecordUserAction.record("Android.ChromeHome.ClosedBySwipe"); + break; + case CLOSED_BY_NTP_CLOSE_BUTTON: + RecordUserAction.record("Android.ChromeHome.ClosedByNTPCloseButton"); + break; + case CLOSED_BY_TAP_SCRIM: + RecordUserAction.record("Android.ChromeHome.ClosedByTapScrim"); + break; + case CLOSED_BY_NAVIGATION: + RecordUserAction.record("Android.ChromeHome.ClosedByNavigation"); + break; + case CLOSED_BY_NONE: + RecordUserAction.record("Android.ChromeHome.Closed"); + break; + default: + assert false; + } + } }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 0392559..d1d7637a 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -462,6 +462,7 @@ "java/src/org/chromium/chrome/browser/infobar/IPHInfoBarSupport.java", "java/src/org/chromium/chrome/browser/infobar/PermissionInfoBar.java", "java/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfoBarDelegate.java", + "java/src/org/chromium/chrome/browser/infobar/ReaderModeInfoBar.java", "java/src/org/chromium/chrome/browser/infobar/SearchGeolocationDisclosureInfoBar.java", "java/src/org/chromium/chrome/browser/infobar/SimpleConfirmInfoBarBuilder.java", "java/src/org/chromium/chrome/browser/infobar/SubresourceFilterInfoBar.java", @@ -788,6 +789,7 @@ "java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java", "java/src/org/chromium/chrome/browser/permissions/PermissionDialogDelegate.java", "java/src/org/chromium/chrome/browser/physicalweb/BitmapHttpRequest.java", + "java/src/org/chromium/chrome/browser/photo_picker/BitmapScalerTask.java", "java/src/org/chromium/chrome/browser/photo_picker/BitmapUtils.java", "java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java", "java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java", @@ -948,6 +950,7 @@ "java/src/org/chromium/chrome/browser/push_messaging/PushMessagingServiceObserver.java", "java/src/org/chromium/chrome/browser/rappor/RapporServiceBridge.java", "java/src/org/chromium/chrome/browser/rlz/RevenueStats.java", + "java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java", "java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java", "java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java", "java/src/org/chromium/chrome/browser/searchwidget/SearchActivityFadingBackgroundView.java", @@ -1018,6 +1021,7 @@ "java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java", "java/src/org/chromium/chrome/browser/suggestions/SuggestionsEventReporter.java", "java/src/org/chromium/chrome/browser/suggestions/SuggestionsEventReporterBridge.java", + "java/src/org/chromium/chrome/browser/suggestions/SuggestionsMetrics.java", "java/src/org/chromium/chrome/browser/suggestions/SuggestionsRanker.java", "java/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProvider.java", "java/src/org/chromium/chrome/browser/sync/GmsCoreSyncListener.java", @@ -1713,7 +1717,7 @@ "junit/src/org/chromium/chrome/browser/offlinepages/ClientIdTest.java", "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java", "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java", - "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsUnitTest.java", + "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java", "junit/src/org/chromium/chrome/browser/offlinepages/ShadowDeviceConditions.java", "junit/src/org/chromium/chrome/browser/offlinepages/ShadowGcmNetworkManager.java", "junit/src/org/chromium/chrome/browser/offlinepages/StubBackgroundSchedulerProcessor.java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java index 14fe46a7..1d421c8 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
@@ -29,6 +29,7 @@ import static org.chromium.chrome.browser.ntp.cards.ContentSuggestionsUnitTestUtils.bindViewHolders; import static org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.createDummySuggestions; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -38,6 +39,7 @@ import org.robolectric.annotation.Config; import org.chromium.base.Callback; +import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.test.util.Feature; import org.chromium.chrome.browser.DisableHistogramsRule; import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder.UpdateLayoutParamsCallback; @@ -81,6 +83,7 @@ @Before public void setUp() { + RecordUserAction.setDisabledForTests(true); MockitoAnnotations.initMocks(this); mBridge = new FakeOfflinePageBridge(); @@ -88,6 +91,11 @@ CardsVariationParameters.setTestVariationParams(new HashMap<String, String>()); } + @After + public void tearDown() { + RecordUserAction.setDisabledForTests(false); + } + @Test @Feature({"Ntp"}) public void testDismissSibling() {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java index a901d25..40a7c419 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java
@@ -7,6 +7,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -14,6 +15,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.content.Context; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -48,6 +51,8 @@ @Mock private SnackbarManager mSnackbarManager; @Mock private SnackbarController mSnackbarController; @Mock private Tab mTab; + @Mock + private OfflinePageUtils.Internal mOfflinePageUtils; private OfflinePageTabObserver createObserver() { OfflinePageTabObserver observer = spy(new OfflinePageTabObserver( @@ -56,13 +61,7 @@ // directly mock out. doNothing().when(observer).startObservingNetworkChanges(); doNothing().when(observer).stopObservingNetworkChanges(); - // TODO(fgorski): This call has to be mocked out until we update OfflinePageUtils. - // It also goes to NetworkChangeNotifier from there. - doReturn(false).when(observer).isConnected(); - doReturn(false).when(observer).isShowingOfflinePreview(any(Tab.class)); - // TODO(fgorski): This call has to be mocked out until we update OfflinePageUtils. - doNothing().when(observer).showReloadSnackbar(any(Tab.class)); - doReturn(true).when(observer).isOfflinePage(any(Tab.class)); + // Assert tab model observer was created. assertTrue(observer.getTabModelObserver() != null); return observer; @@ -81,6 +80,16 @@ // Setting up mock snackbar manager. doNothing().when(mSnackbarManager).dismissSnackbars(eq(mSnackbarController)); + + // Setting up offline page utils. + OfflinePageUtils.setInstanceForTesting(mOfflinePageUtils); + doReturn(false).when(mOfflinePageUtils).isConnected(); + doReturn(false).when(mOfflinePageUtils).isShowingOfflinePreview(any(Tab.class)); + doReturn(true).when(mOfflinePageUtils).isOfflinePage(any(Tab.class)); + doNothing() + .when(mOfflinePageUtils) + .showReloadSnackbar(any(Context.class), any(SnackbarManager.class), + any(SnackbarController.class), anyInt()); } private void showTab(OfflinePageTabObserver observer) { @@ -104,14 +113,14 @@ } private void connect(OfflinePageTabObserver observer, boolean notify) { - doReturn(true).when(observer).isConnected(); + doReturn(true).when(mOfflinePageUtils).isConnected(); if (notify) { observer.onConnectionTypeChanged(0); } } private void disconnect(OfflinePageTabObserver observer, boolean notify) { - doReturn(false).when(observer).isConnected(); + doReturn(false).when(mOfflinePageUtils).isConnected(); if (notify) { observer.onConnectionTypeChanged(0); } @@ -130,14 +139,14 @@ public void testStartObservingTab() { OfflinePageTabObserver observer = createObserver(); - doReturn(false).when(observer).isOfflinePage(any(Tab.class)); + doReturn(false).when(mOfflinePageUtils).isOfflinePage(any(Tab.class)); observer.startObservingTab(mTab); assertFalse(observer.isObservingNetworkChanges()); assertFalse(observer.isObservingTab(mTab)); verify(observer, times(0)).showReloadSnackbar(any(Tab.class)); - doReturn(true).when(observer).isOfflinePage(any(Tab.class)); + doReturn(true).when(mOfflinePageUtils).isOfflinePage(any(Tab.class)); observer.startObservingTab(mTab); assertTrue(observer.isObservingNetworkChanges()); @@ -171,7 +180,7 @@ OfflinePageTabObserver observer = createObserver(); observer.startObservingTab(mTab); - doReturn(true).when(observer).isConnected(); + doReturn(true).when(mOfflinePageUtils).isConnected(); observer.onPageLoadFinished(mTab); verify(observer, times(1)).showReloadSnackbar(any(Tab.class)); @@ -267,7 +276,7 @@ hideTab(null); observer.startObservingTab(mTab); - doReturn(true).when(observer).isShowingOfflinePreview(mTab); + doReturn(true).when(mOfflinePageUtils).isShowingOfflinePreview(mTab); observer.onPageLoadFinished(mTab); verify(observer, times(0)).showReloadSnackbar(any(Tab.class)); @@ -400,7 +409,7 @@ verify(mSnackbarManager, times(1)).dismissSnackbars(eq(mSnackbarController)); // URL updated and tab no longer shows offline page. - doReturn(false).when(observer).isOfflinePage(any(Tab.class)); + doReturn(false).when(mOfflinePageUtils).isOfflinePage(any(Tab.class)); observer.onUrlUpdated(mTab); assertFalse(observer.isObservingTab(mTab)); @@ -432,7 +441,7 @@ observer.onPageLoadFinished(mTab); // URL updated and tab no longer shows offline page. - doReturn(false).when(observer).isOfflinePage(any(Tab.class)); + doReturn(false).when(mOfflinePageUtils).isOfflinePage(any(Tab.class)); observer.onUrlUpdated(mTab); assertFalse(observer.isObservingTab(mTab));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java similarity index 92% rename from chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsUnitTest.java rename to chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java index 11a221c7..96a0747 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java
@@ -16,14 +16,6 @@ import android.os.Environment; -import org.chromium.base.BaseChromiumApplication; -import org.chromium.base.test.util.Feature; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.components.bookmarks.BookmarkId; -import org.chromium.components.bookmarks.BookmarkType; -import org.chromium.content_public.browser.WebContents; -import org.chromium.testing.local.LocalRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,22 +26,34 @@ import org.robolectric.annotation.Implements; import org.robolectric.shadows.multidex.ShadowMultiDex; +import org.chromium.base.BaseChromiumApplication; +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.profiles.Profile; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.components.bookmarks.BookmarkId; +import org.chromium.components.bookmarks.BookmarkType; +import org.chromium.content_public.browser.WebContents; +import org.chromium.testing.local.LocalRobolectricTestRunner; + import java.io.File; /** * Unit tests for OfflinePageUtils. */ @RunWith(LocalRobolectricTestRunner.class) -@Config(manifest = Config.NONE, - application = BaseChromiumApplication.class, - shadows = { OfflinePageUtilsUnitTest.WrappedEnvironment.class, ShadowMultiDex.class }) -public class OfflinePageUtilsUnitTest { - - @Mock private File mMockDataDirectory; - @Mock private Tab mTab; - @Mock private WebContents mWebContents; - @Mock private OfflinePageBridge mOfflinePageBridge; - @Mock private OfflinePageUtils mOfflinePageUtils; +@Config(manifest = Config.NONE, application = BaseChromiumApplication.class, + shadows = {OfflinePageUtilsTest.WrappedEnvironment.class, ShadowMultiDex.class}) +public class OfflinePageUtilsTest { + @Mock + private File mMockDataDirectory; + @Mock + private Tab mTab; + @Mock + private WebContents mWebContents; + @Mock + private OfflinePageBridge mOfflinePageBridge; + @Mock + private OfflinePageUtils.Internal mOfflinePageUtils; @Before public void setUp() throws Exception { @@ -100,13 +104,13 @@ assertEquals("cs.chromium.org", OfflinePageUtils.stripSchemeFromOnlineUrl("http://cs.chromium.org")); // If there is no scheme, nothing changes. - assertEquals("cs.chromium.org", - OfflinePageUtils.stripSchemeFromOnlineUrl("cs.chromium.org")); + assertEquals( + "cs.chromium.org", OfflinePageUtils.stripSchemeFromOnlineUrl("cs.chromium.org")); // Path is not touched/changed. String urlWithPath = "code.google.com/p/chromium/codesearch#search" + "/&q=offlinepageutils&sq=package:chromium&type=cs"; - assertEquals(urlWithPath, - OfflinePageUtils.stripSchemeFromOnlineUrl("https://" + urlWithPath)); + assertEquals( + urlWithPath, OfflinePageUtils.stripSchemeFromOnlineUrl("https://" + urlWithPath)); // Beginning and ending spaces get trimmed. assertEquals("cs.chromium.org", OfflinePageUtils.stripSchemeFromOnlineUrl(" https://cs.chromium.org "));
diff --git a/chrome/app/nibs/BUILD.gn b/chrome/app/nibs/BUILD.gn index 6b0caef..1a06558 100644 --- a/chrome/app/nibs/BUILD.gn +++ b/chrome/app/nibs/BUILD.gn
@@ -31,7 +31,6 @@ "ExtensionInstallPromptWebstoreData.xib", "ExtensionInstalledBubble.xib", "FirstRunBubble.xib", - "FirstRunDialog.xib", "HttpAuthLoginSheet.xib", "HungRendererDialog.xib", "MainMenu.xib",
diff --git a/chrome/app/nibs/FirstRunDialog.xib b/chrome/app/nibs/FirstRunDialog.xib deleted file mode 100644 index a223b06b..0000000 --- a/chrome/app/nibs/FirstRunDialog.xib +++ /dev/null
@@ -1,140 +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="FirstRunDialogController"> - <connections> - <outlet property="objectsToSize_" destination="106" id="117"/> - <outlet property="setAsDefaultCheckbox_" destination="11" id="131"/> - <outlet property="statsCheckbox_" destination="30" id="124"/> - <outlet property="window" destination="1" id="65"/> - </connections> - </customObject> - <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> - <customObject id="-3" userLabel="Application"/> - <window title="^IDS_FIRSTRUN_DLG_MAC_WINDOW_TITLE$IDS_PRODUCT_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="1"> - <windowStyleMask key="styleMask" titled="YES"/> - <windowPositionMask key="initialPositionMask" leftStrut="YES" bottomStrut="YES"/> - <rect key="contentRect" x="196" y="290" width="480" height="209"/> - <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1028"/> - <view key="contentView" id="2"> - <rect key="frame" x="0.0" y="0.0" width="480" height="209"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <subviews> - <button id="11"> - <rect key="frame" x="45" y="126" width="528" height="18"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="check" title="^IDS_FIRSTRUN_DLG_MAC_SET_DEFAULT_BROWSER_LABEL" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="12"> - <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <binding destination="-2" name="value" keyPath="makeDefaultBrowser" id="68"/> - </connections> - </button> - <box autoresizesSubviews="NO" title="Box" boxType="custom" borderType="none" id="21"> - <rect key="frame" x="0.0" y="158" width="480" height="55"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> - <view key="contentView"> - <rect key="frame" x="0.0" y="0.0" width="480" height="55"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <subviews> - <textField verticalHuggingPriority="750" id="3"> - <rect key="frame" x="13" y="25" width="390" height="17"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="^IDS_FIRSTRUN_DLG_MAC_COMPLETE_INSTALLATION_LABEL$IDS_PRODUCT_NAME" id="4"> - <font key="font" metaFont="system"/> - <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> - </textFieldCell> - </textField> - <imageView id="9"> - <rect key="frame" x="408" y="-25" width="96" height="96"/> - <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/> - <imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" image="NSApplicationIcon" id="10"/> - </imageView> - </subviews> - </view> - <color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/> - <color key="fillColor" white="1" alpha="1" colorSpace="calibratedWhite"/> - </box> - <box autoresizesSubviews="NO" verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="22"> - <rect key="frame" x="0.0" y="155" width="480" height="5"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> - <color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/> - <color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> - <font key="titleFont" metaFont="system"/> - </box> - <box autoresizesSubviews="NO" verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="29"> - <rect key="frame" x="0.0" y="55" width="480" height="5"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> - <color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/> - <color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> - <font key="titleFont" metaFont="system"/> - </box> - <button id="30"> - <rect key="frame" x="45" y="101" width="389" height="19"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="check" title="^IDS_FIRSTRUN_DLG_MAC_OPTIONS_SEND_USAGE_STATS_LABEL$IDS_PRODUCT_NAME" bezelStyle="regularSquare" imagePosition="left" alignment="left" state="on" inset="2" id="31"> - <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <binding destination="-2" name="value" keyPath="statsEnabled" id="69"/> - </connections> - </button> - <customView id="97" customClass="GTMWidthBasedTweaker"> - <rect key="frame" x="147" y="-2" width="334" height="52"/> - <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> - <subviews> - <button verticalHuggingPriority="750" id="27"> - <rect key="frame" x="14" y="12" width="306" height="32"/> - <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> - <buttonCell key="cell" type="push" title="^IDS_FIRSTRUN_DLG_MAC_START_CHROME_BUTTON$IDS_PRODUCT_NAME" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="28"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - <string key="keyEquivalent" base64-UTF8="YES"> -DQ -</string> - </buttonCell> - <connections> - <action selector="ok:" target="-2" id="72"/> - </connections> - </button> - </subviews> - </customView> - <button id="36"> - <rect key="frame" x="60" y="76" width="359" height="19"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="roundRect" title="^IDS_LEARN_MORE" bezelStyle="roundedRect" alignment="center" state="on" imageScaling="proportionallyDown" inset="2" id="37" customClass="HyperlinkButtonCell"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - </buttonCell> - <connections> - <action selector="learnMore:" target="-2" id="73"/> - </connections> - </button> - </subviews> - </view> - </window> - <customObject id="91" customClass="ChromeUILocalizer"> - <connections> - <outlet property="owner_" destination="-2" id="118"/> - </connections> - </customObject> - <customObject id="106" userLabel="Objects to Size" customClass="GTMIBArray"> - <connections> - <outlet property="object1_" destination="97" id="107"/> - <outlet property="object2_" destination="36" id="108"/> - <outlet property="object3_" destination="11" id="119"/> - <outlet property="object5_" destination="3" id="130"/> - </connections> - </customObject> - </objects> - <resources> - <image name="NSApplicationIcon" width="128" height="128"/> - </resources> -</document>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 9092afd..85b6d5f 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -564,6 +564,10 @@ "media/media_access_handler.h", "media/media_device_id_salt.cc", "media/media_device_id_salt.h", + "media/media_engagement_service.cc", + "media/media_engagement_service.h", + "media/media_engagement_service_factory.cc", + "media/media_engagement_service_factory.h", "media/media_url_constants.cc", "media/media_url_constants.h", "media/midi_permission_context.cc", @@ -2962,6 +2966,8 @@ "android/resource_mapper.h", "android/rlz/revenue_stats.cc", "android/rlz/revenue_stats.h", + "android/rlz/rlz_ping_handler.cc", + "android/rlz/rlz_ping_handler.h", "android/search_geolocation/search_geolocation_disclosure_infobar_delegate.cc", "android/search_geolocation/search_geolocation_disclosure_infobar_delegate.h", "android/search_geolocation/search_geolocation_disclosure_tab_helper.cc", @@ -3183,6 +3189,7 @@ "//components/safe_browsing_db", "//components/toolbar", "//components/web_contents_delegate_android", + "//rlz:rlz_utils", "//sandbox:sandbox_features", "//third_party/android_opengl/etc1", "//third_party/android_tools:cpu_features", @@ -4144,6 +4151,7 @@ "../android/java/src/org/chromium/chrome/browser/infobar/InstantAppsInfoBarDelegate.java", "../android/java/src/org/chromium/chrome/browser/infobar/PermissionInfoBar.java", "../android/java/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfoBarDelegate.java", + "../android/java/src/org/chromium/chrome/browser/infobar/ReaderModeInfoBar.java", "../android/java/src/org/chromium/chrome/browser/infobar/SearchGeolocationDisclosureInfoBar.java", "../android/java/src/org/chromium/chrome/browser/infobar/SimpleConfirmInfoBarBuilder.java", "../android/java/src/org/chromium/chrome/browser/infobar/SubresourceFilterExperimentalInfoBar.java", @@ -4221,6 +4229,7 @@ "../android/java/src/org/chromium/chrome/browser/push_messaging/PushMessagingServiceObserver.java", "../android/java/src/org/chromium/chrome/browser/rappor/RapporServiceBridge.java", "../android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java", + "../android/java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java", "../android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java", "../android/java/src/org/chromium/chrome/browser/sessions/SessionTabHelper.java", "../android/java/src/org/chromium/chrome/browser/signin/AccountManagementScreenHelper.java",
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index 8d4a2ab1..0d87796b 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -95,6 +95,7 @@ #include "chrome/browser/android/rappor/rappor_service_bridge.h" #include "chrome/browser/android/recently_closed_tabs_bridge.h" #include "chrome/browser/android/rlz/revenue_stats.h" +#include "chrome/browser/android/rlz/rlz_ping_handler.h" #include "chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.h" #include "chrome/browser/android/service_tab_launcher.h" #include "chrome/browser/android/sessions/session_tab_helper_android.h" @@ -159,6 +160,7 @@ #include "chrome/browser/ui/android/infobars/grouped_permission_infobar.h" #include "chrome/browser/ui/android/infobars/infobar_android.h" #include "chrome/browser/ui/android/infobars/infobar_container_android.h" +#include "chrome/browser/ui/android/infobars/reader_mode_infobar.h" #include "chrome/browser/ui/android/infobars/simple_confirm_infobar_builder.h" #include "chrome/browser/ui/android/infobars/translate_compact_infobar.h" #include "chrome/browser/ui/android/infobars/translate_infobar.h" @@ -388,6 +390,7 @@ {"RapporServiceBridge", rappor::RegisterRapporServiceBridge}, {"RecentlyClosedBridge", RecentlyClosedTabsBridge::Register}, {"RecordCastAction", remote_media::RegisterRecordCastAction}, + {"ReaderModeInfoBar", RegisterReaderModeInfoBar}, {"ReaderModeSceneLayer", RegisterReaderModeSceneLayer}, {"RemoteMediaPlayerBridge", remote_media::RemoteMediaPlayerBridge::RegisterRemoteMediaPlayerBridge}, @@ -395,6 +398,7 @@ {"ResourcePrefetchPredictor", predictors::RegisterResourcePrefetchPredictor}, {"RevenueStats", chrome::android::RegisterRevenueStats}, + {"RlzPingHandler", chrome::android::RegisterRlzPingHandler}, {"SafeBrowsing", safe_browsing::android::RegisterBrowserJNI}, {"SceneLayer", RegisterSceneLayer}, {"ScreenshotTask", chrome::android::RegisterScreenshotTask},
diff --git a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc index ad4f121..b970049a 100644 --- a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc +++ b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc
@@ -204,7 +204,7 @@ void AppStatusChanged(base::android::ApplicationState state) { if (variations::GetVariationParamByFeatureAsBool( kNotificationsFeature, kNotificationsKeepWhenFrontmostParam, - false)) { + true)) { return; } if (!ShouldNotifyInState(state)) {
diff --git a/chrome/browser/android/rlz/rlz_ping_handler.cc b/chrome/browser/android/rlz/rlz_ping_handler.cc new file mode 100644 index 0000000..53723c44 --- /dev/null +++ b/chrome/browser/android/rlz/rlz_ping_handler.cc
@@ -0,0 +1,145 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/android/rlz/rlz_ping_handler.h" + +#include "base/android/callback_android.h" +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/strings/stringprintf.h" +#include "chrome/browser/profiles/profile_android.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "jni/RlzPingHandler_jni.h" +#include "net/base/url_util.h" +#include "net/http/http_status_code.h" +#include "net/http/http_util.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "rlz/lib/lib_values.h" +#include "rlz/lib/net_response_check.h" +#include "url/gurl.h" + +using base::android::ConvertJavaStringToUTF16; +using base::android::JavaParamRef; + +constexpr int kMaxRetries = 10; + +namespace chrome { +namespace android { + +RlzPingHandler::RlzPingHandler(jobject jprofile) { + Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); + DCHECK(profile); + request_context_ = profile->GetRequestContext(); +} + +RlzPingHandler::~RlzPingHandler() = default; + +void RlzPingHandler::Ping( + const base::android::JavaParamRef<jstring>& j_brand, + const base::android::JavaParamRef<jstring>& j_language, + const base::android::JavaParamRef<jstring>& j_events, + const base::android::JavaParamRef<jstring>& j_id, + const base::android::JavaParamRef<jobject>& j_callback) { + if (!j_brand || !j_language || !j_events || !j_id || !j_callback) { + base::android::RunCallbackAndroid(j_callback, false); + delete this; + return; + } + + JNIEnv* env = base::android::AttachCurrentThread(); + + j_callback_.Reset(env, j_callback); + std::string brand = ConvertJavaStringToUTF8(env, j_brand); + std::string language = ConvertJavaStringToUTF8(env, j_language); + std::string events = ConvertJavaStringToUTF8(env, j_events); + std::string id = ConvertJavaStringToUTF8(env, j_id); + + DCHECK_EQ(brand.length(), 4u); + DCHECK_EQ(language.length(), 2u); + DCHECK_EQ(id.length(), 50u); + + GURL request_url(base::StringPrintf( + "https://%s%s?", rlz_lib::kFinancialServer, rlz_lib::kFinancialPingPath)); + request_url = net::AppendQueryParameter( + request_url, rlz_lib::kProductSignatureCgiVariable, "chrome"); + request_url = net::AppendQueryParameter( + request_url, rlz_lib::kProductBrandCgiVariable, brand); + request_url = net::AppendQueryParameter( + request_url, rlz_lib::kProductLanguageCgiVariable, language); + request_url = net::AppendQueryParameter(request_url, + rlz_lib::kEventsCgiVariable, events); + request_url = net::AppendQueryParameter(request_url, + rlz_lib::kMachineIdCgiVariable, id); + + net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("rlz", R"( + semantics { + sender: "RLZ Ping Handler" + description: + "Sends rlz pings for revenue related tracking to the designated web" + "end point." + trigger: + "Critical signals like first install, a promotion dialog being" + "shown, a user selection for a promotion may trigger a ping" + destination: WEBSITE + } + policy { + cookies_allowed: true + cookies_store: "user" + setting: "Not user controlled. But it uses a trusted web end point" + "that doesn't use user data" + policy_exception_justification: + "Not implemented, considered not useful as no content is being " + "uploaded." + })"); + + url_fetcher_ = net::URLFetcher::Create(0, request_url, net::URLFetcher::GET, + this, traffic_annotation); + url_fetcher_->SetMaxRetriesOn5xx(kMaxRetries); + url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries); + url_fetcher_->SetAutomaticallyRetryOn5xx(true); + url_fetcher_->SetRequestContext(request_context_.get()); + url_fetcher_->Start(); +} + +void RlzPingHandler::OnURLFetchComplete(const net::URLFetcher* source) { + DCHECK_EQ(source, url_fetcher_.get()); + + jboolean valid = false; + if (!source->GetStatus().is_success() || + source->GetResponseCode() != net::HTTP_OK) { + LOG(WARNING) << base::StringPrintf("Rlz endpoint responded with code %d.", + source->GetResponseCode()); + } else { + std::string response; + source->GetResponseAsString(&response); + int response_length = -1; + valid = rlz_lib::IsPingResponseValid(response.c_str(), &response_length); + } + + // TODO(yusufo) : Investigate what else can be checked for validity that is + // specific to the ping + base::android::RunCallbackAndroid(j_callback_, valid); + delete this; +} + +void StartPing(JNIEnv* env, + const JavaParamRef<jclass>& clazz, + const base::android::JavaParamRef<jobject>& j_profile, + const base::android::JavaParamRef<jstring>& j_brand, + const base::android::JavaParamRef<jstring>& j_language, + const base::android::JavaParamRef<jstring>& j_events, + const base::android::JavaParamRef<jstring>& j_id, + const base::android::JavaParamRef<jobject>& j_callback) { + RlzPingHandler* handler = new RlzPingHandler(j_profile); + handler->Ping(j_brand, j_language, j_events, j_id, j_callback); +} + +// Register native methods +bool RegisterRlzPingHandler(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace android +} // namespace chrome
diff --git a/chrome/browser/android/rlz/rlz_ping_handler.h b/chrome/browser/android/rlz/rlz_ping_handler.h new file mode 100644 index 0000000..2abe720 --- /dev/null +++ b/chrome/browser/android/rlz/rlz_ping_handler.h
@@ -0,0 +1,51 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ANDROID_RLZ_RLZ_PING_HANDLER_H_ +#define CHROME_BROWSER_ANDROID_RLZ_RLZ_PING_HANDLER_H_ + +#include <jni.h> +#include "base/android/scoped_java_ref.h" +#include "net/url_request/url_fetcher.h" +#include "net/url_request/url_fetcher_delegate.h" +#include "net/url_request/url_request_context_getter.h" + +namespace chrome { +namespace android { + +// JNI bridge for RlzPingHandler.java +class RlzPingHandler : public net::URLFetcherDelegate { + public: + explicit RlzPingHandler(jobject jprofile); + ~RlzPingHandler() override; + + // Makes a GET request to the designated web end point with the given + // parameters. |j_brand| is a 4 character priorly designated brand value. + // |j_language| is the 2 letter lower case language. |events| is a single + // string where multiple 4 character long events are concatenated with , + // and |id| is a unique id for the device that is 50 characters long. + void Ping(const base::android::JavaParamRef<jstring>& j_brand, + const base::android::JavaParamRef<jstring>& j_language, + const base::android::JavaParamRef<jstring>& j_events, + const base::android::JavaParamRef<jstring>& j_id, + const base::android::JavaParamRef<jobject>& j_callback); + + private: + // net::URLFetcherDelegate: + void OnURLFetchComplete(const net::URLFetcher* source) override; + + scoped_refptr<net::URLRequestContextGetter> request_context_; + + std::unique_ptr<net::URLFetcher> url_fetcher_; + base::android::ScopedJavaGlobalRef<jobject> j_callback_; + + DISALLOW_COPY_AND_ASSIGN(RlzPingHandler); +}; + +bool RegisterRlzPingHandler(JNIEnv* env); + +} // namespace android +} // namespace chrome + +#endif // CHROME_BROWSER_ANDROID_RLZ_RLZ_PING_HANDLER_H_
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index c275577..dfb99af 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3226,8 +3226,8 @@ content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); if (web_contents) { - registry->AddInterface(base::Bind( - payments::CreatePaymentRequestForWebContents, web_contents)); + registry->AddInterface(base::Bind(payments::CreatePaymentRequest, + render_frame_host, web_contents)); } } #endif
diff --git a/chrome/browser/devtools/devtools_embedder_message_dispatcher.h b/chrome/browser/devtools/devtools_embedder_message_dispatcher.h index 681012c..db6a8f10 100644 --- a/chrome/browser/devtools/devtools_embedder_message_dispatcher.h +++ b/chrome/browser/devtools/devtools_embedder_message_dispatcher.h
@@ -71,7 +71,9 @@ virtual void SetDevicesDiscoveryConfig( bool discover_usb_devices, bool port_forwarding_enabled, - const std::string& port_forwarding_config) = 0; + const std::string& port_forwarding_config, + bool network_discovery_enabled, + const std::string& network_discovery_config) = 0; virtual void PerformActionOnRemotePage(const std::string& page_id, const std::string& action) = 0; virtual void OpenRemotePage(const std::string& browser_id,
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc index 91c8e15..cbdff1523 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.cc +++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -100,6 +100,12 @@ static const char kRemotePageActionActivate[] = "activate"; static const char kRemotePageActionClose[] = "close"; +static const char kConfigDiscoverUsbDevices[] = "discoverUsbDevices"; +static const char kConfigPortForwardingEnabled[] = "portForwardingEnabled"; +static const char kConfigPortForwardingConfig[] = "portForwardingConfig"; +static const char kConfigNetworkDiscoveryEnabled[] = "networkDiscoveryEnabled"; +static const char kConfigNetworkDiscoveryConfig[] = "networkDiscoveryConfig"; + // This constant should be in sync with // the constant at shell_devtools_frontend.cc. const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4; @@ -918,30 +924,63 @@ void DevToolsUIBindings::SetDevicesDiscoveryConfig( bool discover_usb_devices, bool port_forwarding_enabled, - const std::string& port_forwarding_config) { - base::DictionaryValue* config_dict = nullptr; - std::unique_ptr<base::Value> parsed_config = + const std::string& port_forwarding_config, + bool network_discovery_enabled, + const std::string& network_discovery_config) { + base::DictionaryValue* port_forwarding_dict = nullptr; + std::unique_ptr<base::Value> parsed_port_forwarding = base::JSONReader::Read(port_forwarding_config); - if (!parsed_config || !parsed_config->GetAsDictionary(&config_dict)) + if (!parsed_port_forwarding || + !parsed_port_forwarding->GetAsDictionary(&port_forwarding_dict)) { + return; + } + + base::ListValue* network_list = nullptr; + std::unique_ptr<base::Value> parsed_network = + base::JSONReader::Read(network_discovery_config); + if (!parsed_network || !parsed_network->GetAsList(&network_list)) return; profile_->GetPrefs()->SetBoolean( prefs::kDevToolsDiscoverUsbDevicesEnabled, discover_usb_devices); profile_->GetPrefs()->SetBoolean( prefs::kDevToolsPortForwardingEnabled, port_forwarding_enabled); - profile_->GetPrefs()->Set( - prefs::kDevToolsPortForwardingConfig, *config_dict); + profile_->GetPrefs()->Set(prefs::kDevToolsPortForwardingConfig, + *port_forwarding_dict); + profile_->GetPrefs()->SetBoolean(prefs::kDevToolsDiscoverTCPTargetsEnabled, + network_discovery_enabled); + profile_->GetPrefs()->Set(prefs::kDevToolsTCPDiscoveryConfig, *network_list); } void DevToolsUIBindings::DevicesDiscoveryConfigUpdated() { - CallClientFunction( - "DevToolsAPI.devicesDiscoveryConfigChanged", - profile_->GetPrefs()->FindPreference( - prefs::kDevToolsDiscoverUsbDevicesEnabled)->GetValue(), - profile_->GetPrefs()->FindPreference( - prefs::kDevToolsPortForwardingEnabled)->GetValue(), - profile_->GetPrefs()->FindPreference( - prefs::kDevToolsPortForwardingConfig)->GetValue()); + base::DictionaryValue config; + config.Set(kConfigDiscoverUsbDevices, + profile_->GetPrefs() + ->FindPreference(prefs::kDevToolsDiscoverUsbDevicesEnabled) + ->GetValue() + ->CreateDeepCopy()); + config.Set(kConfigPortForwardingEnabled, + profile_->GetPrefs() + ->FindPreference(prefs::kDevToolsPortForwardingEnabled) + ->GetValue() + ->CreateDeepCopy()); + config.Set(kConfigPortForwardingConfig, + profile_->GetPrefs() + ->FindPreference(prefs::kDevToolsPortForwardingConfig) + ->GetValue() + ->CreateDeepCopy()); + config.Set(kConfigNetworkDiscoveryEnabled, + profile_->GetPrefs() + ->FindPreference(prefs::kDevToolsDiscoverTCPTargetsEnabled) + ->GetValue() + ->CreateDeepCopy()); + config.Set(kConfigNetworkDiscoveryConfig, + profile_->GetPrefs() + ->FindPreference(prefs::kDevToolsTCPDiscoveryConfig) + ->GetValue() + ->CreateDeepCopy()); + CallClientFunction("DevToolsAPI.devicesDiscoveryConfigChanged", &config, + nullptr, nullptr); } void DevToolsUIBindings::SendPortForwardingStatus(const base::Value& status) { @@ -968,6 +1007,14 @@ pref_change_registrar_.Add(prefs::kDevToolsPortForwardingConfig, base::Bind(&DevToolsUIBindings::DevicesDiscoveryConfigUpdated, base::Unretained(this))); + pref_change_registrar_.Add( + prefs::kDevToolsDiscoverTCPTargetsEnabled, + base::Bind(&DevToolsUIBindings::DevicesDiscoveryConfigUpdated, + base::Unretained(this))); + pref_change_registrar_.Add( + prefs::kDevToolsTCPDiscoveryConfig, + base::Bind(&DevToolsUIBindings::DevicesDiscoveryConfigUpdated, + base::Unretained(this))); port_status_serializer_.reset(new PortForwardingStatusSerializer( base::Bind(&DevToolsUIBindings::SendPortForwardingStatus, base::Unretained(this)),
diff --git a/chrome/browser/devtools/devtools_ui_bindings.h b/chrome/browser/devtools/devtools_ui_bindings.h index a278572..46e94ed 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.h +++ b/chrome/browser/devtools/devtools_ui_bindings.h
@@ -132,7 +132,9 @@ void SetDevicesDiscoveryConfig( bool discover_usb_devices, bool port_forwarding_enabled, - const std::string& port_forwarding_config) override; + const std::string& port_forwarding_config, + bool network_discovery_enabled, + const std::string& network_discovery_config) override; void SetDevicesUpdatesEnabled(bool enabled) override; void PerformActionOnRemotePage(const std::string& page_id, const std::string& action) override;
diff --git a/chrome/browser/media/OWNERS b/chrome/browser/media/OWNERS index 4258926..a3d42e0 100644 --- a/chrome/browser/media/OWNERS +++ b/chrome/browser/media/OWNERS
@@ -6,4 +6,7 @@ per-file cast_*=hubbe@chromium.org per-file cast_*=miu@chromium.org +# For Media Engagement +per-file media_engagement*=mlamouri@chromium.org + # COMPONENT: Blink>Media
diff --git a/chrome/browser/media/media_engagement_service.cc b/chrome/browser/media/media_engagement_service.cc new file mode 100644 index 0000000..2eb7ffb --- /dev/null +++ b/chrome/browser/media/media_engagement_service.cc
@@ -0,0 +1,62 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/media/media_engagement_service.h" + +#include "chrome/browser/media/media_engagement_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" +#include "media/base/media_switches.h" + +class MediaEngagementService::ContentsObserver + : public content::WebContentsObserver { + public: + ContentsObserver(content::WebContents* web_contents, + MediaEngagementService* service) + : WebContentsObserver(web_contents), service_(service) {} + + ~ContentsObserver() override = default; + + // WebContentsObserver implementation. + void WebContentsDestroyed() override { + service_->contents_observers_.erase(this); + delete this; + } + + private: + // |this| is owned by |service_|. + MediaEngagementService* service_; + + DISALLOW_COPY_AND_ASSIGN(ContentsObserver); +}; + +// static +bool MediaEngagementService::IsEnabled() { + return base::FeatureList::IsEnabled(media::kMediaEngagement); +} + +// static +MediaEngagementService* MediaEngagementService::Get(Profile* profile) { + DCHECK(IsEnabled()); + return MediaEngagementServiceFactory::GetForProfile(profile); +} + +// static +void MediaEngagementService::CreateWebContentsObserver( + content::WebContents* web_contents) { + DCHECK(IsEnabled()); + MediaEngagementService* service = + Get(Profile::FromBrowserContext(web_contents->GetBrowserContext())); + if (!service) + return; + service->contents_observers_.insert( + new ContentsObserver(web_contents, service)); +} + +MediaEngagementService::MediaEngagementService(Profile* profile) { + DCHECK(IsEnabled()); +} + +MediaEngagementService::~MediaEngagementService() = default;
diff --git a/chrome/browser/media/media_engagement_service.h b/chrome/browser/media/media_engagement_service.h new file mode 100644 index 0000000..3701c02 --- /dev/null +++ b/chrome/browser/media/media_engagement_service.h
@@ -0,0 +1,42 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_SERVICE_H_ +#define CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_SERVICE_H_ + +#include <set> + +#include "base/macros.h" +#include "components/keyed_service/core/keyed_service.h" + +class Profile; + +namespace content { +class WebContents; +} // namespace content + +class MediaEngagementService : public KeyedService { + public: + // Returns the instance attached to the given |profile|. + static MediaEngagementService* Get(Profile* profile); + + // Returns whether the feature is enabled. + static bool IsEnabled(); + + // Observe the given |web_contents| by creating an internal + // WebContentsObserver. + static void CreateWebContentsObserver(content::WebContents* web_contents); + + explicit MediaEngagementService(Profile* profile); + ~MediaEngagementService() override; + + private: + class ContentsObserver; + + std::set<ContentsObserver*> contents_observers_; + + DISALLOW_COPY_AND_ASSIGN(MediaEngagementService); +}; + +#endif // CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_SERVICE_H_
diff --git a/chrome/browser/media/media_engagement_service_factory.cc b/chrome/browser/media/media_engagement_service_factory.cc new file mode 100644 index 0000000..8bab790 --- /dev/null +++ b/chrome/browser/media/media_engagement_service_factory.cc
@@ -0,0 +1,39 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/media/media_engagement_service_factory.h" + +#include "chrome/browser/media/media_engagement_service.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +// static +MediaEngagementService* MediaEngagementServiceFactory::GetForProfile( + Profile* profile) { + return static_cast<MediaEngagementService*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +// static +MediaEngagementServiceFactory* MediaEngagementServiceFactory::GetInstance() { + return base::Singleton<MediaEngagementServiceFactory>::get(); +} + +MediaEngagementServiceFactory::MediaEngagementServiceFactory() + : BrowserContextKeyedServiceFactory( + "MediaEngagementServiceFactory", + BrowserContextDependencyManager::GetInstance()) {} + +MediaEngagementServiceFactory::~MediaEngagementServiceFactory() {} + +KeyedService* MediaEngagementServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new MediaEngagementService(Profile::FromBrowserContext(context)); +} + +content::BrowserContext* MediaEngagementServiceFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextOwnInstanceInIncognito(context); +}
diff --git a/chrome/browser/media/media_engagement_service_factory.h b/chrome/browser/media/media_engagement_service_factory.h new file mode 100644 index 0000000..1eee510 --- /dev/null +++ b/chrome/browser/media/media_engagement_service_factory.h
@@ -0,0 +1,35 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_SERVICE_FACTORY_H_ + +#include "base/macros.h" +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class MediaEngagementService; +class Profile; + +class MediaEngagementServiceFactory : public BrowserContextKeyedServiceFactory { + public: + static MediaEngagementService* GetForProfile(Profile* profile); + static MediaEngagementServiceFactory* GetInstance(); + + private: + friend struct base::DefaultSingletonTraits<MediaEngagementServiceFactory>; + + MediaEngagementServiceFactory(); + ~MediaEngagementServiceFactory() override; + + // BrowserContextKeyedBaseFactory methods: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* profile) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; + + DISALLOW_COPY_AND_ASSIGN(MediaEngagementServiceFactory); +}; + +#endif // CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_SERVICE_FACTORY_H_
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list_unittest.cc b/chrome/browser/media/webrtc/native_desktop_media_list_unittest.cc index 037db01..42467a5a 100644 --- a/chrome/browser/media/webrtc/native_desktop_media_list_unittest.cc +++ b/chrome/browser/media/webrtc/native_desktop_media_list_unittest.cc
@@ -16,8 +16,9 @@ #include "base/single_thread_task_runner.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" +#include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/media/webrtc/desktop_media_list_observer.h" -#include "content/public/test/test_browser_thread.h" +#include "content/public/test/test_browser_thread_bundle.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" @@ -161,15 +162,13 @@ EXPECT_EQ(expected_list_size, model->GetSourceCount()); } -ACTION_P(QuitMessageLoop, message_loop) { - message_loop->task_runner()->PostTask( - FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); +ACTION_P2(QuitRunLoop, task_runner, run_loop) { + task_runner->PostTask(FROM_HERE, run_loop->QuitWhenIdleClosure()); } class NativeDesktopMediaListTest : public views::ViewsTestBase { public: - NativeDesktopMediaListTest() - : ui_thread_(content::BrowserThread::UI, message_loop()) {} + NativeDesktopMediaListTest() = default; void TearDown() override { for (size_t i = 0; i < desktop_widgets_.size(); i++) @@ -306,6 +305,8 @@ aura_window_first_index--; } + base::RunLoop run_loop; + { testing::InSequence dummy; size_t source_count = screen ? window_count + 1 : window_count; @@ -318,10 +319,11 @@ } EXPECT_CALL(observer_, OnSourceThumbnailChanged(model_.get(), source_count - 1)) - .WillOnce(QuitMessageLoop(message_loop())); + .WillOnce( + QuitRunLoop(base::ThreadTaskRunnerHandle::Get(), &run_loop)); } model_->StartUpdating(&observer_); - base::RunLoop().Run(); + run_loop.Run(); if (screen) { EXPECT_EQ(model_->GetSource(0).id.type, DesktopMediaID::TYPE_SCREEN); @@ -347,6 +349,8 @@ } protected: + content::TestBrowserThreadBundle test_browser_thread_bundle_; + // Must be listed before |model_|, so it's destroyed last. MockObserver observer_; @@ -358,8 +362,6 @@ std::map<DesktopMediaID::Id, DesktopMediaID::Id> native_aura_id_map_; std::unique_ptr<NativeDesktopMediaList> model_; - content::TestBrowserThread ui_thread_; - DISALLOW_COPY_AND_ASSIGN(NativeDesktopMediaListTest); }; @@ -380,15 +382,18 @@ TEST_F(NativeDesktopMediaListTest, AddNativeWindow) { AddWindowsAndVerify(true, kDefaultWindowCount, kDefaultAuraCount, false); + base::RunLoop run_loop; + const int index = kDefaultWindowCount + 1; EXPECT_CALL(observer_, OnSourceAdded(model_.get(), index)) - .WillOnce(DoAll(CheckListSize(model_.get(), index + 1), - QuitMessageLoop(message_loop()))); + .WillOnce( + DoAll(CheckListSize(model_.get(), index + 1), + QuitRunLoop(base::ThreadTaskRunnerHandle::Get(), &run_loop))); AddNativeWindow(index); window_capturer_->SetWindowList(window_list_); - base::RunLoop().Run(); + run_loop.Run(); EXPECT_EQ(model_->GetSource(index).id.type, DesktopMediaID::TYPE_WINDOW); EXPECT_EQ(model_->GetSource(index).id.id, index); @@ -398,15 +403,18 @@ TEST_F(NativeDesktopMediaListTest, AddAuraWindow) { AddWindowsAndVerify(true, kDefaultWindowCount, kDefaultAuraCount, false); + base::RunLoop run_loop; + const int index = kDefaultWindowCount + 1; EXPECT_CALL(observer_, OnSourceAdded(model_.get(), index)) - .WillOnce(DoAll(CheckListSize(model_.get(), index + 1), - QuitMessageLoop(message_loop()))); + .WillOnce( + DoAll(CheckListSize(model_.get(), index + 1), + QuitRunLoop(base::ThreadTaskRunnerHandle::Get(), &run_loop))); AddAuraWindow(); window_capturer_->SetWindowList(window_list_); - base::RunLoop().Run(); + run_loop.Run(); int native_id = window_list_.back().id; EXPECT_EQ(model_->GetSource(index).id.type, DesktopMediaID::TYPE_WINDOW); @@ -419,61 +427,72 @@ TEST_F(NativeDesktopMediaListTest, RemoveNativeWindow) { AddWindowsAndVerify(true, kDefaultWindowCount, kDefaultAuraCount, false); + base::RunLoop run_loop; + EXPECT_CALL(observer_, OnSourceRemoved(model_.get(), 1)) - .WillOnce(DoAll(CheckListSize(model_.get(), kDefaultWindowCount), - QuitMessageLoop(message_loop()))); + .WillOnce( + DoAll(CheckListSize(model_.get(), kDefaultWindowCount), + QuitRunLoop(base::ThreadTaskRunnerHandle::Get(), &run_loop))); window_list_.erase(window_list_.begin()); window_capturer_->SetWindowList(window_list_); - base::RunLoop().Run(); + run_loop.Run(); } #if defined(ENABLE_AURA_WINDOW_TESTS) TEST_F(NativeDesktopMediaListTest, RemoveAuraWindow) { AddWindowsAndVerify(true, kDefaultWindowCount, kDefaultAuraCount, false); + base::RunLoop run_loop; + int aura_window_start_index = kDefaultWindowCount - kDefaultAuraCount + 1; EXPECT_CALL(observer_, OnSourceRemoved(model_.get(), aura_window_start_index)) - .WillOnce(DoAll(CheckListSize(model_.get(), kDefaultWindowCount), - QuitMessageLoop(message_loop()))); + .WillOnce( + DoAll(CheckListSize(model_.get(), kDefaultWindowCount), + QuitRunLoop(base::ThreadTaskRunnerHandle::Get(), &run_loop))); RemoveAuraWindow(0); window_capturer_->SetWindowList(window_list_); - base::RunLoop().Run(); + run_loop.Run(); } #endif // defined(ENABLE_AURA_WINDOW_TESTS) TEST_F(NativeDesktopMediaListTest, RemoveAllWindows) { AddWindowsAndVerify(true, kDefaultWindowCount, kDefaultAuraCount, false); + base::RunLoop run_loop; + testing::InSequence seq; for (int i = 0; i < kDefaultWindowCount - 1; i++) { EXPECT_CALL(observer_, OnSourceRemoved(model_.get(), 1)) .WillOnce(CheckListSize(model_.get(), kDefaultWindowCount - i)); } EXPECT_CALL(observer_, OnSourceRemoved(model_.get(), 1)) - .WillOnce(DoAll(CheckListSize(model_.get(), 1), - QuitMessageLoop(message_loop()))); + .WillOnce( + DoAll(CheckListSize(model_.get(), 1), + QuitRunLoop(base::ThreadTaskRunnerHandle::Get(), &run_loop))); window_list_.clear(); window_capturer_->SetWindowList(window_list_); - base::RunLoop().Run(); + run_loop.Run(); } TEST_F(NativeDesktopMediaListTest, UpdateTitle) { AddWindowsAndVerify(true, kDefaultWindowCount, kDefaultAuraCount, false); + base::RunLoop run_loop; + EXPECT_CALL(observer_, OnSourceNameChanged(model_.get(), 1)) - .WillOnce(QuitMessageLoop(message_loop())); + .WillOnce(QuitRunLoop(base::ThreadTaskRunnerHandle::Get(), &run_loop)); const std::string kTestTitle = "New Title"; window_list_[0].title = kTestTitle; window_capturer_->SetWindowList(window_list_); - base::RunLoop().Run(); + run_loop.Run(); EXPECT_EQ(model_->GetSource(1).name, base::UTF8ToUTF16(kTestTitle)); } @@ -488,24 +507,29 @@ .Times(testing::AnyNumber()); } + base::RunLoop run_loop; + EXPECT_CALL(observer_, OnSourceThumbnailChanged(model_.get(), 1)) - .WillOnce(QuitMessageLoop(message_loop())); + .WillOnce(QuitRunLoop(base::ThreadTaskRunnerHandle::Get(), &run_loop)); // Update frame for the window and verify that we get notification about it. window_capturer_->SetNextFrameValue(1, 10); - base::RunLoop().Run(); + run_loop.Run(); } TEST_F(NativeDesktopMediaListTest, MoveWindow) { AddWindowsAndVerify(true, kDefaultWindowCount, kDefaultAuraCount, false); + base::RunLoop run_loop; + EXPECT_CALL(observer_, OnSourceMoved(model_.get(), 2, 1)) - .WillOnce(DoAll(CheckListSize(model_.get(), kDefaultWindowCount + 1), - QuitMessageLoop(message_loop()))); + .WillOnce( + DoAll(CheckListSize(model_.get(), kDefaultWindowCount + 1), + QuitRunLoop(base::ThreadTaskRunnerHandle::Get(), &run_loop))); std::swap(window_list_[0], window_list_[1]); window_capturer_->SetWindowList(window_list_); - base::RunLoop().Run(); + run_loop.Run(); }
diff --git a/chrome/browser/memory/tab_manager_delegate_chromeos.cc b/chrome/browser/memory/tab_manager_delegate_chromeos.cc index e39f69f..08c658b 100644 --- a/chrome/browser/memory/tab_manager_delegate_chromeos.cc +++ b/chrome/browser/memory/tab_manager_delegate_chromeos.cc
@@ -94,8 +94,10 @@ std::ostream& operator<<(std::ostream& os, const ProcessType& type) { switch (type) { + case ProcessType::FOCUSED_TAB: + return os << "FOCUSED_TAB"; case ProcessType::FOCUSED_APP: - return os << "FOCUSED_APP/FOCUSED_TAB"; + return os << "FOCUSED_APP"; case ProcessType::VISIBLE_APP: return os << "VISIBLE_APP"; case ProcessType::BACKGROUND_TAB: @@ -144,7 +146,8 @@ return TabManager::CompareTabStats(*tab(), *rhs.tab()); // Impossible case. If app and tab are mixed in one process type, favor // apps. - NOTREACHED() << "Undefined comparison between apps and tabs"; + NOTREACHED() << "Undefined comparison between apps and tabs: process_type=" + << process_type(); return app(); }
diff --git a/chrome/browser/memory/tab_manager_delegate_chromeos.h b/chrome/browser/memory/tab_manager_delegate_chromeos.h index 931767df..0c86a265 100644 --- a/chrome/browser/memory/tab_manager_delegate_chromeos.h +++ b/chrome/browser/memory/tab_manager_delegate_chromeos.h
@@ -33,16 +33,18 @@ // Possible types of Apps/Tabs processes. From most important to least // important. enum class ProcessType { - // There can be only one process having process type "FOCUSED_APP" - // or "FOCUSED_TAB" in the system at any give time (i.e., The focused window - // could be either a chrome window or an Android app. But not both. - FOCUSED_APP = 1, - FOCUSED_TAB = FOCUSED_APP, + // Conceptually, the system cannot have both FOCUSED_TAB and FOCUSED_APP at + // the same time, but because Chrome cannot retrieve FOCUSED_APP status + // synchronously, Chrome may still see both at the same time. When that + // happens, treat FOCUSED_TAB as the most important since the (synchronously + // retrieved) tab information is more reliable and up-to-date. + FOCUSED_TAB = 1, + FOCUSED_APP = 2, - VISIBLE_APP = 2, - BACKGROUND_TAB = 3, - BACKGROUND_APP = 4, - UNKNOWN_TYPE = 5, + VISIBLE_APP = 3, + BACKGROUND_TAB = 4, + BACKGROUND_APP = 5, + UNKNOWN_TYPE = 6, }; // The Chrome OS TabManagerDelegate is responsible for keeping the @@ -99,6 +101,8 @@ private: FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, CandidatesSorted); FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, + CandidatesSortedWithFocusedAppAndTab); + FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, DoNotKillRecentlyKilledArcProcesses); FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, IsRecentlyKilledArcProcess); FRIEND_TEST_ALL_PREFIXES(TabManagerDelegateTest, KillMultipleProcesses);
diff --git a/chrome/browser/memory/tab_manager_delegate_chromeos_unittest.cc b/chrome/browser/memory/tab_manager_delegate_chromeos_unittest.cc index fd25dbbe..8d10119 100644 --- a/chrome/browser/memory/tab_manager_delegate_chromeos_unittest.cc +++ b/chrome/browser/memory/tab_manager_delegate_chromeos_unittest.cc
@@ -109,6 +109,28 @@ EXPECT_EQ("service", candidates[8].app()->process_name()); } +// Occasionally, Chrome sees both FOCUSED_TAB and FOCUSED_APP at the same time. +// Test that Chrome treats the former as a more important process. +TEST_F(TabManagerDelegateTest, CandidatesSortedWithFocusedAppAndTab) { + std::vector<arc::ArcProcess> arc_processes; + arc_processes.emplace_back(1, 10, "focused", arc::mojom::ProcessState::TOP, + kIsFocused, 100); + TabStats tab1; + tab1.tab_contents_id = 100; + tab1.is_pinned = true; + tab1.is_selected = true; + const TabStatsList tab_list = {tab1}; + + const std::vector<TabManagerDelegate::Candidate> candidates = + TabManagerDelegate::GetSortedCandidates(tab_list, arc_processes); + ASSERT_EQ(2U, candidates.size()); + // FOCUSED_TAB should be the first one. + ASSERT_TRUE(candidates[0].tab()); + EXPECT_EQ(100, candidates[0].tab()->tab_contents_id); + ASSERT_TRUE(candidates[1].app()); + EXPECT_EQ("focused", candidates[1].app()->process_name()); +} + class MockTabManagerDelegate : public TabManagerDelegate { public: MockTabManagerDelegate()
diff --git a/chrome/browser/payments/payment_request_factory.cc b/chrome/browser/payments/payment_request_factory.cc index ccf5964..e74a33b 100644 --- a/chrome/browser/payments/payment_request_factory.cc +++ b/chrome/browser/payments/payment_request_factory.cc
@@ -4,25 +4,23 @@ #include "chrome/browser/payments/payment_request_factory.h" -#include <memory> +#include <utility> #include "base/logging.h" #include "base/memory/ptr_util.h" #include "chrome/browser/payments/chrome_payment_request_delegate.h" #include "components/payments/content/payment_request_web_contents_manager.h" -#include "components/payments/core/payment_request_delegate.h" -#include "content/public/browser/web_contents.h" namespace payments { -void CreatePaymentRequestForWebContents( - content::WebContents* web_contents, - const service_manager::BindSourceInfo& source_info, - payments::mojom::PaymentRequestRequest request) { +void CreatePaymentRequest(content::RenderFrameHost* render_frame_host, + content::WebContents* web_contents, + const service_manager::BindSourceInfo& source_info, + mojom::PaymentRequestRequest request) { DCHECK(web_contents); PaymentRequestWebContentsManager::GetOrCreateForWebContents(web_contents) ->CreatePaymentRequest( - web_contents, + render_frame_host, web_contents, base::MakeUnique<ChromePaymentRequestDelegate>(web_contents), std::move(request), /*observer_for_testing=*/nullptr);
diff --git a/chrome/browser/payments/payment_request_factory.h b/chrome/browser/payments/payment_request_factory.h index 8188568..f575a56 100644 --- a/chrome/browser/payments/payment_request_factory.h +++ b/chrome/browser/payments/payment_request_factory.h
@@ -6,22 +6,23 @@ #define CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_FACTORY_H_ #include "components/payments/mojom/payment_request.mojom.h" -#include "mojo/public/cpp/bindings/binding.h" #include "services/service_manager/public/cpp/bind_source_info.h" namespace content { +class RenderFrameHost; class WebContents; } namespace payments { -// Will create a PaymentRequest attached to |web_contents|, based on the -// contents of |request|. This is called everytime a new Mojo PaymentRequest is -// created. -void CreatePaymentRequestForWebContents( - content::WebContents* web_contents, - const service_manager::BindSourceInfo& source_info, - payments::mojom::PaymentRequestRequest request); +// Will create a PaymentRequest based on the contents of |request|. The +// |request| was initiated by the frame hosted by |render_frame_host|, which is +// inside of |web_contents|. This function is called every time a new instance +// of PaymentRequest is created in the renderer. +void CreatePaymentRequest(content::RenderFrameHost* render_frame_host, + content::WebContents* web_contents, + const service_manager::BindSourceInfo& source_info, + mojom::PaymentRequestRequest request); } // namespace payments
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index d101a40a..500f488 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -261,6 +261,7 @@ #endif #if defined(USE_ASH) +#include "ash/shell.h" #include "chrome/browser/ui/ash/chrome_launcher_prefs.h" #endif @@ -644,6 +645,7 @@ #if defined(USE_ASH) RegisterChromeLauncherUserPrefs(registry); + ash::Shell::RegisterPrefs(registry); #endif #if !defined(OS_ANDROID) && !defined(OS_IOS)
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index 3320105..42114fc8 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -28,6 +28,8 @@ #include "chrome/browser/google/google_url_tracker_factory.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h" +#include "chrome/browser/media/media_engagement_service.h" +#include "chrome/browser/media/media_engagement_service_factory.h" #include "chrome/browser/media/router/media_router_factory.h" #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h" #include "chrome/browser/net/nqe/ui_network_quality_estimator_service_factory.h" @@ -269,6 +271,8 @@ ->SetUIDelegateFactory(std::move(networking_private_ui_delegate_factory)); #endif #endif + if (MediaEngagementService::IsEnabled()) + MediaEngagementServiceFactory::GetInstance(); media_router::MediaRouterFactory::GetInstance(); #if !defined(OS_ANDROID) media_router::MediaRouterUIServiceFactory::GetInstance();
diff --git a/chrome/browser/supervised_user/supervised_user_service_factory.cc b/chrome/browser/supervised_user/supervised_user_service_factory.cc index 1664652..09ceffd 100644 --- a/chrome/browser/supervised_user/supervised_user_service_factory.cc +++ b/chrome/browser/supervised_user/supervised_user_service_factory.cc
@@ -25,6 +25,13 @@ } // static +SupervisedUserService* SupervisedUserServiceFactory::GetForProfileIfExists( + Profile* profile) { + return static_cast<SupervisedUserService*>( + GetInstance()->GetServiceForBrowserContext(profile, /*create=*/false)); +} + +// static SupervisedUserServiceFactory* SupervisedUserServiceFactory::GetInstance() { return base::Singleton<SupervisedUserServiceFactory>::get(); } @@ -43,8 +50,6 @@ extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); #endif DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance()); - - // TODO(skym, crbug.com/705545): Fix this circular dependency. DependsOn(ProfileSyncServiceFactory::GetInstance()); }
diff --git a/chrome/browser/supervised_user/supervised_user_service_factory.h b/chrome/browser/supervised_user/supervised_user_service_factory.h index 5106700..f850c2c 100644 --- a/chrome/browser/supervised_user/supervised_user_service_factory.h +++ b/chrome/browser/supervised_user/supervised_user_service_factory.h
@@ -16,6 +16,8 @@ public: static SupervisedUserService* GetForProfile(Profile* profile); + static SupervisedUserService* GetForProfileIfExists(Profile* profile); + static SupervisedUserServiceFactory* GetInstance(); // Used to create instances for testing.
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index 6a48990..c952021 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -447,10 +447,16 @@ return SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext( profile_)->AsWeakPtr(); #endif // !defined(OS_ANDROID) - case syncer::SUPERVISED_USER_WHITELISTS: - return SupervisedUserServiceFactory::GetForProfile(profile_) - ->GetWhitelistService() - ->AsWeakPtr(); + case syncer::SUPERVISED_USER_WHITELISTS: { + // Unlike other types here, ProfileSyncServiceFactory does not declare a + // DependsOn the SupervisedUserServiceFactory (in order to avoid circular + // dependency), which means we cannot assume it is still alive. + SupervisedUserService* supervised_user_service = + SupervisedUserServiceFactory::GetForProfileIfExists(profile_); + if (supervised_user_service) + return supervised_user_service->GetWhitelistService()->AsWeakPtr(); + return base::WeakPtr<syncer::SyncableService>(); + } #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) case syncer::ARTICLES: { dom_distiller::DomDistillerService* service = @@ -507,7 +513,7 @@ ->AsWeakPtr(); #endif // defined(OS_CHROMEOS) case syncer::TYPED_URLS: - // TODO(gangwu):implement TypedURLSyncBridge and return real + // TODO(gangwu): Implement TypedURLSyncBridge and return real // TypedURLSyncBridge here. return base::WeakPtr<syncer::ModelTypeSyncBridge>(); default:
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc index 743d212..3fda480 100644 --- a/chrome/browser/sync/profile_sync_service_factory.cc +++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -141,8 +141,6 @@ DependsOn(SigninManagerFactory::GetInstance()); DependsOn(SpellcheckServiceFactory::GetInstance()); #if BUILDFLAG(ENABLE_SUPERVISED_USERS) - // TODO(skym, crbug.com/705545): Fix this circular dependency. - // DependsOn(SupervisedUserServiceFactory::GetInstance()); DependsOn(SupervisedUserSettingsServiceFactory::GetInstance()); #if !defined(OS_ANDROID) DependsOn(SupervisedUserSharedSettingsServiceFactory::GetInstance());
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index e6c3445..ee693f8 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -2270,6 +2270,8 @@ "android/infobars/instant_apps_infobar.h", "android/infobars/permission_infobar.cc", "android/infobars/permission_infobar.h", + "android/infobars/reader_mode_infobar.cc", + "android/infobars/reader_mode_infobar.h", "android/infobars/search_geolocation_disclosure_infobar.cc", "android/infobars/search_geolocation_disclosure_infobar.h", "android/infobars/simple_confirm_infobar_builder.cc", @@ -2412,6 +2414,8 @@ "cocoa/download/download_util_mac.mm", "cocoa/first_run_dialog.h", "cocoa/first_run_dialog.mm", + "cocoa/first_run_dialog_controller.h", + "cocoa/first_run_dialog_controller.mm", "cocoa/handoff_active_url_observer.cc", "cocoa/handoff_active_url_observer.h", "cocoa/handoff_active_url_observer_bridge.h",
diff --git a/chrome/browser/ui/android/infobars/reader_mode_infobar.cc b/chrome/browser/ui/android/infobars/reader_mode_infobar.cc new file mode 100644 index 0000000..e424ebd6 --- /dev/null +++ b/chrome/browser/ui/android/infobars/reader_mode_infobar.cc
@@ -0,0 +1,63 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/android/infobars/reader_mode_infobar.h" + +#include <memory> +#include <utility> + +#include "base/memory/ptr_util.h" +#include "chrome/browser/android/tab_android.h" +#include "chrome/browser/infobars/infobar_service.h" +#include "components/infobars/core/infobar_delegate.h" +#include "content/public/browser/web_contents.h" +#include "jni/ReaderModeInfoBar_jni.h" +#include "ui/android/window_android.h" + +using base::android::JavaParamRef; +using base::android::ScopedJavaLocalRef; + +class ReaderModeInfoBarDelegate : public infobars::InfoBarDelegate { + public: + ~ReaderModeInfoBarDelegate() override {} + + infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override { + return InfoBarDelegate::InfoBarIdentifier::READER_MODE_INFOBAR_ANDROID; + } + + bool EqualsDelegate(infobars::InfoBarDelegate* delegate) const override { + return delegate->GetIdentifier() == GetIdentifier(); + } +}; + +ReaderModeInfoBar::ReaderModeInfoBar( + std::unique_ptr<ReaderModeInfoBarDelegate> delegate) + : InfoBarAndroid(std::move(delegate)) {} + +ReaderModeInfoBar::~ReaderModeInfoBar() {} + +infobars::InfoBarDelegate* ReaderModeInfoBar::GetDelegate() { + return delegate(); +} + +ScopedJavaLocalRef<jobject> ReaderModeInfoBar::CreateRenderInfoBar( + JNIEnv* env) { + return Java_ReaderModeInfoBar_create(env); +} + +void ReaderModeInfoBar::ProcessButton(int action) {} + +void Create(JNIEnv* env, + const JavaParamRef<jclass>& j_caller, + const JavaParamRef<jobject>& j_tab) { + InfoBarService* service = InfoBarService::FromWebContents( + TabAndroid::GetNativeTab(env, j_tab)->web_contents()); + + service->AddInfoBar(base::MakeUnique<ReaderModeInfoBar>( + base::MakeUnique<ReaderModeInfoBarDelegate>())); +} + +bool RegisterReaderModeInfoBar(JNIEnv* env) { + return RegisterNativesImpl(env); +}
diff --git a/chrome/browser/ui/android/infobars/reader_mode_infobar.h b/chrome/browser/ui/android/infobars/reader_mode_infobar.h new file mode 100644 index 0000000..22059e2 --- /dev/null +++ b/chrome/browser/ui/android/infobars/reader_mode_infobar.h
@@ -0,0 +1,37 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ANDROID_INFOBARS_READER_MODE_INFOBAR_H_ +#define CHROME_BROWSER_UI_ANDROID_INFOBARS_READER_MODE_INFOBAR_H_ + +#include "base/android/jni_android.h" +#include "base/android/scoped_java_ref.h" +#include "base/macros.h" +#include "chrome/browser/ui/android/infobars/infobar_android.h" +#include "components/infobars/core/infobar_delegate.h" + +class ReaderModeInfoBarDelegate; + +class ReaderModeInfoBar : public InfoBarAndroid { + public: + explicit ReaderModeInfoBar( + std::unique_ptr<ReaderModeInfoBarDelegate> delegate); + ~ReaderModeInfoBar() override; + + protected: + infobars::InfoBarDelegate* GetDelegate(); + + // InfoBarAndroid overrides. + void ProcessButton(int action) override; + base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar( + JNIEnv* env) override; + + private: + DISALLOW_COPY_AND_ASSIGN(ReaderModeInfoBar); +}; + +// Register native methods. +bool RegisterReaderModeInfoBar(JNIEnv* env); + +#endif // CHROME_BROWSER_UI_ANDROID_INFOBARS_READER_MODE_INFOBAR_H_
diff --git a/chrome/browser/ui/ash/session_controller_client.cc b/chrome/browser/ui/ash/session_controller_client.cc index 6d15a76..96b2ab5e 100644 --- a/chrome/browser/ui/ash/session_controller_client.cc +++ b/chrome/browser/ui/ash/session_controller_client.cc
@@ -26,6 +26,7 @@ #include "chrome/grit/theme_resources.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/session_manager_client.h" +#include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" #include "components/session_manager/core/session_manager.h" #include "content/public/browser/notification_service.h" @@ -377,6 +378,18 @@ ->AddObserver(this); } + base::Closure session_info_changed_closure = + base::Bind(&SessionControllerClient::SendSessionInfoIfChanged, + weak_ptr_factory_.GetWeakPtr()); + std::unique_ptr<PrefChangeRegistrar> pref_change_registrar = + base::MakeUnique<PrefChangeRegistrar>(); + pref_change_registrar->Init(profile->GetPrefs()); + pref_change_registrar->Add(prefs::kAllowScreenLock, + session_info_changed_closure); + pref_change_registrar->Add(prefs::kEnableAutoScreenLock, + session_info_changed_closure); + pref_change_registrars_.push_back(std::move(pref_change_registrar)); + // Needed because the user-to-profile mapping isn't available until later, // which is needed in UserToUserSession(). base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/chrome/browser/ui/ash/session_controller_client.h b/chrome/browser/ui/ash/session_controller_client.h index 9fffbe0..a7e4dc4 100644 --- a/chrome/browser/ui/ash/session_controller_client.h +++ b/chrome/browser/ui/ash/session_controller_client.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_UI_ASH_SESSION_CONTROLLER_CLIENT_H_ #define CHROME_BROWSER_UI_ASH_SESSION_CONTROLLER_CLIENT_H_ +#include <vector> + #include "ash/public/interfaces/session_controller.mojom.h" #include "base/callback_forward.h" #include "base/gtest_prod_util.h" @@ -18,6 +20,7 @@ #include "mojo/public/cpp/bindings/binding.h" class Profile; +class PrefChangeRegistrar; namespace ash { enum class AddUserSessionPolicy; @@ -97,6 +100,7 @@ private: FRIEND_TEST_ALL_PREFIXES(SessionControllerClientTest, SendUserSession); FRIEND_TEST_ALL_PREFIXES(SessionControllerClientTest, SupervisedUser); + FRIEND_TEST_ALL_PREFIXES(SessionControllerClientTest, UserPrefsChange); // Called when the login profile is ready. void OnLoginUserProfilePrepared(Profile* profile); @@ -131,6 +135,11 @@ content::NotificationRegistrar registrar_; + // Pref change observers to update session info when a relevant user pref + // changes. There is one observer per user and they have no particular order, + // i.e. they don't much the user session order. + std::vector<std::unique_ptr<PrefChangeRegistrar>> pref_change_registrars_; + // Used to suppress duplicate IPCs to ash. ash::mojom::SessionInfoPtr last_sent_session_info_; ash::mojom::UserSessionPtr last_sent_user_session_;
diff --git a/chrome/browser/ui/ash/session_controller_client_unittest.cc b/chrome/browser/ui/ash/session_controller_client_unittest.cc index 660e1a8..3304917b 100644 --- a/chrome/browser/ui/ash/session_controller_client_unittest.cc +++ b/chrome/browser/ui/ash/session_controller_client_unittest.cc
@@ -22,6 +22,7 @@ #include "chrome/common/pref_names.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile_manager.h" +#include "components/prefs/pref_service.h" #include "components/session_manager/core/session_manager.h" #include "components/signin/core/account_id/account_id.h" #include "components/user_manager/user_manager.h" @@ -66,6 +67,25 @@ NotifyOnLogin(); } + user_manager::UserList GetUnlockUsers() const override { + // Test case UserPrefsChange expects that the list of the unlock users + // depends on prefs::kAllowScreenLock. + user_manager::UserList unlock_users; + for (user_manager::User* user : users_) { + Profile* user_profile = + chromeos::ProfileHelper::Get()->GetProfileByUser(user); + // Skip if user has a profile and kAllowScreenLock is set to false. + if (user_profile && + !user_profile->GetPrefs()->GetBoolean(prefs::kAllowScreenLock)) { + continue; + } + + unlock_users.push_back(user); + } + + return unlock_users; + } + private: DISALLOW_COPY_AND_ASSIGN(TestChromeUserManager); }; @@ -172,28 +192,29 @@ TestChromeUserManager* user_manager() { return user_manager_; } // Adds a regular user with a profile. - void InitForMultiProfile() { + TestingProfile* InitForMultiProfile() { const AccountId account_id(AccountId::FromUserEmail(kUser)); const user_manager::User* user = user_manager()->AddUser(account_id); // Note that user profiles are created after user login in reality. - CreateTestingProfile(user); + return CreateTestingProfile(user); } - // Calls private methods to create a testing profile. - void CreateTestingProfile(const user_manager::User* user) { + // Calls private methods to create a testing profile. The created profile + // is owned by ProfileManager. + TestingProfile* CreateTestingProfile(const user_manager::User* user) { const AccountId& account_id = user->GetAccountId(); - user_profile_ = + TestingProfile* profile = profile_manager_->CreateTestingProfile(account_id.GetUserEmail()); - user_profile_->set_profile_name(account_id.GetUserEmail()); - chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting( - user, user_profile_); + profile->set_profile_name(account_id.GetUserEmail()); + chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, + profile); + return profile; } content::TestBrowserThreadBundle threads_; std::unique_ptr<policy::PolicyCertVerifier> cert_verifier_; std::unique_ptr<TestingProfileManager> profile_manager_; - TestingProfile* user_profile_; session_manager::SessionManager session_manager_; private: @@ -246,7 +267,7 @@ // Make sure MultiProfile disabled by primary user policy. TEST_F(SessionControllerClientTest, MultiProfileDisallowedByUserPolicy) { - InitForMultiProfile(); + TestingProfile* user_profile = InitForMultiProfile(); EXPECT_EQ(ash::AddUserSessionPolicy::ALLOWED, SessionControllerClient::GetAddUserSessionPolicy()); const AccountId account_id(AccountId::FromUserEmail(kUser)); @@ -258,7 +279,7 @@ EXPECT_EQ(ash::AddUserSessionPolicy::ALLOWED, SessionControllerClient::GetAddUserSessionPolicy()); - user_profile_->GetPrefs()->SetString( + user_profile->GetPrefs()->SetString( prefs::kMultiProfileUserBehavior, chromeos::MultiProfileUserController::kBehaviorNotAllowed); EXPECT_EQ(ash::AddUserSessionPolicy::ERROR_NOT_ALLOWED_PRIMARY_USER, @@ -287,7 +308,7 @@ // Make sure MultiProfile disabled by primary user certificates in memory. TEST_F(SessionControllerClientTest, MultiProfileDisallowedByPrimaryUserCertificatesInMemory) { - InitForMultiProfile(); + TestingProfile* user_profile = InitForMultiProfile(); user_manager()->AddUser(AccountId::FromUserEmail("bb@b.b")); const AccountId account_id(AccountId::FromUserEmail(kUser)); @@ -298,9 +319,9 @@ g_policy_cert_verifier_for_factory = cert_verifier_.get(); ASSERT_TRUE( policy::PolicyCertServiceFactory::GetInstance()->SetTestingFactoryAndUse( - user_profile_, CreateTestPolicyCertService)); + user_profile, CreateTestPolicyCertService)); policy::PolicyCertService* service = - policy::PolicyCertServiceFactory::GetForProfile(user_profile_); + policy::PolicyCertServiceFactory::GetForProfile(user_profile); ASSERT_TRUE(service); EXPECT_FALSE(service->has_policy_certificates()); @@ -352,13 +373,13 @@ // Make sure adding users to multiprofiles disabled by primary user policy. TEST_F(SessionControllerClientTest, AddUserToMultiprofileDisallowedByPrimaryUserPolicy) { - InitForMultiProfile(); + TestingProfile* user_profile = InitForMultiProfile(); EXPECT_EQ(ash::AddUserSessionPolicy::ALLOWED, SessionControllerClient::GetAddUserSessionPolicy()); const AccountId account_id(AccountId::FromUserEmail(kUser)); user_manager()->LoginUser(account_id); - user_profile_->GetPrefs()->SetString( + user_profile->GetPrefs()->SetString( prefs::kMultiProfileUserBehavior, chromeos::MultiProfileUserController::kBehaviorNotAllowed); user_manager()->AddUser(AccountId::FromUserEmail("bb@b.b")); @@ -429,17 +450,17 @@ session_controller.last_user_session()->type); // Simulate profile creation after login. - CreateTestingProfile(user); - user_profile_->SetSupervisedUserId("child-id"); + TestingProfile* user_profile = CreateTestingProfile(user); + user_profile->SetSupervisedUserId("child-id"); // Simulate supervised user custodians. - PrefService* prefs = user_profile_->GetPrefs(); + PrefService* prefs = user_profile->GetPrefs(); prefs->SetString(prefs::kSupervisedUserCustodianEmail, "parent1@test.com"); prefs->SetString(prefs::kSupervisedUserSecondCustodianEmail, "parent2@test.com"); // Simulate the notification that the profile is ready. - client.OnLoginUserProfilePrepared(user_profile_); + client.OnLoginUserProfilePrepared(user_profile); base::RunLoop().RunUntilIdle(); // For PostTask and mojo interface. // The custodians were sent over the mojo interface. @@ -457,3 +478,44 @@ EXPECT_EQ("parent3@test.com", session_controller.last_user_session()->custodian_email); } + +TEST_F(SessionControllerClientTest, UserPrefsChange) { + // Create an object to test and connect it to our test interface. + SessionControllerClient client; + TestSessionController session_controller; + client.session_controller_ = session_controller.CreateInterfacePtrAndBind(); + client.Init(); + SessionControllerClient::FlushForTesting(); + + // Simulate login. + const AccountId account_id(AccountId::FromUserEmail("user@test.com")); + const user_manager::User* user = user_manager()->AddUser(account_id); + session_manager_.CreateSession( + account_id, chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting( + "user@test.com")); + session_manager_.SetSessionState(SessionState::ACTIVE); + SessionControllerClient::FlushForTesting(); + + // Simulate the notification that the profile is ready. + TestingProfile* const user_profile = CreateTestingProfile(user); + client.OnLoginUserProfilePrepared(user_profile); + + // Manipulate user prefs and verify SessionController is updated. + PrefService* const user_prefs = user_profile->GetPrefs(); + + user_prefs->SetBoolean(prefs::kAllowScreenLock, true); + SessionControllerClient::FlushForTesting(); + EXPECT_TRUE(session_controller.last_session_info()->can_lock_screen); + user_prefs->SetBoolean(prefs::kAllowScreenLock, false); + SessionControllerClient::FlushForTesting(); + EXPECT_FALSE(session_controller.last_session_info()->can_lock_screen); + + user_prefs->SetBoolean(prefs::kEnableAutoScreenLock, true); + SessionControllerClient::FlushForTesting(); + EXPECT_TRUE( + session_controller.last_session_info()->should_lock_screen_automatically); + user_prefs->SetBoolean(prefs::kEnableAutoScreenLock, false); + SessionControllerClient::FlushForTesting(); + EXPECT_FALSE( + session_controller.last_session_info()->should_lock_screen_automatically); +}
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h index e0d91ad..594a3f7b 100644 --- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h +++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
@@ -141,6 +141,7 @@ SkColor InactiveFrameColor() const override; gfx::Insets GetFrameInsets() const override; bool CanHaveAlphaEnabled() const override; + void SetActivateOnPointer(bool activate_on_pointer) override; // These are used to simulate Mac-style hide/show. Since windows can be hidden // and shown using the app.window API, this sets is_hidden_with_app_ to
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm index c6a0fba..a9d9a06 100644 --- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm +++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
@@ -663,6 +663,10 @@ return false; } +void NativeAppWindowCocoa::SetActivateOnPointer(bool activate_on_pointer) { + NOTIMPLEMENTED(); +} + gfx::NativeView NativeAppWindowCocoa::GetHostView() const { return WebContents()->GetNativeView(); }
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa.mm index 3aaa475..b9e788cf1 100644 --- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa.mm +++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view_cocoa.mm
@@ -108,6 +108,11 @@ [importBookmarksButton_ setFont:smallSystemFont]; [importBookmarksButton_ sizeToFit]; + // Hide by default so these don't flash if it takes a while for the bookmark + // model to load. + [noItemTextField_ setHidden:YES]; + [importBookmarksButton_ setHidden:YES]; + [self addSubview:noItemTextField_]; [self addSubview:importBookmarksButton_]; [self registerForNotificationsAndDraggedTypes];
diff --git a/chrome/browser/ui/cocoa/first_run_dialog.h b/chrome/browser/ui/cocoa/first_run_dialog.h index f576325..1f938da 100644 --- a/chrome/browser/ui/cocoa/first_run_dialog.h +++ b/chrome/browser/ui/cocoa/first_run_dialog.h
@@ -10,27 +10,10 @@ // Class that acts as a controller for the modal first run dialog. // The dialog asks the user's explicit permission for reporting stats to help // us improve Chromium. -@interface FirstRunDialogController : NSWindowController { - @private - // Bound to the value of the checkbox in FirstRunDialog.xib. - BOOL statsEnabled_; - BOOL makeDefaultBrowser_; +@interface FirstRunDialogController : NSWindowController - IBOutlet NSArray* objectsToSize_; - IBOutlet NSButton* setAsDefaultCheckbox_; - IBOutlet NSButton* statsCheckbox_; - BOOL beenSized_; -} - -// Called when the "Start Google Chrome" button is pressed. -- (IBAction)ok:(id)sender; - -// Called when the "Learn More" button is pressed. -- (IBAction)learnMore:(id)sender; - -// Properties for bindings. -@property(assign, nonatomic) BOOL statsEnabled; -@property(assign, nonatomic) BOOL makeDefaultBrowser; +- (BOOL)isStatsReportingEnabled; +- (BOOL)isMakeDefaultBrowserEnabled; @end
diff --git a/chrome/browser/ui/cocoa/first_run_dialog.mm b/chrome/browser/ui/cocoa/first_run_dialog.mm index 1844bfc..a3de622 100644 --- a/chrome/browser/ui/cocoa/first_run_dialog.mm +++ b/chrome/browser/ui/cocoa/first_run_dialog.mm
@@ -4,6 +4,7 @@ #import "chrome/browser/ui/cocoa/first_run_dialog.h" +#include "base/compiler_specific.h" #include "base/mac/bundle_locations.h" #import "base/mac/scoped_nsobject.h" #include "base/memory/ref_counted.h" @@ -17,6 +18,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/shell_integration.h" +#include "chrome/browser/ui/cocoa/first_run_dialog_controller.h" #include "chrome/common/url_constants.h" #include "components/search_engines/template_url_service.h" #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h" @@ -57,48 +59,32 @@ // Show the first run UI. // Returns true if the first run dialog was shown. -bool ShowFirstRun(Profile* profile) { - bool dialog_shown = false; -#if defined(GOOGLE_CHROME_BUILD) +bool ShowFirstRunModal(Profile* profile) { // The purpose of the dialog is to ask the user to enable stats and crash // reporting. This setting may be controlled through configuration management // in enterprise scenarios. If that is the case, skip the dialog entirely, as // it's not worth bothering the user for only the default browser question // (which is likely to be forced in enterprise deployments anyway). - if (!IsMetricsReportingPolicyManaged()) { - base::scoped_nsobject<FirstRunDialogController> dialog( - [[FirstRunDialogController alloc] init]); + if (IsMetricsReportingPolicyManaged()) + return false; + base::scoped_nsobject<FirstRunDialogController> dialog( + [[FirstRunDialogController alloc] init]); - [dialog.get() showWindow:nil]; - dialog_shown = true; + [dialog.get() showWindow:nil]; - // If the dialog asked the user to opt-in for stats and crash reporting, - // record the decision and enable the crash reporter if appropriate. - bool consent_given = [dialog.get() statsEnabled]; - ChangeMetricsReportingState(consent_given); + // If the dialog asked the user to opt-in for stats and crash reporting, + // record the decision and enable the crash reporter if appropriate. + bool consent_given = [dialog.get() isStatsReportingEnabled]; + ChangeMetricsReportingState(consent_given); - // If selected set as default browser. - BOOL make_default_browser = [dialog.get() makeDefaultBrowser]; - if (make_default_browser) { - bool success = shell_integration::SetAsDefaultBrowser(); - DCHECK(success); - } + // If selected set as default browser. + BOOL make_default_browser = [dialog.get() isMakeDefaultBrowserEnabled]; + if (make_default_browser) { + bool success = shell_integration::SetAsDefaultBrowser(); + DCHECK(success); } -#else // GOOGLE_CHROME_BUILD - // We don't show the dialog in Chromium. -#endif // GOOGLE_CHROME_BUILD - // Set preference to show first run bubble and welcome page. - // Only display the bubble if there is a default search provider. - TemplateURLService* search_engines_model = - TemplateURLServiceFactory::GetForProfile(profile); - if (search_engines_model && - search_engines_model->GetDefaultSearchProvider()) { - first_run::SetShowFirstRunBubblePref(first_run::FIRST_RUN_BUBBLE_SHOW); - } - first_run::SetShouldShowWelcomePage(); - - return dialog_shown; + return true; } // True when the stats checkbox should be checked by default. This is only @@ -113,25 +99,50 @@ namespace first_run { bool ShowFirstRunDialog(Profile* profile) { - return ShowFirstRun(profile); + bool dialog_shown = false; +#if defined(GOOGLE_CHROME_BUILD) + dialog_shown = ShowFirstRunModal(profile); +#else + (void)ShowFirstRunModal; // Placate compiler. +#endif + // Set preference to show first run bubble and welcome page. + // Only display the bubble if there is a default search provider. + TemplateURLService* search_engines_model = + TemplateURLServiceFactory::GetForProfile(profile); + if (search_engines_model && + search_engines_model->GetDefaultSearchProvider()) { + first_run::SetShowFirstRunBubblePref(first_run::FIRST_RUN_BUBBLE_SHOW); + } + first_run::SetShouldShowWelcomePage(); + + return dialog_shown; } } // namespace first_run -@implementation FirstRunDialogController +@implementation FirstRunDialogController { + base::scoped_nsobject<FirstRunDialogViewController> viewController_; +} -@synthesize statsEnabled = statsEnabled_; -@synthesize makeDefaultBrowser = makeDefaultBrowser_; +- (instancetype)init { + viewController_.reset([[FirstRunDialogViewController alloc] + initWithStatsCheckboxInitiallyChecked:StatsCheckboxDefault() + defaultBrowserCheckboxVisible:shell_integration:: + CanSetAsDefaultBrowser()]); -- (id)init { - NSString* nibpath = - [base::mac::FrameworkBundle() pathForResource:@"FirstRunDialog" - ofType:@"nib"]; - if ((self = [super initWithWindowNibPath:nibpath owner:self])) { - // Bound to the dialog checkboxes. - makeDefaultBrowser_ = shell_integration::CanSetAsDefaultBrowser(); - statsEnabled_ = StatsCheckboxDefault(); - } + // Create the content view controller (and the content view) *before* the + // window, so that we can find out what the content view's frame is supposed + // to be for use here. + base::scoped_nsobject<NSWindow> window([[NSWindow alloc] + initWithContentRect:[[viewController_ view] frame] + styleMask:NSTitledWindowMask + backing:NSBackingStoreBuffered + defer:YES]); + [window setContentView:[viewController_ view]]; + [window setTitle:[viewController_ windowTitle]]; + + self = [super initWithWindow:window.get()]; + return self; } @@ -153,100 +164,6 @@ - (void)show { NSWindow* win = [self window]; - if (!shell_integration::CanSetAsDefaultBrowser()) { - [setAsDefaultCheckbox_ setHidden:YES]; - } - - // Only support the sizing the window once. - DCHECK(!beenSized_) << "ShowWindow was called twice?"; - if (!beenSized_) { - beenSized_ = YES; - DCHECK_GT([objectsToSize_ count], 0U); - - // Size everything to fit, collecting the widest growth needed (XIB provides - // the min size, i.e.-never shrink, just grow). - CGFloat largestWidthChange = 0.0; - for (NSView* view in objectsToSize_) { - DCHECK_NE(statsCheckbox_, view) << "Stats checkbox shouldn't be in list"; - if (![view isHidden]) { - NSSize delta = [GTMUILocalizerAndLayoutTweaker sizeToFitView:view]; - DCHECK_EQ(delta.height, 0.0) - << "Didn't expect anything to change heights"; - if (largestWidthChange < delta.width) - largestWidthChange = delta.width; - } - } - - // Make the window wide enough to fit everything. - if (largestWidthChange > 0.0) { - NSView* contentView = [win contentView]; - NSRect windowFrame = [contentView convertRect:[win frame] fromView:nil]; - windowFrame.size.width += largestWidthChange; - windowFrame = [contentView convertRect:windowFrame toView:nil]; - [win setFrame:windowFrame display:NO]; - } - - // The stats checkbox gets some really long text, so it gets word wrapped - // and then sized. - DCHECK(statsCheckbox_); - CGFloat statsCheckboxHeightChange = 0.0; - [GTMUILocalizerAndLayoutTweaker wrapButtonTitleForWidth:statsCheckbox_]; - statsCheckboxHeightChange = - [GTMUILocalizerAndLayoutTweaker sizeToFitView:statsCheckbox_].height; - - // Walk bottom up shuffling for all the hidden views. - NSArray* subViews = - [[[win contentView] subviews] sortedArrayUsingComparator:^(id a, id b) { - CGFloat y1 = NSMinY([a frame]); - CGFloat y2 = NSMinY([b frame]); - if (y1 < y2) - return NSOrderedAscending; - else if (y1 > y2) - return NSOrderedDescending; - else - return NSOrderedSame; - }]; - CGFloat moveDown = 0.0; - NSUInteger numSubViews = [subViews count]; - for (NSUInteger idx = 0 ; idx < numSubViews ; ++idx) { - NSView* view = [subViews objectAtIndex:idx]; - - // If the view is hidden, collect the amount to move everything above it - // down, if it's not hidden, apply any shift down. - if ([view isHidden]) { - DCHECK_GT((numSubViews - 1), idx) - << "Don't support top view being hidden"; - NSView* nextView = [subViews objectAtIndex:(idx + 1)]; - CGFloat viewBottom = [view frame].origin.y; - CGFloat nextViewBottom = [nextView frame].origin.y; - moveDown += nextViewBottom - viewBottom; - } else { - if (moveDown != 0.0) { - NSPoint origin = [view frame].origin; - origin.y -= moveDown; - [view setFrameOrigin:origin]; - } - } - // Special case, if this is the stats checkbox, everything above it needs - // to get moved up by the amount it changed height. - if (view == statsCheckbox_) { - moveDown -= statsCheckboxHeightChange; - } - } - - // Resize the window for any height change from hidden views, etc. - if (moveDown != 0.0) { - NSView* contentView = [win contentView]; - [contentView setAutoresizesSubviews:NO]; - NSRect windowFrame = [contentView convertRect:[win frame] fromView:nil]; - windowFrame.size.height -= moveDown; - windowFrame = [contentView convertRect:windowFrame toView:nil]; - [win setFrame:windowFrame display:NO]; - [contentView setAutoresizesSubviews:YES]; - } - - } - // Neat weirdness in the below code - the Application menu stays enabled // while the window is open but selecting items from it (e.g. Quit) has // no effect. I'm guessing that this is an artifact of us being a @@ -258,15 +175,12 @@ [NSApp runModalForWindow:win]; } -- (IBAction)ok:(id)sender { - [[self window] close]; - [NSApp stopModal]; +- (BOOL)isStatsReportingEnabled { + return [viewController_ isStatsReportingEnabled]; } -- (IBAction)learnMore:(id)sender { - NSString* urlStr = base::SysUTF8ToNSString(chrome::kLearnMoreReportingURL); - NSURL* learnMoreUrl = [NSURL URLWithString:urlStr]; - [[NSWorkspace sharedWorkspace] openURL:learnMoreUrl]; +- (BOOL)isMakeDefaultBrowserEnabled { + return [viewController_ isMakeDefaultBrowserEnabled]; } @end
diff --git a/chrome/browser/ui/cocoa/first_run_dialog_controller.h b/chrome/browser/ui/cocoa/first_run_dialog_controller.h new file mode 100644 index 0000000..008f5108 --- /dev/null +++ b/chrome/browser/ui/cocoa/first_run_dialog_controller.h
@@ -0,0 +1,24 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_COCOA_FIRST_RUN_DIALOG_CONTROLLER_H_ +#define CHROME_BROWSER_UI_COCOA_FIRST_RUN_DIALOG_CONTROLLER_H_ + +#include <Cocoa/Cocoa.h> + +// FirstRunDialogViewController is the NSViewController for the first run +// dialog's content view. +@interface FirstRunDialogViewController : NSViewController + +- (instancetype)initWithStatsCheckboxInitiallyChecked:(BOOL)checked + defaultBrowserCheckboxVisible:(BOOL)visible; + +- (NSString*)windowTitle; + +- (BOOL)isStatsReportingEnabled; +- (BOOL)isMakeDefaultBrowserEnabled; + +@end + +#endif // CHROME_BROWSER_UI_COCOA_FIRST_RUN_DIALOG_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/first_run_dialog_controller.mm b/chrome/browser/ui/cocoa/first_run_dialog_controller.mm new file mode 100644 index 0000000..e5ecd3dd --- /dev/null +++ b/chrome/browser/ui/cocoa/first_run_dialog_controller.mm
@@ -0,0 +1,186 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/cocoa/first_run_dialog_controller.h" + +#include "base/mac/scoped_nsobject.h" +#include "base/strings/sys_string_conversions.h" +#include "chrome/browser/ui/cocoa/key_equivalent_constants.h" +#include "chrome/browser/ui/cocoa/l10n_util.h" +#include "chrome/common/url_constants.h" +#include "chrome/grit/chromium_strings.h" +#include "chrome/grit/generated_resources.h" +#include "components/strings/grit/components_strings.h" +#include "ui/base/cocoa/controls/button_utils.h" +#include "ui/base/cocoa/controls/textfield_utils.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/l10n_util_mac.h" + +namespace { + +// Return the internationalized message |message_id|, with the product name +// substituted in for $1. +NSString* NSStringWithProductName(int message_id) { + return l10n_util::GetNSStringF(message_id, + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); +} + +void MoveViewsDown(NSArray* views, CGFloat distance) { + for (NSView* view : views) { + NSRect frame = view.frame; + frame.origin.y -= distance; + [view setFrame:frame]; + } +} + +} // namespace + +@implementation FirstRunDialogViewController { + // These are owned by the NSView hierarchy: + NSButton* defaultBrowserCheckbox_; + NSButton* statsCheckbox_; + + // This is owned by NSViewController: + NSView* view_; + + BOOL statsCheckboxInitiallyChecked_; + BOOL defaultBrowserCheckboxVisible_; +} + +- (instancetype)initWithStatsCheckboxInitiallyChecked:(BOOL)checked + defaultBrowserCheckboxVisible:(BOOL)visible { + if ((self = [super init])) { + statsCheckboxInitiallyChecked_ = checked; + defaultBrowserCheckboxVisible_ = visible; + } + return self; +} + +- (void)loadView { + // Frame constants in this method were taken directly from the now-deleted + // chrome/app/nibs/FirstRunDialog.xib. + NSBox* topBox = + [[[NSBox alloc] initWithFrame:NSMakeRect(0, 158, 480, 55)] autorelease]; + [topBox setFillColor:[NSColor whiteColor]]; + [topBox setBoxType:NSBoxCustom]; + [topBox setBorderType:NSNoBorder]; + [topBox setContentViewMargins:NSZeroSize]; + + NSTextField* completionLabel = [TextFieldUtils + labelWithString:NSStringWithProductName( + IDS_FIRSTRUN_DLG_MAC_COMPLETE_INSTALLATION_LABEL)]; + [completionLabel setFrame:NSMakeRect(13, 25, 390, 17)]; + + NSImageView* logoImage = [[[NSImageView alloc] + initWithFrame:NSMakeRect(408, -25, 96, 96)] autorelease]; + [logoImage setImage:[NSImage imageNamed:NSImageNameApplicationIcon]]; + [logoImage setRefusesFirstResponder:YES]; + [logoImage setEditable:NO]; + + defaultBrowserCheckbox_ = [ButtonUtils + checkboxWithTitle:l10n_util::GetNSString( + IDS_FIRSTRUN_DLG_MAC_SET_DEFAULT_BROWSER_LABEL)]; + [defaultBrowserCheckbox_ setFrame:NSMakeRect(45, 126, 528, 18)]; + if (!defaultBrowserCheckboxVisible_) + [defaultBrowserCheckbox_ setHidden:YES]; + + statsCheckbox_ = [ButtonUtils + checkboxWithTitle: + NSStringWithProductName( + IDS_FIRSTRUN_DLG_MAC_OPTIONS_SEND_USAGE_STATS_LABEL)]; + [statsCheckbox_ setFrame:NSMakeRect(45, 101, 389, 19)]; + if (statsCheckboxInitiallyChecked_) + [statsCheckbox_ setNextState]; + + NSButton* startChromeButton = + [ButtonUtils buttonWithTitle:NSStringWithProductName( + IDS_FIRSTRUN_DLG_MAC_START_CHROME_BUTTON) + action:@selector(ok:) + target:self]; + [startChromeButton setFrame:NSMakeRect(161, 12, 306, 32)]; + [startChromeButton setKeyEquivalent:kKeyEquivalentReturn]; + + NSButton* learnMoreLink = + [ButtonUtils linkWithTitle:l10n_util::GetNSString(IDS_LEARN_MORE) + action:@selector(learnMore:) + target:self]; + [learnMoreLink setFrame:NSMakeRect(60, 76, 359, 19)]; + + NSBox* topSeparator = + [[[NSBox alloc] initWithFrame:NSMakeRect(0, 155, 480, 5)] autorelease]; + [topSeparator setBoxType:NSBoxSeparator]; + + NSBox* bottomSeparator = + [[[NSBox alloc] initWithFrame:NSMakeRect(0, 55, 480, 5)] autorelease]; + [bottomSeparator setBoxType:NSBoxSeparator]; + + [topBox addSubview:completionLabel]; + [topBox addSubview:logoImage]; + + base::scoped_nsobject<NSView> content_view( + [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 480, 209)]); + self.view = content_view.get(); + [self.view addSubview:topBox]; + [self.view addSubview:topSeparator]; + [self.view addSubview:defaultBrowserCheckbox_]; + [self.view addSubview:statsCheckbox_]; + [self.view addSubview:learnMoreLink]; + [self.view addSubview:bottomSeparator]; + [self.view addSubview:startChromeButton]; + + // Now that the content view is constructed, fix the layout: since this view + // isn't using autolayout, if the widths of some of the subviews change + // because of localization, they need to be resized and perhaps repositioned, + // which is done here by |VerticallyReflowGroup()|. + CGFloat oldWidth = NSWidth([startChromeButton frame]); + cocoa_l10n_util::VerticallyReflowGroup( + @[ defaultBrowserCheckbox_, statsCheckbox_, learnMoreLink ]); + + // The "Start Chrome" button needs to be sized to fit the localized string + // inside it, but it should still be at the right-most edge of the dialog, so + // any width added or subtracted by |sizeToFit| is added to its x coord, which + // keeps its right edge where it was. + [startChromeButton sizeToFit]; + NSRect frame = [startChromeButton frame]; + frame.origin.x += oldWidth - NSWidth([startChromeButton frame]); + [startChromeButton setFrame:frame]; + + // Lastly, if the default browser checkbox is actually invisible, move the + // views above it downward so that there's not a big open space in the content + // view, and resize the content view itself so there isn't extra space. + if (!defaultBrowserCheckboxVisible_) { + CGFloat delta = NSHeight([defaultBrowserCheckbox_ frame]); + MoveViewsDown(@[ topBox, topSeparator ], delta); + NSRect frame = [self.view frame]; + frame.size.height -= delta; + [self.view setAutoresizesSubviews:NO]; + [self.view setFrame:frame]; + [self.view setAutoresizesSubviews:YES]; + } +} + +- (NSString*)windowTitle { + return NSStringWithProductName(IDS_FIRSTRUN_DLG_MAC_WINDOW_TITLE); +} + +- (BOOL)isStatsReportingEnabled { + return [statsCheckbox_ state] == NSOnState; +} + +- (BOOL)isMakeDefaultBrowserEnabled { + return [defaultBrowserCheckbox_ state] == NSOnState; +} + +- (void)ok:(id)sender { + [[[self view] window] close]; + [NSApp stopModal]; +} + +- (void)learnMore:(id)sender { + NSString* urlStr = base::SysUTF8ToNSString(chrome::kLearnMoreReportingURL); + NSURL* learnMoreUrl = [NSURL URLWithString:urlStr]; + [[NSWorkspace sharedWorkspace] openURL:learnMoreUrl]; +} + +@end
diff --git a/chrome/browser/ui/cocoa/first_run_dialog_controller_unittest.mm b/chrome/browser/ui/cocoa/first_run_dialog_controller_unittest.mm new file mode 100644 index 0000000..c1cd6b1 --- /dev/null +++ b/chrome/browser/ui/cocoa/first_run_dialog_controller_unittest.mm
@@ -0,0 +1,46 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/cocoa/first_run_dialog_controller.h" +#include "base/mac/scoped_nsobject.h" +#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" + +using FirstRunDialogControllerTest = CocoaTest; +using TestController = base::scoped_nsobject<FirstRunDialogViewController>; + +TestController MakeTestController(BOOL stats, BOOL browser) { + return TestController([[FirstRunDialogViewController alloc] + initWithStatsCheckboxInitiallyChecked:stats + defaultBrowserCheckboxVisible:browser]); +} + +NSView* FindBrowserButton(NSView* view) { + for (NSView* subview : [view subviews]) { + if (![subview isKindOfClass:[NSButton class]]) + continue; + NSString* title = [(NSButton*)subview title]; + if ([title rangeOfString:@"browser"].location != NSNotFound) + return subview; + } + return nil; +} + +TEST(FirstRunDialogControllerTest, SetStatsDefault) { + TestController controller(MakeTestController(YES, YES)); + [controller view]; // Make sure view is actually loaded. + EXPECT_TRUE([controller isStatsReportingEnabled]); +} + +TEST(FirstRunDialogControllerTest, ShowBrowser) { + TestController controller(MakeTestController(YES, YES)); + NSView* checkbox = FindBrowserButton([controller view]); + EXPECT_FALSE(checkbox.hidden); +} + +TEST(FirstRunDialogControllerTest, HideBrowser) { + TestController controller(MakeTestController(YES, NO)); + NSView* checkbox = FindBrowserButton([controller view]); + EXPECT_TRUE(checkbox.hidden); +}
diff --git a/chrome/browser/ui/find_bar/find_bar_controller.h b/chrome/browser/ui/find_bar/find_bar_controller.h index 25ecaed1..e912a06 100644 --- a/chrome/browser/ui/find_bar/find_bar_controller.h +++ b/chrome/browser/ui/find_bar/find_bar_controller.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "base/strings/string16.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index a70d9b2..7cb45b44 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/history/history_tab_helper.h" #include "chrome/browser/history/top_sites_factory.h" #include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/media/media_engagement_service.h" #include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_observer.h" #include "chrome/browser/metrics/renderer_uptime_web_contents_observer.h" #include "chrome/browser/net/net_error_tab_helper.h" @@ -298,4 +299,7 @@ if (tracing::NavigationTracingObserver::IsEnabled()) tracing::NavigationTracingObserver::CreateForWebContents(web_contents); + + if (MediaEngagementService::IsEnabled()) + MediaEngagementService::CreateWebContentsObserver(web_contents); }
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc index 3097a35..ef0430f 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -373,6 +373,12 @@ } } +void ChromeNativeAppWindowViewsAuraAsh::SetActivateOnPointer( + bool activate_on_pointer) { + widget()->GetNativeWindow()->SetProperty(aura::client::kActivateOnPointerKey, + activate_on_pointer); +} + void ChromeNativeAppWindowViewsAuraAsh::OnMenuClosed() { menu_runner_.reset(); menu_model_adapter_.reset();
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h index e3a0d77f..2a2ae09 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.h
@@ -64,6 +64,7 @@ void SetFullscreen(int fullscreen_types) override; void UpdateDraggableRegions( const std::vector<extensions::DraggableRegion>& regions) override; + void SetActivateOnPointer(bool activate_on_pointer) override; private: FRIEND_TEST_ALL_PREFIXES(ShapedAppWindowTargeterTest,
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc index e556570..915f4897 100644 --- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc +++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -13,6 +13,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/command_line.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" @@ -33,7 +34,9 @@ #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" +#include "net/dns/mock_host_resolver.h" #include "services/service_manager/public/cpp/bind_source_info.h" #include "services/service_manager/public/cpp/binder_registry.h" #include "testing/gtest/include/gtest/gtest.h" @@ -59,10 +62,18 @@ is_valid_ssl_(true) {} PaymentRequestBrowserTestBase::~PaymentRequestBrowserTestBase() {} +void PaymentRequestBrowserTestBase::SetUpCommandLine( + base::CommandLine* command_line) { + // HTTPS server only serves a valid cert for localhost, so this is needed to + // load pages from "a.com" without an interstitial. + command_line->AppendSwitch(switches::kIgnoreCertificateErrors); +} + void PaymentRequestBrowserTestBase::SetUpOnMainThread() { // Setup the https server. https_server_ = base::MakeUnique<net::EmbeddedTestServer>( net::EmbeddedTestServer::TYPE_HTTPS); + host_resolver()->AddRule("a.com", "127.0.0.1"); ASSERT_TRUE(https_server_->InitializeAndListen()); https_server_->ServeFilesFromSourceDirectory("chrome/test/data/payments"); https_server_->StartAcceptingConnections(); @@ -82,10 +93,12 @@ } void PaymentRequestBrowserTestBase::NavigateTo(const std::string& file_path) { - ui_test_utils::NavigateToURL(browser(), - file_path.find("data:") == 0U - ? GURL(file_path) - : https_server()->GetURL(file_path)); + if (file_path.find("data:") == 0U) { + ui_test_utils::NavigateToURL(browser(), GURL(file_path)); + } else { + ui_test_utils::NavigateToURL(browser(), + https_server()->GetURL("a.com", file_path)); + } } void PaymentRequestBrowserTestBase::SetIncognito() { @@ -414,8 +427,8 @@ web_contents, this /* observer */, is_incognito_, is_valid_ssl_); delegate_ = delegate.get(); PaymentRequestWebContentsManager::GetOrCreateForWebContents(web_contents) - ->CreatePaymentRequest(web_contents, std::move(delegate), - std::move(request), this); + ->CreatePaymentRequest(web_contents->GetMainFrame(), web_contents, + std::move(delegate), std::move(request), this); } void PaymentRequestBrowserTestBase::ClickOnDialogViewAndWait(
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h index 8365bff..35abd42c 100644 --- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h +++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
@@ -90,6 +90,7 @@ explicit PaymentRequestBrowserTestBase(const std::string& test_file_path); ~PaymentRequestBrowserTestBase() override; + void SetUpCommandLine(base::CommandLine* command_line) override; void SetUpOnMainThread() override; void NavigateTo(const std::string& file_path);
diff --git a/chrome/browser/ui/views/payments/payment_request_can_make_payment_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_can_make_payment_browsertest.cc index cb4e072..7575799 100644 --- a/chrome/browser/ui/views/payments/payment_request_can_make_payment_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_can_make_payment_browsertest.cc
@@ -96,4 +96,102 @@ ExpectBodyContains({"true"}); } +class PaymentRequestCanMakePaymentQueryCCTest + : public PaymentRequestBrowserTestBase { + protected: + PaymentRequestCanMakePaymentQueryCCTest() + : PaymentRequestBrowserTestBase( + "/payment_request_can_make_payment_query_cc_test.html") {} + + void CallCanMakePayment(bool visa) { + ResetEventObserver(DialogEvent::CAN_MAKE_PAYMENT_CALLED); + ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), + visa ? "buy();" : "other_buy();")); + WaitForObservedEvent(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(PaymentRequestCanMakePaymentQueryCCTest); +}; + +IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryCCTest, QueryQuota) { + // Query "visa" payment method. + CallCanMakePayment(/*visa=*/true); + + // User does not have a visa card. + ExpectBodyContains({"false"}); + + // Query "mastercard" payment method. + CallCanMakePayment(/*visa=*/false); + + // Query quota exceeded. + ExpectBodyContains({"NotAllowedError"}); + + AddCreditCard(autofill::test::GetCreditCard()); // visa + + // Query "visa" payment method. + CallCanMakePayment(/*visa=*/true); + + // User now has a visa card. The query is cached, but the result is always + // fresh. + ExpectBodyContains({"true"}); + + // Query "mastercard" payment method. + CallCanMakePayment(/*visa=*/false); + + // Query quota exceeded. + ExpectBodyContains({"NotAllowedError"}); +} + +class PaymentRequestCanMakePaymentQueryBasicCardTest + : public PaymentRequestBrowserTestBase { + protected: + PaymentRequestCanMakePaymentQueryBasicCardTest() + : PaymentRequestBrowserTestBase("/payment_request_basic_card_test.html") { + } + + void CallCanMakePayment(bool visa) { + ResetEventObserver(DialogEvent::CAN_MAKE_PAYMENT_CALLED); + ASSERT_TRUE(content::ExecuteScript( + GetActiveWebContents(), + visa ? "checkBasicVisa();" : "checkBasicCard();")); + WaitForObservedEvent(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(PaymentRequestCanMakePaymentQueryBasicCardTest); +}; + +IN_PROC_BROWSER_TEST_F(PaymentRequestCanMakePaymentQueryBasicCardTest, + QueryQuota) { + // Query "basic-card" payment method with "supportedNetworks": ["visa"] in the + // payment method specific data. + CallCanMakePayment(/*visa=*/true); + + // User does not have a visa card. + ExpectBodyContains({"false"}); + + // Query "basic-card" payment method without "supportedNetworks" parameter. + CallCanMakePayment(/*visa=*/false); + + // Query quota exceeded. + ExpectBodyContains({"NotAllowedError"}); + + AddCreditCard(autofill::test::GetCreditCard()); // visa + + // Query "basic-card" payment method with "supportedNetworks": ["visa"] in the + // payment method specific data. + CallCanMakePayment(/*visa=*/true); + + // User now has a visa card. The query is cached, but the result is always + // fresh. + ExpectBodyContains({"true"}); + + // Query "basic-card" payment method without "supportedNetworks" parameter. + CallCanMakePayment(/*visa=*/false); + + // Query quota exceeded. + ExpectBodyContains({"NotAllowedError"}); +} + } // namespace payments
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc index eec286e9..c64c1c6 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/ui/views/toolbar/toolbar_action_view.h" + #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" @@ -11,9 +13,8 @@ #include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h" #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" -#include "chrome/browser/ui/views/toolbar/toolbar_action_view.h" #include "chrome/test/base/testing_profile.h" -#include "content/public/test/test_browser_thread.h" +#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_web_contents_factory.h" #include "ui/accessibility/ax_node_data.h" #include "ui/events/test/event_generator.h" @@ -98,10 +99,7 @@ class ToolbarActionViewUnitTest : public views::ViewsTestBase { public: - ToolbarActionViewUnitTest() - : widget_(nullptr), - ui_thread_(content::BrowserThread::UI, message_loop()), - scoped_task_scheduler_(base::MessageLoop::current()) {} + ToolbarActionViewUnitTest() : widget_(nullptr) {} ~ToolbarActionViewUnitTest() override {} void SetUp() override { @@ -122,13 +120,12 @@ views::Widget* widget() { return widget_; } private: + // Web contents need a UI thread and a TaskScheduler. + content::TestBrowserThreadBundle test_browser_thread_bundle_; + // The widget managed by this test. views::Widget* widget_; - // Web contents need a UI thread and a TaskScheduler. - content::TestBrowserThread ui_thread_; - base::test::ScopedTaskScheduler scoped_task_scheduler_; - DISALLOW_COPY_AND_ASSIGN(ToolbarActionViewUnitTest); };
diff --git a/chrome/renderer/resources/extensions/media_router_bindings.js b/chrome/renderer/resources/extensions/media_router_bindings.js index 4eac395..c6554c1 100644 --- a/chrome/renderer/resources/extensions/media_router_bindings.js +++ b/chrome/renderer/resources/extensions/media_router_bindings.js
@@ -189,6 +189,7 @@ default: throw new Error('Scheme must be http or https'); } + mojoOrigin.suborigin = ''; return new originMojom.Origin(mojoOrigin); }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 0cf7abb..e3964e4 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -4450,6 +4450,7 @@ "../browser/ui/cocoa/find_bar/find_bar_view_unittest.mm", "../browser/ui/cocoa/find_pasteboard_unittest.mm", "../browser/ui/cocoa/first_run_bubble_controller_unittest.mm", + "../browser/ui/cocoa/first_run_dialog_controller_unittest.mm", "../browser/ui/cocoa/floating_bar_backing_view_unittest.mm", "../browser/ui/cocoa/framed_browser_window_unittest.mm", "../browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_unittest.mm",
diff --git a/chrome/test/data/payments/can_make_payment_query_cc.js b/chrome/test/data/payments/can_make_payment_query_cc.js index f56b8fd..a60e9dd 100644 --- a/chrome/test/data/payments/can_make_payment_query_cc.js +++ b/chrome/test/data/payments/can_make_payment_query_cc.js
@@ -4,15 +4,12 @@ * found in the LICENSE file. */ -/* global PaymentRequest:false */ -/* global print:false */ - /** * Checks for existence of a complete VISA credit card. */ function buy() { // eslint-disable-line no-unused-vars try { - var request = new PaymentRequest( + const request = new PaymentRequest( [{supportedMethods: ['visa']}], {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}}); request.canMakePayment() @@ -30,9 +27,9 @@ /** * Checks for existence of a complete MasterCard credit card. */ -function other_buy() { // eslint-disable-line no-unused-vars +function other_buy() { // eslint-disable-line no-unused-vars, camelcase try { - var request = new PaymentRequest( + const request = new PaymentRequest( [{supportedMethods: ['mastercard']}], {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}}); request.canMakePayment()
diff --git a/components/autofill/content/common/autofill_types_struct_traits_unittest.cc b/components/autofill/content/common/autofill_types_struct_traits_unittest.cc index b60bff0..dba2fa6 100644 --- a/components/autofill/content/common/autofill_types_struct_traits_unittest.cc +++ b/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
@@ -93,7 +93,7 @@ form->icon_url = GURL("https://foo.com/icon.png"); form->federation_origin = url::Origin::UnsafelyCreateOriginWithoutNormalization( - "http", "www.google.com", 80); + "http", "www.google.com", 80, ""); form->skip_zero_click = false; form->layout = PasswordForm::Layout::LAYOUT_LOGIN_AND_SIGNUP; form->was_parsed_using_autofill_predictions = false;
diff --git a/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc index df12ab1a..7049f31f 100644 --- a/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc +++ b/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -448,6 +448,13 @@ } void AutocompleteSyncBridge::LoadMetadata() { + if (!web_data_backend_ || !web_data_backend_->GetDatabase() || + !GetAutofillTable()) { + change_processor()->ReportError(FROM_HERE, + "Failed to load AutofillWebDatabase."); + return; + } + auto batch = base::MakeUnique<syncer::MetadataBatch>(); if (!GetAutofillTable()->GetAllSyncMetadata(syncer::AUTOFILL, batch.get())) { change_processor()->ReportError(
diff --git a/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc index 668ff41..59506b1 100644 --- a/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc +++ b/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
@@ -141,10 +141,10 @@ } ~AutocompleteSyncBridgeTest() override {} - void ResetBridge() { + void ResetBridge(bool expect_error = false) { bridge_.reset(new AutocompleteSyncBridge( - &backend_, - RecordingModelTypeChangeProcessor::FactoryForBridgeTest(&processor_))); + &backend_, RecordingModelTypeChangeProcessor::FactoryForBridgeTest( + &processor_, expect_error))); } void SaveSpecificsToTable( @@ -266,6 +266,8 @@ AutofillTable* table() { return &table_; } + FakeAutofillBackend* backend() { return &backend_; } + private: ScopedTempDir temp_dir_; base::test::ScopedTaskEnvironment scoped_task_environment_; @@ -592,6 +594,12 @@ EXPECT_EQ(1u, processor().metadata()->TakeAllMetadata().size()); } +TEST_F(AutocompleteSyncBridgeTest, LoadMetadataReportsErrorForMissingDB) { + backend()->SetWebDatabase(nullptr); + // The processor's destructor will verify that an error has occured. + ResetBridge(/*expect_error=*/true); +} + TEST_F(AutocompleteSyncBridgeTest, MergeSyncDataEmpty) { VerifyMerge(std::vector<AutofillSpecifics>());
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc index 9aa55fc..f9e941d 100644 --- a/components/exo/wayland/server.cc +++ b/components/exo/wayland/server.cc
@@ -2149,7 +2149,8 @@ // already activated on the client side, so do not notify about the // activation. It means that zcr_remote_shell_v1_send_activated is used // only to notify about activations originating in Aura. - if (gained_active && gained_active->GetProperty(kIgnoreWindowActivated)) { + if (gained_active && ShellSurface::GetMainSurface(gained_active) && + gained_active->GetProperty(kIgnoreWindowActivated)) { gained_active->SetProperty(kIgnoreWindowActivated, false); return; }
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h index c041844..48ad40203 100644 --- a/components/infobars/core/infobar_delegate.h +++ b/components/infobars/core/infobar_delegate.h
@@ -145,6 +145,7 @@ SEARCH_GEOLOCATION_DISCLOSURE_INFOBAR_DELEGATE = 72, AUTOMATION_INFOBAR_DELEGATE = 73, VR_SERVICES_UPGRADE_ANDROID = 74, + READER_MODE_INFOBAR_ANDROID = 75, }; // Describes navigation events, used to decide whether infobars should be
diff --git a/components/navigation_metrics/OWNERS b/components/navigation_metrics/OWNERS index e9db99ed..06f6dae 100644 --- a/components/navigation_metrics/OWNERS +++ b/components/navigation_metrics/OWNERS
@@ -1,4 +1,6 @@ cbentzel@chromium.org davidben@chromium.org +elawrence@chromium.org +estark@chromium.org # COMPONENT: Internals>Network
diff --git a/components/ntp_snippets/content_suggestions_metrics.cc b/components/ntp_snippets/content_suggestions_metrics.cc index 5d2d4af..c6345f2 100644 --- a/components/ntp_snippets/content_suggestions_metrics.cc +++ b/components/ntp_snippets/content_suggestions_metrics.cc
@@ -292,6 +292,8 @@ if (category.IsKnownCategory(KnownCategories::ARTICLES)) { RecordContentSuggestionsUsage(); } + + base::RecordAction(base::UserMetricsAction("Suggestions.Content.Opened")); } void OnSuggestionMenuOpened(int global_position, @@ -366,5 +368,17 @@ "NewTabPage.ContentSuggestions.Preferences.RemoteSuggestions", enabled); } +void RecordContentSuggestionDismissed() { + base::RecordAction(base::UserMetricsAction("Suggestions.Content.Dismissed")); +} + +void RecordCategoryDismissed() { + base::RecordAction(base::UserMetricsAction("Suggestions.Category.Dismissed")); +} + +void RecordFetchAction() { + base::RecordAction(base::UserMetricsAction("Suggestions.Category.Fetch")); +} + } // namespace metrics } // namespace ntp_snippets
diff --git a/components/ntp_snippets/content_suggestions_metrics.h b/components/ntp_snippets/content_suggestions_metrics.h index a2f04e566..3bfff0ec7 100644 --- a/components/ntp_snippets/content_suggestions_metrics.h +++ b/components/ntp_snippets/content_suggestions_metrics.h
@@ -60,6 +60,12 @@ void RecordRemoteSuggestionsProviderState(bool enabled); +void RecordContentSuggestionDismissed(); + +void RecordCategoryDismissed(); + +void RecordFetchAction(); + } // namespace metrics } // namespace ntp_snippets
diff --git a/components/ntp_snippets/content_suggestions_service.cc b/components/ntp_snippets/content_suggestions_service.cc index c31a72e..565f420 100644 --- a/components/ntp_snippets/content_suggestions_service.cc +++ b/components/ntp_snippets/content_suggestions_service.cc
@@ -20,6 +20,7 @@ #include "components/favicon/core/large_icon_service.h" #include "components/favicon_base/fallback_icon_style.h" #include "components/favicon_base/favicon_types.h" +#include "components/ntp_snippets/content_suggestions_metrics.h" #include "components/ntp_snippets/pref_names.h" #include "components/ntp_snippets/remote/remote_suggestions_provider.h" #include "components/prefs/pref_registry_simple.h" @@ -324,6 +325,9 @@ << " for unavailable category " << suggestion_id.category(); return; } + + metrics::RecordContentSuggestionDismissed(); + providers_by_category_[suggestion_id.category()]->DismissSuggestion( suggestion_id); @@ -339,6 +343,8 @@ return; } + metrics::RecordCategoryDismissed(); + ContentSuggestionsProvider* provider = providers_it->second; UnregisterCategory(category, provider); @@ -382,6 +388,8 @@ return; } + metrics::RecordFetchAction(); + providers_it->second->Fetch(category, known_suggestion_ids, callback); }
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc index 6809aa4..b09aa4c8 100644 --- a/components/ntp_tiles/most_visited_sites.cc +++ b/components/ntp_tiles/most_visited_sites.cc
@@ -12,6 +12,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/feature_list.h" +#include "base/metrics/user_metrics.h" #include "base/strings/utf_string_conversions.h" #include "components/history/core/browser/top_sites.h" #include "components/ntp_tiles/constants.h" @@ -134,6 +135,13 @@ void MostVisitedSites::AddOrRemoveBlacklistedUrl(const GURL& url, bool add_url) { + if (add_url) { + base::RecordAction(base::UserMetricsAction("Suggestions.Site.Removed")); + } else { + base::RecordAction( + base::UserMetricsAction("Suggestions.Site.RemovalUndone")); + } + if (top_sites_) { // Always blacklist in the local TopSites. if (add_url)
diff --git a/components/payments/content/BUILD.gn b/components/payments/content/BUILD.gn index a74987dd..7b6216a 100644 --- a/components/payments/content/BUILD.gn +++ b/components/payments/content/BUILD.gn
@@ -4,6 +4,8 @@ static_library("content") { sources = [ + "can_make_payment_query_factory.cc", + "can_make_payment_query_factory.h", "payment_request.cc", "payment_request.h", "payment_request_dialog.h", @@ -20,6 +22,7 @@ deps = [ ":utils", "//components/autofill/core/browser", + "//components/keyed_service/content", "//components/payments/core", "//components/payments/mojom", "//components/strings:components_strings_grit",
diff --git a/components/payments/content/DEPS b/components/payments/content/DEPS index 548a164..2cf753e70 100644 --- a/components/payments/content/DEPS +++ b/components/payments/content/DEPS
@@ -3,6 +3,7 @@ "-components/payments/content/utility", "+components/autofill", "+components/data_use_measurement", + "+components/keyed_service/content", "+components/link_header_util", "+components/strings", "+content/public",
diff --git a/components/payments/content/can_make_payment_query_factory.cc b/components/payments/content/can_make_payment_query_factory.cc new file mode 100644 index 0000000..2f881730 --- /dev/null +++ b/components/payments/content/can_make_payment_query_factory.cc
@@ -0,0 +1,36 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/payments/content/can_make_payment_query_factory.h" + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/payments/core/can_make_payment_query.h" + +namespace payments { + +// static +CanMakePaymentQueryFactory* CanMakePaymentQueryFactory::GetInstance() { + return base::Singleton<CanMakePaymentQueryFactory>::get(); +} + +CanMakePaymentQuery* CanMakePaymentQueryFactory::GetForContext( + content::BrowserContext* context) { + return static_cast<CanMakePaymentQuery*>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +CanMakePaymentQueryFactory::CanMakePaymentQueryFactory() + : BrowserContextKeyedServiceFactory( + "CanMakePaymentQuery", + BrowserContextDependencyManager::GetInstance()) {} + +CanMakePaymentQueryFactory::~CanMakePaymentQueryFactory() {} + +KeyedService* CanMakePaymentQueryFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new CanMakePaymentQuery; +} + +} // namespace payments
diff --git a/components/payments/content/can_make_payment_query_factory.h b/components/payments/content/can_make_payment_query_factory.h new file mode 100644 index 0000000..3d67e03 --- /dev/null +++ b/components/payments/content/can_make_payment_query_factory.h
@@ -0,0 +1,46 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PAYMENTS_CONTENT_CAN_MAKE_PAYMENT_QUERY_FACTORY_H_ +#define COMPONENTS_PAYMENTS_CONTENT_CAN_MAKE_PAYMENT_QUERY_FACTORY_H_ + +#include "base/macros.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +namespace base { +template <typename T> +struct DefaultSingletonTraits; +} + +namespace content { +class BrowserContext; +} + +namespace payments { + +class CanMakePaymentQuery; + +// Ensures that there's only one instance of CanMakePaymentQuery per browser +// context. +class CanMakePaymentQueryFactory : public BrowserContextKeyedServiceFactory { + public: + static CanMakePaymentQueryFactory* GetInstance(); + CanMakePaymentQuery* GetForContext(content::BrowserContext* context); + + private: + friend struct base::DefaultSingletonTraits<CanMakePaymentQueryFactory>; + + CanMakePaymentQueryFactory(); + ~CanMakePaymentQueryFactory() override; + + // BrowserContextKeyedServiceFactory: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + + DISALLOW_COPY_AND_ASSIGN(CanMakePaymentQueryFactory); +}; + +} // namespace payments + +#endif // COMPONENTS_PAYMENTS_CONTENT_CAN_MAKE_PAYMENT_QUERY_FACTORY_H_
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc index 138b6d1..69a13a702 100644 --- a/components/payments/content/payment_request.cc +++ b/components/payments/content/payment_request.cc
@@ -8,15 +8,19 @@ #include <utility> #include "base/memory/ptr_util.h" +#include "components/payments/content/can_make_payment_query_factory.h" #include "components/payments/content/origin_security_checker.h" #include "components/payments/content/payment_details_validation.h" #include "components/payments/content/payment_request_web_contents_manager.h" +#include "components/payments/core/can_make_payment_query.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" namespace payments { PaymentRequest::PaymentRequest( + content::RenderFrameHost* render_frame_host, content::WebContents* web_contents, std::unique_ptr<PaymentRequestDelegate> delegate, PaymentRequestWebContentsManager* manager, @@ -26,6 +30,7 @@ delegate_(std::move(delegate)), manager_(manager), binding_(this, std::move(request)), + frame_origin_(GURL(render_frame_host->GetLastCommittedURL()).GetOrigin()), observer_for_testing_(observer_for_testing), journey_logger_(delegate_->IsIncognito(), web_contents_->GetLastCommittedURL(), @@ -167,14 +172,30 @@ } void PaymentRequest::CanMakePayment() { - // TODO(crbug.com/704676): Implement a quota policy for this method. - // PaymentRequest.canMakePayments() never returns false in incognito mode. - client_->OnCanMakePayment( - delegate_->IsIncognito() || state()->CanMakePayment() - ? mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT - : mojom::CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT); - journey_logger_.SetCanMakePaymentValue(delegate_->IsIncognito() || - state()->CanMakePayment()); + bool can_make_payment = state()->CanMakePayment(); + if (delegate_->IsIncognito()) { + client_->OnCanMakePayment( + mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT); + journey_logger_.SetCanMakePaymentValue(true); + } else if (CanMakePaymentQueryFactory::GetInstance() + ->GetForContext(web_contents_->GetBrowserContext()) + ->CanQuery(frame_origin_, spec()->stringified_method_data())) { + client_->OnCanMakePayment( + can_make_payment + ? mojom::CanMakePaymentQueryResult::CAN_MAKE_PAYMENT + : mojom::CanMakePaymentQueryResult::CANNOT_MAKE_PAYMENT); + journey_logger_.SetCanMakePaymentValue(can_make_payment); + } else if (OriginSecurityChecker::IsOriginLocalhostOrFile(frame_origin_)) { + client_->OnCanMakePayment( + can_make_payment + ? mojom::CanMakePaymentQueryResult::WARNING_CAN_MAKE_PAYMENT + : mojom::CanMakePaymentQueryResult::WARNING_CANNOT_MAKE_PAYMENT); + journey_logger_.SetCanMakePaymentValue(can_make_payment); + } else { + client_->OnCanMakePayment( + mojom::CanMakePaymentQueryResult::QUERY_QUOTA_EXCEEDED); + } + if (observer_for_testing_) observer_for_testing_->OnCanMakePaymentCalled(); }
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h index 2514a8b..4613add 100644 --- a/components/payments/content/payment_request.h +++ b/components/payments/content/payment_request.h
@@ -16,8 +16,10 @@ #include "components/payments/mojom/payment_request.mojom.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/interface_request.h" +#include "url/gurl.h" namespace content { +class RenderFrameHost; class WebContents; } @@ -45,7 +47,8 @@ virtual ~ObserverForTest() {} }; - PaymentRequest(content::WebContents* web_contents, + PaymentRequest(content::RenderFrameHost* render_frame_host, + content::WebContents* web_contents, std::unique_ptr<PaymentRequestDelegate> delegate, PaymentRequestWebContentsManager* manager, mojo::InterfaceRequest<mojom::PaymentRequest> request, @@ -101,6 +104,10 @@ std::unique_ptr<PaymentRequestSpec> spec_; std::unique_ptr<PaymentRequestState> state_; + // The RFC 6454 origin of the frame that has invoked PaymentRequest API. This + // can be either the main frame or an iframe. + const GURL frame_origin_; + // May be null, must outlive this object. ObserverForTest* observer_for_testing_;
diff --git a/components/payments/content/payment_request_spec.cc b/components/payments/content/payment_request_spec.cc index a5addb5c..2f7a7e4 100644 --- a/components/payments/content/payment_request_spec.cc +++ b/components/payments/content/payment_request_spec.cc
@@ -143,6 +143,11 @@ method_data_vector.reserve(method_data_mojom.size()); for (const mojom::PaymentMethodDataPtr& method_data_entry : method_data_mojom) { + for (const std::string& method : method_data_entry->supported_methods) { + stringified_method_data_[method].insert( + method_data_entry->stringified_data); + } + PaymentMethodData method_data; method_data.supported_methods = method_data_entry->supported_methods; // Transfer the supported basic card networks.
diff --git a/components/payments/content/payment_request_spec.h b/components/payments/content/payment_request_spec.h index dba1e03..98e7d67 100644 --- a/components/payments/content/payment_request_spec.h +++ b/components/payments/content/payment_request_spec.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_SPEC_H_ #define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_SPEC_H_ +#include <map> #include <set> #include <string> #include <vector> @@ -77,6 +78,10 @@ const std::set<std::string>& supported_card_networks_set() const { return supported_card_networks_set_; } + const std::map<std::string, std::set<std::string>>& stringified_method_data() + const { + return stringified_method_data_; + } // Returns whether the |method_name| was specified as supported through the // "basic-card" payment method. If false, it means either the |method_name| is // not supported at all, or specified directly in supportedMethods. @@ -152,6 +157,10 @@ // |supported_card_networks_set_| to check merchant support. std::set<std::string> basic_card_specified_networks_; + // A mapping of the payment method names to the corresponding JSON-stringified + // payment method specific data. + std::map<std::string, std::set<std::string>> stringified_method_data_; + // The |observer_for_testing_| will fire after all the |observers_| have been // notified. base::ObserverList<Observer> observers_;
diff --git a/components/payments/content/payment_request_web_contents_manager.cc b/components/payments/content/payment_request_web_contents_manager.cc index 1c15003..1d186e1 100644 --- a/components/payments/content/payment_request_web_contents_manager.cc +++ b/components/payments/content/payment_request_web_contents_manager.cc
@@ -28,13 +28,14 @@ } void PaymentRequestWebContentsManager::CreatePaymentRequest( + content::RenderFrameHost* render_frame_host, content::WebContents* web_contents, std::unique_ptr<PaymentRequestDelegate> delegate, mojo::InterfaceRequest<payments::mojom::PaymentRequest> request, PaymentRequest::ObserverForTest* observer_for_testing) { auto new_request = base::MakeUnique<PaymentRequest>( - web_contents, std::move(delegate), this, std::move(request), - observer_for_testing); + render_frame_host, web_contents, std::move(delegate), this, + std::move(request), observer_for_testing); PaymentRequest* request_ptr = new_request.get(); payment_requests_.insert(std::make_pair(request_ptr, std::move(new_request))); }
diff --git a/components/payments/content/payment_request_web_contents_manager.h b/components/payments/content/payment_request_web_contents_manager.h index 1c000ec3..1d4a538 100644 --- a/components/payments/content/payment_request_web_contents_manager.h +++ b/components/payments/content/payment_request_web_contents_manager.h
@@ -15,6 +15,7 @@ #include "mojo/public/cpp/bindings/binding.h" namespace content { +class RenderFrameHost; class WebContents; } @@ -40,8 +41,10 @@ static PaymentRequestWebContentsManager* GetOrCreateForWebContents( content::WebContents* web_contents); - // Creates the PaymentRequest that will interact with this |web_contents|. + // Creates the PaymentRequest that will interact with this |render_frame_host| + // and the associated |web_contents|. void CreatePaymentRequest( + content::RenderFrameHost* render_frame_host, content::WebContents* web_contents, std::unique_ptr<PaymentRequestDelegate> delegate, mojo::InterfaceRequest<payments::mojom::PaymentRequest> request,
diff --git a/components/payments/core/BUILD.gn b/components/payments/core/BUILD.gn index 8d94990..5094bd22 100644 --- a/components/payments/core/BUILD.gn +++ b/components/payments/core/BUILD.gn
@@ -11,6 +11,8 @@ "autofill_payment_instrument.h", "basic_card_response.cc", "basic_card_response.h", + "can_make_payment_query.cc", + "can_make_payment_query.h", "currency_formatter.cc", "currency_formatter.h", "journey_logger.cc", @@ -34,6 +36,7 @@ deps = [ "//base", "//components/autofill/core/browser", + "//components/keyed_service/core", "//components/strings:components_strings_grit", "//components/ukm", "//third_party/libphonenumber",
diff --git a/components/payments/core/DEPS b/components/payments/core/DEPS index 9347542..9117b76 100644 --- a/components/payments/core/DEPS +++ b/components/payments/core/DEPS
@@ -2,6 +2,7 @@ "-components/payments/content", "-content", "+components/autofill/core", + "+components/keyed_service/core", "+components/metrics", "+components/strings", "+components/ukm",
diff --git a/components/payments/core/can_make_payment_query.cc b/components/payments/core/can_make_payment_query.cc new file mode 100644 index 0000000..c4264be8 --- /dev/null +++ b/components/payments/core/can_make_payment_query.cc
@@ -0,0 +1,44 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/payments/core/can_make_payment_query.h" + +#include <utility> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/location.h" +#include "base/memory/ptr_util.h" +#include "base/time/time.h" + +namespace payments { + +CanMakePaymentQuery::CanMakePaymentQuery() {} + +CanMakePaymentQuery::~CanMakePaymentQuery() {} + +bool CanMakePaymentQuery::CanQuery( + const GURL& frame_origin, + const std::map<std::string, std::set<std::string>>& query) { + const auto& it = queries_.find(frame_origin); + if (it == queries_.end()) { + std::unique_ptr<base::OneShotTimer> timer = + base::MakeUnique<base::OneShotTimer>(); + timer->Start(FROM_HERE, base::TimeDelta::FromMinutes(30), + base::Bind(&CanMakePaymentQuery::ExpireQuotaForFrameOrigin, + base::Unretained(this), frame_origin)); + timers_.insert(std::make_pair(frame_origin, std::move(timer))); + queries_.insert(std::make_pair(frame_origin, query)); + return true; + } + + return it->second == query; +} + +void CanMakePaymentQuery::ExpireQuotaForFrameOrigin(const GURL& frame_origin) { + timers_.erase(frame_origin); + queries_.erase(frame_origin); +} + +} // namespace payments
diff --git a/components/payments/core/can_make_payment_query.h b/components/payments/core/can_make_payment_query.h new file mode 100644 index 0000000..69da576 --- /dev/null +++ b/components/payments/core/can_make_payment_query.h
@@ -0,0 +1,50 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PAYMENTS_CORE_CAN_MAKE_PAYMENT_QUERY_H_ +#define COMPONENTS_PAYMENTS_CORE_CAN_MAKE_PAYMENT_QUERY_H_ + +#include <map> +#include <memory> +#include <set> +#include <string> + +#include "base/macros.h" +#include "base/timer/timer.h" +#include "components/keyed_service/core/keyed_service.h" +#include "url/gurl.h" + +namespace payments { + +// Keeps track of canMakePayment() queries per browser context. +class CanMakePaymentQuery : public KeyedService { + public: + CanMakePaymentQuery(); + ~CanMakePaymentQuery() override; + + // Returns whether |frame_origin| can call canMakePayment() with |query|, + // which is a mapping of payment method names to the corresponding + // JSON-stringified payment method data. Remembers the frame-to-query mapping + // for 30 minutes to enforce the quota. + bool CanQuery(const GURL& frame_origin, + const std::map<std::string, std::set<std::string>>& query); + + private: + void ExpireQuotaForFrameOrigin(const GURL& frame_origin); + + // A mapping of frame origin to the timer that, when fired, allows the frame + // to invoke canMakePayment() with a different query. + std::map<GURL, std::unique_ptr<base::OneShotTimer>> timers_; + + // A mapping of frame origin to its last query. Each query is a mapping of + // payment method names to the corresponding JSON-stringified payment method + // data. + std::map<GURL, std::map<std::string, std::set<std::string>>> queries_; + + DISALLOW_COPY_AND_ASSIGN(CanMakePaymentQuery); +}; + +} // namespace payments + +#endif // COMPONENTS_PAYMENTS_CORE_CAN_MAKE_PAYMENT_QUERY_H_
diff --git a/components/sync/DEPS b/components/sync/DEPS index 25bc59b..5ec8a7b 100644 --- a/components/sync/DEPS +++ b/components/sync/DEPS
@@ -6,6 +6,7 @@ # to test. "+base", "+build", + "+components/version_info", "+google_apis", "+testing",
diff --git a/components/sync/base/DEPS b/components/sync/base/DEPS index 67e7d838..e17cf5f 100644 --- a/components/sync/base/DEPS +++ b/components/sync/base/DEPS
@@ -6,7 +6,6 @@ "+components/prefs", "+components/sync/protocol", "+components/sync_preferences", - "+components/version_info", "+crypto", "+google/cacheinvalidation", "+third_party/zlib", # For UniquePosition compression
diff --git a/components/sync/device_info/DEPS b/components/sync/device_info/DEPS index d0e8a8e..6cdc821 100644 --- a/components/sync/device_info/DEPS +++ b/components/sync/device_info/DEPS
@@ -5,5 +5,4 @@ "+components/sync/engine", "+components/sync/model", "+components/sync/protocol", - "+components/version_info", ]
diff --git a/components/sync/driver/DEPS b/components/sync/driver/DEPS index ad82970..29e27de 100644 --- a/components/sync/driver/DEPS +++ b/components/sync/driver/DEPS
@@ -15,9 +15,7 @@ "+components/sync/syncable", "+components/sync/test", "+components/sync_preferences", - "+components/version_info", "+google/cacheinvalidation", - "+google_apis", "+net", "+policy", ]
diff --git a/components/sync/model/recording_model_type_change_processor.cc b/components/sync/model/recording_model_type_change_processor.cc index e74e44f4..a20e299 100644 --- a/components/sync/model/recording_model_type_change_processor.cc +++ b/components/sync/model/recording_model_type_change_processor.cc
@@ -16,10 +16,13 @@ std::unique_ptr<ModelTypeChangeProcessor> CreateAndAssignProcessor( RecordingModelTypeChangeProcessor** processor_address, + bool expect_error, ModelType type, ModelTypeSyncBridge* bridge) { auto processor = base::MakeUnique<RecordingModelTypeChangeProcessor>(); *processor_address = processor.get(); + if (expect_error) + processor->ExpectError(); // Not all compilers are smart enough to up cast during copy elision, so we // explicitly create a correctly typed unique_ptr. return base::WrapUnique(processor.release()); @@ -61,9 +64,10 @@ // static ModelTypeSyncBridge::ChangeProcessorFactory RecordingModelTypeChangeProcessor::FactoryForBridgeTest( - RecordingModelTypeChangeProcessor** processor_address) { + RecordingModelTypeChangeProcessor** processor_address, + bool expect_error) { return base::Bind(&CreateAndAssignProcessor, - base::Unretained(processor_address)); + base::Unretained(processor_address), expect_error); } } // namespace syncer
diff --git a/components/sync/model/recording_model_type_change_processor.h b/components/sync/model/recording_model_type_change_processor.h index 59f87e9..861ec23 100644 --- a/components/sync/model/recording_model_type_change_processor.h +++ b/components/sync/model/recording_model_type_change_processor.h
@@ -48,7 +48,8 @@ // want to verify the RecordingModelTypeChangeProcessor was given data by the // bridge they are testing. static ModelTypeSyncBridge::ChangeProcessorFactory FactoryForBridgeTest( - RecordingModelTypeChangeProcessor** processor_address); + RecordingModelTypeChangeProcessor** processor_address, + bool expect_error = false); private: std::multimap<std::string, std::unique_ptr<EntityData>> put_multimap_;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 333afca9..172ece03 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -136,7 +136,6 @@ "//third_party/WebKit/public:features", "//third_party/WebKit/public:image_resources", "//third_party/WebKit/public:mojo_bindings", - "//third_party/WebKit/public:offscreen_canvas_mojo_bindings", "//third_party/WebKit/public:resources", "//third_party/angle:angle_common", "//third_party/icu", @@ -173,6 +172,7 @@ public_deps = [ "//ipc", "//media/mojo/interfaces:remoting", + "//third_party/WebKit/public:offscreen_canvas_mojo_bindings", "//third_party/leveldatabase", ] @@ -1236,8 +1236,6 @@ "renderer_host/media/video_capture_provider.h", "renderer_host/native_web_keyboard_event_aura.cc", "renderer_host/native_web_keyboard_event_mac.mm", - "renderer_host/offscreen_canvas_compositor_frame_sink_manager.cc", - "renderer_host/offscreen_canvas_compositor_frame_sink_manager.h", "renderer_host/offscreen_canvas_provider_impl.cc", "renderer_host/offscreen_canvas_provider_impl.h", "renderer_host/offscreen_canvas_surface_impl.cc",
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 42f550f0..2f7909aa9 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2794,12 +2794,12 @@ return true; // Standard URLs must match the reported origin. - if (url.IsStandard() && !origin.IsSameOriginWith(url::Origin(url))) + if (url.IsStandard() && !origin.IsSamePhysicalOriginWith(url::Origin(url))) return false; // A non-unique origin must be a valid URL, which allows us to safely do a // conversion to GURL. - GURL origin_url(origin.Serialize()); + GURL origin_url = origin.GetPhysicalOrigin().GetURL(); // Verify that the origin is allowed to commit in this process. // Note: This also handles non-standard cases for |url|, such as
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.cc b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.cc deleted file mode 100644 index 4a87ca3..0000000 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.cc +++ /dev/null
@@ -1,70 +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 "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h" - -#include "base/lazy_instance.h" -#include "cc/surfaces/surface_manager.h" -#include "content/browser/compositor/surface_utils.h" - -namespace content { - -namespace { -base::LazyInstance<OffscreenCanvasCompositorFrameSinkManager>::Leaky g_manager = - LAZY_INSTANCE_INITIALIZER; -} - -OffscreenCanvasCompositorFrameSinkManager:: - OffscreenCanvasCompositorFrameSinkManager() { - GetSurfaceManager()->AddObserver(this); -} - -OffscreenCanvasCompositorFrameSinkManager:: - ~OffscreenCanvasCompositorFrameSinkManager() { - registered_surface_instances_.clear(); - GetSurfaceManager()->RemoveObserver(this); -} - -OffscreenCanvasCompositorFrameSinkManager* -OffscreenCanvasCompositorFrameSinkManager::GetInstance() { - return g_manager.Pointer(); -} - -void OffscreenCanvasCompositorFrameSinkManager::OnSurfaceCreated( - const cc::SurfaceInfo& surface_info) { - auto surface_iter = - registered_surface_instances_.find(surface_info.id().frame_sink_id()); - if (surface_iter == registered_surface_instances_.end()) - return; - OffscreenCanvasSurfaceImpl* surface_impl = surface_iter->second; - surface_impl->OnSurfaceCreated(surface_info); -} - -void OffscreenCanvasCompositorFrameSinkManager:: - RegisterOffscreenCanvasSurfaceInstance( - const cc::FrameSinkId& frame_sink_id, - OffscreenCanvasSurfaceImpl* surface_instance) { - DCHECK(surface_instance); - DCHECK_EQ(registered_surface_instances_.count(frame_sink_id), 0u); - registered_surface_instances_[frame_sink_id] = surface_instance; -} - -void OffscreenCanvasCompositorFrameSinkManager:: - UnregisterOffscreenCanvasSurfaceInstance( - const cc::FrameSinkId& frame_sink_id) { - DCHECK_EQ(registered_surface_instances_.count(frame_sink_id), 1u); - registered_surface_instances_.erase(frame_sink_id); -} - -OffscreenCanvasSurfaceImpl* -OffscreenCanvasCompositorFrameSinkManager::GetSurfaceInstance( - const cc::FrameSinkId& frame_sink_id) { - auto search = registered_surface_instances_.find(frame_sink_id); - if (search != registered_surface_instances_.end()) { - return search->second; - } - return nullptr; -} - -} // namespace content
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h deleted file mode 100644 index 2d3a2599..0000000 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h +++ /dev/null
@@ -1,49 +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 CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_MANAGER_H_ -#define CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_MANAGER_H_ - -#include "base/memory/weak_ptr.h" -#include "cc/surfaces/surface_id.h" -#include "cc/surfaces/surface_observer.h" -#include "content/browser/renderer_host/offscreen_canvas_surface_impl.h" - -namespace content { - -class CONTENT_EXPORT OffscreenCanvasCompositorFrameSinkManager - : public cc::SurfaceObserver { - public: - OffscreenCanvasCompositorFrameSinkManager(); - virtual ~OffscreenCanvasCompositorFrameSinkManager(); - - static OffscreenCanvasCompositorFrameSinkManager* GetInstance(); - - void RegisterOffscreenCanvasSurfaceInstance( - const cc::FrameSinkId& frame_sink_id, - OffscreenCanvasSurfaceImpl* offscreen_canvas_surface); - void UnregisterOffscreenCanvasSurfaceInstance( - const cc::FrameSinkId& frame_sink_id); - OffscreenCanvasSurfaceImpl* GetSurfaceInstance( - const cc::FrameSinkId& frame_sink_id); - - private: - friend class OffscreenCanvasCompositorFrameSinkManagerTest; - - // cc::SurfaceObserver implementation. - void OnSurfaceCreated(const cc::SurfaceInfo& surface_info) override; - void OnSurfaceDamaged(const cc::SurfaceId&, bool* changed) override {} - - // When an OffscreenCanvasSurfaceImpl instance is destructed, it will - // unregister the corresponding entry from this map. - std::unordered_map<cc::FrameSinkId, - OffscreenCanvasSurfaceImpl*, - cc::FrameSinkIdHash> - registered_surface_instances_; - DISALLOW_COPY_AND_ASSIGN(OffscreenCanvasCompositorFrameSinkManager); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_COMPOSITOR_FRAME_SINK_MANAGER_H_
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager_unittest.cc b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager_unittest.cc deleted file mode 100644 index 8733de6c..0000000 --- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager_unittest.cc +++ /dev/null
@@ -1,113 +0,0 @@ -// Copyright (c) 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 "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h" - -#include "base/message_loop/message_loop.h" -#include "cc/surfaces/local_surface_id_allocator.h" -#include "content/browser/compositor/test/no_transport_image_transport_factory.h" -#include "content/browser/renderer_host/offscreen_canvas_surface_impl.h" -#include "content/public/test/test_browser_thread.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom.h" - -#if defined(OS_ANDROID) -#include "base/memory/ptr_util.h" -#else -#include "content/browser/compositor/image_transport_factory.h" -#endif - -namespace content { - -class OffscreenCanvasCompositorFrameSinkManagerTest : public testing::Test { - public: - int getNumSurfaceImplInstances() { - return OffscreenCanvasCompositorFrameSinkManager::GetInstance() - ->registered_surface_instances_.size(); - } - - void OnSurfaceCreated(const cc::SurfaceId& surface_id) { - OffscreenCanvasCompositorFrameSinkManager::GetInstance()->OnSurfaceCreated( - cc::SurfaceInfo(surface_id, 1.0f, gfx::Size(10, 10))); - } - - protected: - void SetUp() override; - void TearDown() override; - - private: - std::unique_ptr<TestBrowserThread> ui_thread_; - base::MessageLoopForUI message_loop_; -}; - -void OffscreenCanvasCompositorFrameSinkManagerTest::SetUp() { -#if !defined(OS_ANDROID) - ImageTransportFactory::InitializeForUnitTests( - std::unique_ptr<ImageTransportFactory>( - new NoTransportImageTransportFactory)); -#endif - ui_thread_.reset(new TestBrowserThread(BrowserThread::UI, &message_loop_)); -} - -void OffscreenCanvasCompositorFrameSinkManagerTest::TearDown() { -#if !defined(OS_ANDROID) - ImageTransportFactory::Terminate(); -#endif -} - -// This test mimics the workflow of OffscreenCanvas.commit() on renderer -// process. -TEST_F(OffscreenCanvasCompositorFrameSinkManagerTest, - SingleHTMLCanvasElementTransferToOffscreen) { - blink::mojom::OffscreenCanvasSurfaceClientPtr client; - cc::FrameSinkId frame_sink_id(3, 3); - cc::LocalSurfaceIdAllocator local_surface_id_allocator; - cc::LocalSurfaceId current_local_surface_id( - local_surface_id_allocator.GenerateId()); - - auto surface_impl = base::WrapUnique(new OffscreenCanvasSurfaceImpl( - cc::FrameSinkId(), frame_sink_id, std::move(client))); - EXPECT_EQ(1, this->getNumSurfaceImplInstances()); - EXPECT_EQ(surface_impl.get(), - OffscreenCanvasCompositorFrameSinkManager::GetInstance() - ->GetSurfaceInstance(frame_sink_id)); - - this->OnSurfaceCreated( - cc::SurfaceId(frame_sink_id, current_local_surface_id)); - EXPECT_EQ(current_local_surface_id, surface_impl->current_local_surface_id()); - - surface_impl = nullptr; - EXPECT_EQ(0, this->getNumSurfaceImplInstances()); -} - -TEST_F(OffscreenCanvasCompositorFrameSinkManagerTest, - MultiHTMLCanvasElementTransferToOffscreen) { - blink::mojom::OffscreenCanvasSurfaceClientPtr client_a; - cc::FrameSinkId dummy_parent_frame_sink_id(0, 0); - cc::FrameSinkId frame_sink_id_a(3, 3); - auto surface_impl_a = base::WrapUnique(new OffscreenCanvasSurfaceImpl( - dummy_parent_frame_sink_id, frame_sink_id_a, std::move(client_a))); - - blink::mojom::OffscreenCanvasSurfaceClientPtr client_b; - cc::FrameSinkId frame_sink_id_b(4, 4); - - auto surface_impl_b = base::WrapUnique(new OffscreenCanvasSurfaceImpl( - dummy_parent_frame_sink_id, frame_sink_id_b, std::move(client_b))); - - EXPECT_EQ(2, this->getNumSurfaceImplInstances()); - EXPECT_EQ(surface_impl_a.get(), - OffscreenCanvasCompositorFrameSinkManager::GetInstance() - ->GetSurfaceInstance(frame_sink_id_a)); - EXPECT_EQ(surface_impl_b.get(), - OffscreenCanvasCompositorFrameSinkManager::GetInstance() - ->GetSurfaceInstance(frame_sink_id_b)); - - surface_impl_a = nullptr; - EXPECT_EQ(1, this->getNumSurfaceImplInstances()); - surface_impl_b = nullptr; - EXPECT_EQ(0, this->getNumSurfaceImplInstances()); -} - -} // namespace content
diff --git a/content/browser/renderer_host/offscreen_canvas_provider_impl.cc b/content/browser/renderer_host/offscreen_canvas_provider_impl.cc index 7e9567a..c16e1aa 100644 --- a/content/browser/renderer_host/offscreen_canvas_provider_impl.cc +++ b/content/browser/renderer_host/offscreen_canvas_provider_impl.cc
@@ -4,8 +4,7 @@ #include "content/browser/renderer_host/offscreen_canvas_provider_impl.h" -#include "content/browser/compositor/surface_utils.h" -#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h" +#include "base/bind.h" #include "content/browser/renderer_host/offscreen_canvas_surface_impl.h" namespace content { @@ -36,8 +35,13 @@ return; } - OffscreenCanvasSurfaceImpl::Create(parent_frame_sink_id, frame_sink_id, - std::move(client), std::move(request)); + auto destroy_callback = base::BindOnce( + &OffscreenCanvasProviderImpl::DestroyOffscreenCanvasSurface, + base::Unretained(this), frame_sink_id); + + canvas_map_[frame_sink_id] = base::MakeUnique<OffscreenCanvasSurfaceImpl>( + parent_frame_sink_id, frame_sink_id, std::move(client), + std::move(request), std::move(destroy_callback)); } void OffscreenCanvasProviderImpl::CreateCompositorFrameSink( @@ -50,16 +54,19 @@ return; } - // TODO(kylechar): Add test for bad |frame_sink_id|. - auto* manager = OffscreenCanvasCompositorFrameSinkManager::GetInstance(); - auto* surface_impl = manager->GetSurfaceInstance(frame_sink_id); - if (!surface_impl) { + auto iter = canvas_map_.find(frame_sink_id); + if (iter == canvas_map_.end()) { DLOG(ERROR) << "No OffscreenCanvasSurfaceImpl for " << frame_sink_id; return; } - surface_impl->CreateCompositorFrameSink(std::move(client), + iter->second->CreateCompositorFrameSink(std::move(client), std::move(request)); } +void OffscreenCanvasProviderImpl::DestroyOffscreenCanvasSurface( + cc::FrameSinkId frame_sink_id) { + canvas_map_.erase(frame_sink_id); +} + } // namespace content
diff --git a/content/browser/renderer_host/offscreen_canvas_provider_impl.h b/content/browser/renderer_host/offscreen_canvas_provider_impl.h index 554e121..54f5070 100644 --- a/content/browser/renderer_host/offscreen_canvas_provider_impl.h +++ b/content/browser/renderer_host/offscreen_canvas_provider_impl.h
@@ -5,14 +5,20 @@ #ifndef CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_PROVIDER_IMPL_H_ #define CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_PROVIDER_IMPL_H_ +#include <memory> + +#include "base/containers/flat_map.h" #include "cc/surfaces/frame_sink_id.h" +#include "content/common/content_export.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom.h" namespace content { +class OffscreenCanvasSurfaceImpl; + // Creates OffscreenCanvasSurfaces and MojoCompositorFrameSinks for a renderer. -class OffscreenCanvasProviderImpl +class CONTENT_EXPORT OffscreenCanvasProviderImpl : public blink::mojom::OffscreenCanvasProvider { public: explicit OffscreenCanvasProviderImpl(uint32_t renderer_client_id); @@ -32,11 +38,20 @@ cc::mojom::MojoCompositorFrameSinkRequest request) override; private: + friend class OffscreenCanvasProviderImplTest; + + // Destroys the |canvas_map_| entry for |frame_sink_id|. Provided as a + // callback to each OffscreenCanvasSurfaceImpl so they can destroy themselves. + void DestroyOffscreenCanvasSurface(cc::FrameSinkId frame_sink_id); + // FrameSinkIds for offscreen canvas must use the renderer client id. const uint32_t renderer_client_id_; mojo::BindingSet<blink::mojom::OffscreenCanvasProvider> bindings_; + base::flat_map<cc::FrameSinkId, std::unique_ptr<OffscreenCanvasSurfaceImpl>> + canvas_map_; + DISALLOW_COPY_AND_ASSIGN(OffscreenCanvasProviderImpl); };
diff --git a/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc b/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc new file mode 100644 index 0000000..06e1f5a --- /dev/null +++ b/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc
@@ -0,0 +1,347 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/offscreen_canvas_provider_impl.h" + +#include <algorithm> +#include <utility> +#include <vector> + +#include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "cc/ipc/mojo_compositor_frame_sink.mojom.h" +#include "cc/output/compositor_frame.h" +#include "content/browser/compositor/test/no_transport_image_transport_factory.h" +#include "content/browser/renderer_host/offscreen_canvas_surface_impl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom.h" + +#if !defined(OS_ANDROID) +#include "content/browser/compositor/image_transport_factory.h" +#endif + +using testing::ElementsAre; +using testing::IsEmpty; + +namespace content { +namespace { + +constexpr uint32_t kRendererClientId = 3; +constexpr cc::FrameSinkId kFrameSinkParent(kRendererClientId, 1); +constexpr cc::FrameSinkId kFrameSinkA(kRendererClientId, 3); +constexpr cc::FrameSinkId kFrameSinkB(kRendererClientId, 4); + +// Stub OffscreenCanvasSurfaceClient that stores the latest SurfaceInfo. +class StubOffscreenCanvasSurfaceClient + : public blink::mojom::OffscreenCanvasSurfaceClient { + public: + StubOffscreenCanvasSurfaceClient() : binding_(this) {} + ~StubOffscreenCanvasSurfaceClient() override {} + + blink::mojom::OffscreenCanvasSurfaceClientPtr GetInterfacePtr() { + return binding_.CreateInterfacePtrAndBind(); + } + + const cc::SurfaceInfo& GetLastSurfaceInfo() const { + return last_surface_info_; + } + + private: + // blink::mojom::OffscreenCanvasSurfaceClient: + void OnSurfaceCreated(const cc::SurfaceInfo& surface_info) override { + last_surface_info_ = surface_info; + } + + mojo::Binding<blink::mojom::OffscreenCanvasSurfaceClient> binding_; + cc::SurfaceInfo last_surface_info_; + + DISALLOW_COPY_AND_ASSIGN(StubOffscreenCanvasSurfaceClient); +}; + +// Stub MojoCompositorFrameSinkClient that does nothing. +class StubCompositorFrameSinkClient + : public cc::mojom::MojoCompositorFrameSinkClient { + public: + StubCompositorFrameSinkClient() : binding_(this) {} + ~StubCompositorFrameSinkClient() override {} + + cc::mojom::MojoCompositorFrameSinkClientPtr GetInterfacePtr() { + return binding_.CreateInterfacePtrAndBind(); + } + + private: + // cc::mojom::MojoCompositorFrameSinkClient: + void DidReceiveCompositorFrameAck( + const cc::ReturnedResourceArray& resources) override {} + void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) override {} + void ReclaimResources(const cc::ReturnedResourceArray& resources) override {} + + mojo::Binding<cc::mojom::MojoCompositorFrameSinkClient> binding_; + + DISALLOW_COPY_AND_ASSIGN(StubCompositorFrameSinkClient); +}; + +// Create a CompositorFrame suitable to send over IPC. +cc::CompositorFrame MakeCompositorFrame() { + cc::CompositorFrame frame; + frame.metadata.begin_frame_ack.source_id = + cc::BeginFrameArgs::kManualSourceId; + frame.metadata.begin_frame_ack.sequence_number = + cc::BeginFrameArgs::kStartingFrameNumber; + frame.metadata.device_scale_factor = 1.0f; + + auto render_pass = cc::RenderPass::Create(); + render_pass->id = 1; + render_pass->output_rect = gfx::Rect(100, 100); + frame.render_pass_list.push_back(std::move(render_pass)); + + return frame; +} + +// Creates a closure that sets |error_variable| true when run. +base::Closure ConnectionErrorClosure(bool* error_variable) { + return base::Bind([](bool* error_variable) { *error_variable = true; }, + error_variable); +} + +} // namespace + +class OffscreenCanvasProviderImplTest : public testing::Test { + public: + OffscreenCanvasProviderImpl* provider() { return provider_.get(); } + + // Gets the OffscreenCanvasSurfaceImpl for |frame_sink_id| or null if it + // it doesn't exist. + OffscreenCanvasSurfaceImpl* GetOffscreenCanvasSurface( + const cc::FrameSinkId& frame_sink_id) { + auto iter = provider_->canvas_map_.find(frame_sink_id); + if (iter == provider_->canvas_map_.end()) + return nullptr; + return iter->second.get(); + } + + // Gets list of FrameSinkId for all offscreen canvases. + std::vector<cc::FrameSinkId> GetAllCanvases() { + std::vector<cc::FrameSinkId> frame_sink_ids; + for (auto& map_entry : provider_->canvas_map_) + frame_sink_ids.push_back(map_entry.second->frame_sink_id()); + std::sort(frame_sink_ids.begin(), frame_sink_ids.end()); + return frame_sink_ids; + } + + void DeleteOffscreenCanvasProviderImpl() { provider_.reset(); } + + void RunUntilIdle() { base::RunLoop().RunUntilIdle(); } + + protected: + void SetUp() override { +#if !defined(OS_ANDROID) + ImageTransportFactory::InitializeForUnitTests( + std::unique_ptr<ImageTransportFactory>( + new NoTransportImageTransportFactory)); + ImageTransportFactory::GetInstance() + ->GetFrameSinkManagerHost() + ->ConnectToFrameSinkManager(); +#endif + provider_ = + base::MakeUnique<OffscreenCanvasProviderImpl>(kRendererClientId); + } + void TearDown() override { + provider_.reset(); +#if !defined(OS_ANDROID) + ImageTransportFactory::Terminate(); +#endif + } + + private: + base::MessageLoop message_loop_; + std::unique_ptr<OffscreenCanvasProviderImpl> provider_; +}; + +// Mimics the workflow of OffscreenCanvas.commit() on renderer process. +TEST_F(OffscreenCanvasProviderImplTest, + SingleHTMLCanvasElementTransferToOffscreen) { + // Mimic connection from the renderer main thread to browser. + StubOffscreenCanvasSurfaceClient surface_client; + blink::mojom::OffscreenCanvasSurfacePtr surface; + provider()->CreateOffscreenCanvasSurface(kFrameSinkParent, kFrameSinkA, + surface_client.GetInterfacePtr(), + mojo::MakeRequest(&surface)); + + OffscreenCanvasSurfaceImpl* surface_impl = + GetOffscreenCanvasSurface(kFrameSinkA); + + // There should be a single OffscreenCanvasSurfaceImpl and it should have the + // provided FrameSinkId and parent FrameSinkId. + EXPECT_EQ(kFrameSinkA, surface_impl->frame_sink_id()); + EXPECT_EQ(kFrameSinkParent, surface_impl->parent_frame_sink_id()); + EXPECT_THAT(GetAllCanvases(), ElementsAre(kFrameSinkA)); + + // Mimic connection from the renderer main or worker thread to browser. + cc::mojom::MojoCompositorFrameSinkPtr compositor_frame_sink; + StubCompositorFrameSinkClient compositor_frame_sink_client; + provider()->CreateCompositorFrameSink( + kFrameSinkA, compositor_frame_sink_client.GetInterfacePtr(), + mojo::MakeRequest(&compositor_frame_sink)); + + // Renderer submits a CompositorFrame with |local_id|. + const cc::LocalSurfaceId local_id(1, base::UnguessableToken::Create()); + compositor_frame_sink->SubmitCompositorFrame(local_id, MakeCompositorFrame()); + + RunUntilIdle(); + + // OffscreenCanvasSurfaceImpl in browser should have LocalSurfaceId that was + // submitted with the CompositorFrame. + EXPECT_EQ(local_id, surface_impl->local_surface_id()); + + // OffscreenCanvasSurfaceClient in the renderer should get the new SurfaceId + // including the |local_id|. + const auto& surface_info = surface_client.GetLastSurfaceInfo(); + EXPECT_EQ(kFrameSinkA, surface_info.id().frame_sink_id()); + EXPECT_EQ(local_id, surface_info.id().local_surface_id()); +} + +// Check that renderer closing the mojom::OffscreenCanvasSurface connection +// destroys the OffscreenCanvasSurfaceImpl in browser. +TEST_F(OffscreenCanvasProviderImplTest, ClientClosesConnection) { + StubOffscreenCanvasSurfaceClient surface_client; + blink::mojom::OffscreenCanvasSurfacePtr surface; + provider()->CreateOffscreenCanvasSurface(kFrameSinkParent, kFrameSinkA, + surface_client.GetInterfacePtr(), + mojo::MakeRequest(&surface)); + + RunUntilIdle(); + + EXPECT_THAT(GetAllCanvases(), ElementsAre(kFrameSinkA)); + + // Mimic closing the connection from the renderer. + surface.reset(); + + RunUntilIdle(); + + // The renderer closing the connection should destroy the + // OffscreenCanvasSurfaceImpl. + EXPECT_THAT(GetAllCanvases(), IsEmpty()); +} + +// Check that destroying OffscreenCanvasProviderImpl closes connection to +// renderer. +TEST_F(OffscreenCanvasProviderImplTest, ProviderClosesConnections) { + StubOffscreenCanvasSurfaceClient surface_client; + blink::mojom::OffscreenCanvasSurfacePtr surface; + provider()->CreateOffscreenCanvasSurface(kFrameSinkParent, kFrameSinkA, + surface_client.GetInterfacePtr(), + mojo::MakeRequest(&surface)); + + // Observe connection errors on |surface|. + bool connection_error = false; + surface.set_connection_error_handler( + ConnectionErrorClosure(&connection_error)); + + RunUntilIdle(); + + // There should be a OffscreenCanvasSurfaceImpl and |surface| should be bound. + EXPECT_THAT(GetAllCanvases(), ElementsAre(kFrameSinkA)); + EXPECT_TRUE(surface.is_bound()); + EXPECT_FALSE(connection_error); + + // Delete OffscreenCanvasProviderImpl before client disconnects. + DeleteOffscreenCanvasProviderImpl(); + + RunUntilIdle(); + + // This should destroy the OffscreenCanvasSurfaceImpl and close the connection + // to |surface| triggering a connection error. + EXPECT_TRUE(connection_error); +} + +// Check that connecting MojoCompositorFrameSink without first making a +// OffscreenCanvasSurface connection fails. +TEST_F(OffscreenCanvasProviderImplTest, ClientConnectionWrongOrder) { + // Mimic connection from the renderer main or worker thread. + cc::mojom::MojoCompositorFrameSinkPtr compositor_frame_sink; + StubCompositorFrameSinkClient compositor_frame_sink_client; + // Try to connect MojoCompositorFrameSink without first making + // OffscreenCanvasSurface connection. This should fail. + provider()->CreateCompositorFrameSink( + kFrameSinkA, compositor_frame_sink_client.GetInterfacePtr(), + mojo::MakeRequest(&compositor_frame_sink)); + + // Observe connection errors on |compositor_frame_sink|. + bool connection_error = false; + compositor_frame_sink.set_connection_error_handler( + ConnectionErrorClosure(&connection_error)); + + RunUntilIdle(); + + // The connection for |compositor_frame_sink| will have failed and triggered a + // connection error. + EXPECT_TRUE(connection_error); +} + +// Check that trying to create an OffscreenCanvasSurfaceImpl with a client id +// that doesn't match the renderer fails. +TEST_F(OffscreenCanvasProviderImplTest, InvalidClientId) { + const cc::FrameSinkId invalid_frame_sink_id(4, 3); + EXPECT_NE(kRendererClientId, invalid_frame_sink_id.client_id()); + + StubOffscreenCanvasSurfaceClient surface_client; + blink::mojom::OffscreenCanvasSurfacePtr surface; + provider()->CreateOffscreenCanvasSurface( + kFrameSinkParent, invalid_frame_sink_id, surface_client.GetInterfacePtr(), + mojo::MakeRequest(&surface)); + + // Observe connection errors on |surface|. + bool connection_error = false; + surface.set_connection_error_handler( + ConnectionErrorClosure(&connection_error)); + + RunUntilIdle(); + + // No OffscreenCanvasSurfaceImpl should have been created. + EXPECT_THAT(GetAllCanvases(), IsEmpty()); + + // The connection for |surface| will have failed and triggered a connection + // error. + EXPECT_TRUE(connection_error); +} + +// Mimic renderer with two offscreen canvases. +TEST_F(OffscreenCanvasProviderImplTest, + MultiHTMLCanvasElementTransferToOffscreen) { + StubOffscreenCanvasSurfaceClient surface_client_a; + blink::mojom::OffscreenCanvasSurfacePtr surface_a; + provider()->CreateOffscreenCanvasSurface(kFrameSinkParent, kFrameSinkA, + surface_client_a.GetInterfacePtr(), + mojo::MakeRequest(&surface_a)); + + StubOffscreenCanvasSurfaceClient surface_client_b; + blink::mojom::OffscreenCanvasSurfacePtr surface_b; + provider()->CreateOffscreenCanvasSurface(kFrameSinkParent, kFrameSinkB, + surface_client_b.GetInterfacePtr(), + mojo::MakeRequest(&surface_b)); + + RunUntilIdle(); + + // There should be two OffscreenCanvasSurfaceImpls created. + EXPECT_THAT(GetAllCanvases(), ElementsAre(kFrameSinkA, kFrameSinkB)); + + // Mimic closing first connection from the renderer. + surface_a.reset(); + + RunUntilIdle(); + + EXPECT_THAT(GetAllCanvases(), ElementsAre(kFrameSinkB)); + + // Mimic closing second connection from the renderer. + surface_b.reset(); + + RunUntilIdle(); + + EXPECT_THAT(GetAllCanvases(), IsEmpty()); +} + +} // namespace content
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc index 4145493..8058e25f 100644 --- a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc +++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
@@ -7,24 +7,28 @@ #include <memory> #include <utility> -#include "base/bind_helpers.h" #include "base/memory/ptr_util.h" #include "cc/surfaces/surface_manager.h" #include "content/browser/compositor/frame_sink_manager_host.h" #include "content/browser/compositor/surface_utils.h" -#include "content/browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager.h" namespace content { OffscreenCanvasSurfaceImpl::OffscreenCanvasSurfaceImpl( const cc::FrameSinkId& parent_frame_sink_id, const cc::FrameSinkId& frame_sink_id, - blink::mojom::OffscreenCanvasSurfaceClientPtr client) + blink::mojom::OffscreenCanvasSurfaceClientPtr client, + blink::mojom::OffscreenCanvasSurfaceRequest request, + DestroyCallback destroy_callback) : client_(std::move(client)), + binding_(this, std::move(request)), + destroy_callback_(std::move(destroy_callback)), frame_sink_id_(frame_sink_id), parent_frame_sink_id_(parent_frame_sink_id) { - OffscreenCanvasCompositorFrameSinkManager::GetInstance() - ->RegisterOffscreenCanvasSurfaceInstance(frame_sink_id_, this); + binding_.set_connection_error_handler( + base::Bind(&OffscreenCanvasSurfaceImpl::OnSurfaceConnectionClosed, + base::Unretained(this))); + GetFrameSinkManagerHost()->AddObserver(this); } OffscreenCanvasSurfaceImpl::~OffscreenCanvasSurfaceImpl() { @@ -32,22 +36,7 @@ GetFrameSinkManagerHost()->UnregisterFrameSinkHierarchy( parent_frame_sink_id_, frame_sink_id_); } - OffscreenCanvasCompositorFrameSinkManager::GetInstance() - ->UnregisterOffscreenCanvasSurfaceInstance(frame_sink_id_); -} - -// static -void OffscreenCanvasSurfaceImpl::Create( - const cc::FrameSinkId& parent_frame_sink_id, - const cc::FrameSinkId& frame_sink_id, - blink::mojom::OffscreenCanvasSurfaceClientPtr client, - blink::mojom::OffscreenCanvasSurfaceRequest request) { - std::unique_ptr<OffscreenCanvasSurfaceImpl> impl = - base::MakeUnique<OffscreenCanvasSurfaceImpl>( - parent_frame_sink_id, frame_sink_id, std::move(client)); - OffscreenCanvasSurfaceImpl* surface_service = impl.get(); - surface_service->binding_ = - mojo::MakeStrongBinding(std::move(impl), std::move(request)); + GetFrameSinkManagerHost()->RemoveObserver(this); } void OffscreenCanvasSurfaceImpl::CreateCompositorFrameSink( @@ -69,13 +58,12 @@ void OffscreenCanvasSurfaceImpl::OnSurfaceCreated( const cc::SurfaceInfo& surface_info) { - DCHECK_EQ(surface_info.id().frame_sink_id(), frame_sink_id_); - if (!current_local_surface_id_.is_valid() || - surface_info.id().local_surface_id() != current_local_surface_id_) { - current_local_surface_id_ = surface_info.id().local_surface_id(); - if (client_) - client_->OnSurfaceCreated(surface_info); - } + if (surface_info.id().frame_sink_id() != frame_sink_id_) + return; + + local_surface_id_ = surface_info.id().local_surface_id(); + if (client_) + client_->OnSurfaceCreated(surface_info); } void OffscreenCanvasSurfaceImpl::Require(const cc::SurfaceId& surface_id, @@ -87,4 +75,8 @@ GetSurfaceManager()->SatisfySequence(sequence); } +void OffscreenCanvasSurfaceImpl::OnSurfaceConnectionClosed() { + std::move(destroy_callback_).Run(); +} + } // namespace content
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.h b/content/browser/renderer_host/offscreen_canvas_surface_impl.h index 14d4b0a..ff566c5 100644 --- a/content/browser/renderer_host/offscreen_canvas_surface_impl.h +++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.h
@@ -5,8 +5,13 @@ #ifndef CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_SURFACE_IMPL_H_ #define CONTENT_BROWSER_RENDERER_HOST_OFFSCREEN_CANVAS_SURFACE_IMPL_H_ -#include "cc/surfaces/surface_id.h" -#include "mojo/public/cpp/bindings/strong_binding.h" +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "cc/surfaces/frame_sink_id.h" +#include "cc/surfaces/surface_info.h" +#include "content/browser/compositor/frame_sink_observer.h" +#include "content/common/content_export.h" +#include "mojo/public/cpp/bindings/binding.h" #include "third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom.h" namespace content { @@ -14,18 +19,28 @@ // The browser owned object for an offscreen canvas connection. Holds // connections to both the renderer and frame sink manager. class CONTENT_EXPORT OffscreenCanvasSurfaceImpl - : public blink::mojom::OffscreenCanvasSurface { + : public blink::mojom::OffscreenCanvasSurface, + public NON_EXPORTED_BASE(FrameSinkObserver) { public: + using DestroyCallback = base::OnceCallback<void()>; + OffscreenCanvasSurfaceImpl( const cc::FrameSinkId& parent_frame_sink_id, const cc::FrameSinkId& frame_sink_id, - blink::mojom::OffscreenCanvasSurfaceClientPtr client); + blink::mojom::OffscreenCanvasSurfaceClientPtr client, + blink::mojom::OffscreenCanvasSurfaceRequest request, + DestroyCallback destroy_callback); ~OffscreenCanvasSurfaceImpl() override; - static void Create(const cc::FrameSinkId& parent_frame_sink_id, - const cc::FrameSinkId& frame_sink_id, - blink::mojom::OffscreenCanvasSurfaceClientPtr client, - blink::mojom::OffscreenCanvasSurfaceRequest request); + const cc::FrameSinkId& frame_sink_id() const { return frame_sink_id_; } + + const cc::FrameSinkId& parent_frame_sink_id() const { + return parent_frame_sink_id_; + } + + const cc::LocalSurfaceId& local_surface_id() const { + return local_surface_id_; + } // Creates a MojoCompositorFrameSink connection to FrameSinkManager for an // offscreen canvas client. The corresponding private interface will be owned @@ -35,35 +50,33 @@ cc::mojom::MojoCompositorFrameSinkClientPtr client, cc::mojom::MojoCompositorFrameSinkRequest request); - void OnSurfaceCreated(const cc::SurfaceInfo& surface_info); + // FrameSinkObserver implementation. + void OnSurfaceCreated(const cc::SurfaceInfo& surface_info) override; // blink::mojom::OffscreenCanvasSurface implementation. void Require(const cc::SurfaceId& surface_id, const cc::SurfaceSequence& sequence) override; void Satisfy(const cc::SurfaceSequence& sequence) override; - const cc::FrameSinkId& frame_sink_id() const { return frame_sink_id_; } - - const cc::FrameSinkId& parent_frame_sink_id() const { - return parent_frame_sink_id_; - } - - const cc::LocalSurfaceId& current_local_surface_id() const { - return current_local_surface_id_; - } - private: + // Registered as a callback for when |binding_| is closed. Will call + // |destroy_callback_|. + void OnSurfaceConnectionClosed(); + blink::mojom::OffscreenCanvasSurfaceClientPtr client_; - mojo::StrongBindingPtr<blink::mojom::OffscreenCanvasSurface> binding_; + mojo::Binding<blink::mojom::OffscreenCanvasSurface> binding_; // Private connection for the CompositorFrameSink. The CompositorFrameSink // will not be destroyed until both private and offscreen canvas client // connections are closed. cc::mojom::MojoCompositorFrameSinkPrivatePtr compositor_frame_sink_private_; + // To be called if |binding_| is closed. + DestroyCallback destroy_callback_; + // Surface-related state const cc::FrameSinkId frame_sink_id_; - cc::LocalSurfaceId current_local_surface_id_; + cc::LocalSurfaceId local_surface_id_; const cc::FrameSinkId parent_frame_sink_id_; bool has_created_compositor_frame_sink_ = false;
diff --git a/content/child/blink_platform_impl_unittest.cc b/content/child/blink_platform_impl_unittest.cc index 47b3659..ca84ee2f 100644 --- a/content/child/blink_platform_impl_unittest.cc +++ b/content/child/blink_platform_impl_unittest.cc
@@ -20,7 +20,7 @@ url::Origin checked_origin = url::Origin::UnsafelyCreateOriginWithoutNormalization( origin.Protocol().Utf8(), origin.Host().Utf8(), - origin.EffectivePort()); + origin.EffectivePort(), origin.Suborigin().Utf8()); url::Origin non_checked_origin = url::Origin::CreateFromNormalizedTupleWithSuborigin( origin.Protocol().Utf8(), origin.Host().Utf8(),
diff --git a/content/public/common/common_param_traits.cc b/content/public/common/common_param_traits.cc index 3fcfdda..286e6621 100644 --- a/content/public/common/common_param_traits.cc +++ b/content/public/common/common_param_traits.cc
@@ -21,6 +21,7 @@ GetParamSize(s, p.scheme()); GetParamSize(s, p.host()); GetParamSize(s, p.port()); + GetParamSize(s, p.suborigin()); } void ParamTraits<url::Origin>::Write(base::Pickle* m, const url::Origin& p) { @@ -28,6 +29,7 @@ WriteParam(m, p.scheme()); WriteParam(m, p.host()); WriteParam(m, p.port()); + WriteParam(m, p.suborigin()); } bool ParamTraits<url::Origin>::Read(const base::Pickle* m, @@ -37,15 +39,17 @@ std::string scheme; std::string host; uint16_t port; + std::string suborigin; if (!ReadParam(m, iter, &unique) || !ReadParam(m, iter, &scheme) || - !ReadParam(m, iter, &host) || !ReadParam(m, iter, &port)) { + !ReadParam(m, iter, &host) || !ReadParam(m, iter, &port) || + !ReadParam(m, iter, &suborigin)) { *p = url::Origin(); return false; } *p = unique ? url::Origin() : url::Origin::UnsafelyCreateOriginWithoutNormalization( - scheme, host, port); + scheme, host, port, suborigin); // If a unique origin was created, but the unique flag wasn't set, then // the values provided to 'UnsafelyCreateOriginWithoutNormalization' were
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index c72402f..1122904 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1240,7 +1240,7 @@ "../browser/renderer_host/media/video_capture_controller_unittest.cc", "../browser/renderer_host/media/video_capture_manager_unittest.cc", "../browser/renderer_host/media/video_capture_unittest.cc", - "../browser/renderer_host/offscreen_canvas_compositor_frame_sink_manager_unittest.cc", + "../browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc", "../browser/renderer_host/render_process_host_unittest.cc", "../browser/renderer_host/render_view_host_unittest.cc", "../browser/renderer_host/render_widget_host_unittest.cc", @@ -1512,7 +1512,6 @@ "//testing/gmock", "//testing/gtest", "//third_party/WebKit/public:blink", - "//third_party/WebKit/public:offscreen_canvas_mojo_bindings", "//third_party/icu", "//third_party/leveldatabase", "//third_party/re2",
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt index d3585f8..1e495a9 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt +++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@ # AUTOGENERATED FILE - DO NOT EDIT # SEE roll_webgl_conformance.py -Current webgl revision c91689d6df5536fefaa07a459c80c210bd580a1b +Current webgl revision 73b300f24942adf7013de30ccdc6a2cc88105e72
diff --git a/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc b/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc index 74f6c9d3..779e9a2c 100644 --- a/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc +++ b/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc
@@ -31,6 +31,8 @@ namespace SetAlwaysOnTop = app_current_window_internal::SetAlwaysOnTop; namespace SetVisibleOnAllWorkspaces = app_current_window_internal::SetVisibleOnAllWorkspaces; +namespace SetActivateOnPointer = + app_current_window_internal::SetActivateOnPointer; using app_current_window_internal::Bounds; using app_current_window_internal::Region; @@ -377,4 +379,13 @@ return RespondNow(NoArguments()); } +ExtensionFunction::ResponseAction +AppCurrentWindowInternalSetActivateOnPointerFunction::Run() { + std::unique_ptr<SetActivateOnPointer::Params> params( + SetActivateOnPointer::Params::Create(*args_)); + CHECK(params.get()); + window()->GetBaseWindow()->SetActivateOnPointer(params->activate_on_pointer); + return RespondNow(NoArguments()); +} + } // namespace extensions
diff --git a/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.h b/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.h index 66f265a4..72ddd534 100644 --- a/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.h +++ b/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.h
@@ -190,6 +190,17 @@ ResponseAction Run() override; }; +class AppCurrentWindowInternalSetActivateOnPointerFunction + : public AppCurrentWindowInternalExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("app.currentWindowInternal.setActivateOnPointer", + APP_CURRENTWINDOWINTERNAL_SETACTIVATEONPOINTER) + + protected: + ~AppCurrentWindowInternalSetActivateOnPointerFunction() override {} + ResponseAction Run() override; +}; + } // namespace extensions #endif // EXTENSIONS_BROWSER_API_APP_CURRENT_WINDOW_INTERNAL_APP_CURRENT_WINDOW_INTERNAL_API_H_
diff --git a/extensions/browser/app_window/native_app_window.h b/extensions/browser/app_window/native_app_window.h index a6510c88..719180bb 100644 --- a/extensions/browser/app_window/native_app_window.h +++ b/extensions/browser/app_window/native_app_window.h
@@ -94,6 +94,9 @@ // when compositing. virtual bool CanHaveAlphaEnabled() const = 0; + // Sets whether the window should be activated on pointer event. + virtual void SetActivateOnPointer(bool activate_on_pointer) = 0; + ~NativeAppWindow() override {} };
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 0faac6a..8be8786 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1233,6 +1233,7 @@ WEBRTC_AUDIO_PRIVATE_SET_AUDIO_EXPERIMENTS, AUTOTESTPRIVATE_GETPLAYSTORESTATE, AUTOTESTPRIVATE_SETPLAYSTOREENABLED, + APP_CURRENTWINDOWINTERNAL_SETACTIVATEONPOINTER, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/common/api/app_current_window_internal.idl b/extensions/common/api/app_current_window_internal.idl index 344ef1c..13937b3 100644 --- a/extensions/common/api/app_current_window_internal.idl +++ b/extensions/common/api/app_current_window_internal.idl
@@ -51,6 +51,7 @@ static void setShape(Region region); static void setAlwaysOnTop(boolean always_on_top); static void setVisibleOnAllWorkspaces(boolean always_visible); + static void setActivateOnPointer(boolean activate_on_pointer); }; interface Events {
diff --git a/extensions/components/native_app_window/native_app_window_views.cc b/extensions/components/native_app_window/native_app_window_views.cc index f4abafac..e2818e20 100644 --- a/extensions/components/native_app_window/native_app_window_views.cc +++ b/extensions/components/native_app_window/native_app_window_views.cc
@@ -439,4 +439,6 @@ widget_->SetVisibleOnAllWorkspaces(always_visible); } +void NativeAppWindowViews::SetActivateOnPointer(bool activate_on_pointer) {} + } // namespace native_app_window
diff --git a/extensions/components/native_app_window/native_app_window_views.h b/extensions/components/native_app_window/native_app_window_views.h index f7cb963..b5213a0 100644 --- a/extensions/components/native_app_window/native_app_window_views.h +++ b/extensions/components/native_app_window/native_app_window_views.h
@@ -147,6 +147,7 @@ const gfx::Size& max_size) override; bool CanHaveAlphaEnabled() const override; void SetVisibleOnAllWorkspaces(bool always_visible) override; + void SetActivateOnPointer(bool activate_on_pointer) override; // web_modal::WebContentsModalDialogHost implementation. gfx::NativeView GetHostView() const override;
diff --git a/extensions/shell/browser/shell_native_app_window.cc b/extensions/shell/browser/shell_native_app_window.cc index cee27aab..8d9044c 100644 --- a/extensions/shell/browser/shell_native_app_window.cc +++ b/extensions/shell/browser/shell_native_app_window.cc
@@ -195,4 +195,8 @@ return false; } +void ShellNativeAppWindow::SetActivateOnPointer(bool activate_on_pointer) { + NOTIMPLEMENTED(); +} + } // namespace extensions
diff --git a/extensions/shell/browser/shell_native_app_window.h b/extensions/shell/browser/shell_native_app_window.h index f3ff7be..389d082a 100644 --- a/extensions/shell/browser/shell_native_app_window.h +++ b/extensions/shell/browser/shell_native_app_window.h
@@ -68,6 +68,7 @@ const gfx::Size& max_size) override; void SetVisibleOnAllWorkspaces(bool always_visible) override; bool CanHaveAlphaEnabled() const override; + void SetActivateOnPointer(bool activate_on_pointer) override; private: AppWindow* app_window_;
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index b4fa9fc..aeaf971 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc
@@ -2455,6 +2455,21 @@ error_state, function_name, args.target, "target"); return false; } + if (feature_info_->IsWebGL1OrES2Context()) { + switch (args.format) { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL: + if (args.target != GL_TEXTURE_2D) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "invalid target for depth/stencil textures"); + return false; + } + break; + default: + break; + } + } if (!ValidateTextureParameters( error_state, function_name, true, args.format, args.type, args.internal_format, args.level)) {
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn index 0de74588..950d2be 100644 --- a/ios/chrome/browser/ui/authentication/BUILD.gn +++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -136,6 +136,7 @@ ] deps = [ "//base", + "//components/signin/core/browser", "//ios/chrome/app/strings", "//ios/chrome/browser/ui", "//ios/chrome/browser/ui/collection_view/cells",
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view.h b/ios/chrome/browser/ui/authentication/signin_promo_view.h index 1935e8a..cd08711 100644 --- a/ios/chrome/browser/ui/authentication/signin_promo_view.h +++ b/ios/chrome/browser/ui/authentication/signin_promo_view.h
@@ -7,6 +7,8 @@ #import <UIKit/UIKit.h> +#include "components/signin/core/browser/signin_metrics.h" + @class MDCFlatButton; typedef NS_ENUM(NSInteger, SigninPromoViewMode) { @@ -36,9 +38,6 @@ @property(nonatomic, readonly) UILabel* textLabel; @property(nonatomic, readonly) MDCFlatButton* primaryButton; @property(nonatomic, readonly) MDCFlatButton* secondaryButton; -// If set to YES, ShowSigninCommand is sent when primary or secondary buttons -// are tapped. -@property(nonatomic, getter=doesSendChromeCommand) BOOL sendChromeCommand; // Horizontal padding used for |textLabel|, |primaryButton| and // |secondaryButton|. Used to compute the preferred max layout width of @@ -52,6 +51,13 @@ // cropped first). Must only be called in the "Warm State" mode. - (void)setProfileImage:(UIImage*)image; +// Enables SigninPromoView to send ShowSigninCommand when primary or secondary +// buttons are tapped, and sets the metric access point. By default, command is +// disabled. +// This method should be called only once. +- (void)enableChromeCommandWithAccessPoint: + (signin_metrics::AccessPoint)accessPoint; + @end #endif // IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGN_PROMO_VIEW_H_
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view.mm b/ios/chrome/browser/ui/authentication/signin_promo_view.mm index bfa3bfa..3e38e1fd 100644 --- a/ios/chrome/browser/ui/authentication/signin_promo_view.mm +++ b/ios/chrome/browser/ui/authentication/signin_promo_view.mm
@@ -5,6 +5,8 @@ #import "ios/chrome/browser/ui/authentication/signin_promo_view.h" #include "base/logging.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" #import "ios/chrome/browser/ui/commands/show_signin_command.h" @@ -34,6 +36,8 @@ @implementation SigninPromoView { NSArray<NSLayoutConstraint*>* _coldStateConstraints; NSArray<NSLayoutConstraint*>* _warmStateConstraints; + BOOL _shouldSendChromeCommand; + signin_metrics::AccessPoint _accessPoint; } @synthesize mode = _mode; @@ -41,12 +45,12 @@ @synthesize textLabel = _textLabel; @synthesize primaryButton = _primaryButton; @synthesize secondaryButton = _secondaryButton; -@synthesize sendChromeCommand = _sendChromeCommand; - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.isAccessibilityElement = YES; + _accessPoint = signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN; // Adding subviews. self.clipsToBounds = YES; @@ -205,23 +209,29 @@ return kHorizontalPadding; } +- (void)enableChromeCommandWithAccessPoint: + (signin_metrics::AccessPoint)accessPoint { + DCHECK(!_shouldSendChromeCommand); + _shouldSendChromeCommand = YES; + _accessPoint = accessPoint; +} + - (void)onPrimaryButtonAction:(id)unused { - if (!_sendChromeCommand) { + if (!_shouldSendChromeCommand) { return; } + [self recordSigninUserActionForAccessPoint]; ShowSigninCommand* command = nil; switch (_mode) { case SigninPromoViewModeColdState: command = [[ShowSigninCommand alloc] initWithOperation:AUTHENTICATION_OPERATION_SIGNIN - accessPoint:signin_metrics::AccessPoint:: - ACCESS_POINT_RECENT_TABS]; + accessPoint:_accessPoint]; break; case SigninPromoViewModeWarmState: command = [[ShowSigninCommand alloc] initWithOperation:AUTHENTICATION_OPERATION_SIGNIN_PROMO_CONTINUE_AS - accessPoint:signin_metrics::AccessPoint:: - ACCESS_POINT_RECENT_TABS]; + accessPoint:_accessPoint]; break; } DCHECK(command); @@ -229,15 +239,32 @@ } - (void)onSecondaryButtonAction:(id)unused { - if (!_sendChromeCommand) { + if (!_shouldSendChromeCommand) { return; } + [self recordSigninUserActionForAccessPoint]; ShowSigninCommand* command = [[ShowSigninCommand alloc] initWithOperation:AUTHENTICATION_OPERATION_SIGNIN - accessPoint:signin_metrics::AccessPoint::ACCESS_POINT_RECENT_TABS]; + accessPoint:_accessPoint]; [self chromeExecuteCommand:command]; } +- (void)recordSigninUserActionForAccessPoint { + switch (_accessPoint) { + case signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER: + base::RecordAction( + base::UserMetricsAction("Signin_Signin_FromBookmarkManager")); + break; + case signin_metrics::AccessPoint::ACCESS_POINT_RECENT_TABS: + base::RecordAction( + base::UserMetricsAction("Signin_Signin_FromRecentTabs")); + break; + default: + NOTREACHED() << "Unexpected value for access point " << (int)_accessPoint; + break; + } +} + #pragma mark - NSObject(Accessibility) - (NSArray<UIAccessibilityCustomAction*>*)accessibilityCustomActions {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_collection_view.mm b/ios/chrome/browser/ui/bookmarks/bookmark_folder_collection_view.mm index 40d298ac..29fe56a 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_collection_view.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_collection_view.mm
@@ -411,7 +411,9 @@ dequeueReusableCellWithReuseIdentifier:[BookmarkSigninPromoCell reuseIdentifier] forIndexPath:indexPath]; - signinPromoCell.signinPromoView.sendChromeCommand = YES; + [signinPromoCell.signinPromoView + enableChromeCommandWithAccessPoint:signin_metrics::AccessPoint:: + ACCESS_POINT_BOOKMARK_MANAGER]; [[_signinPromoViewMediator createConfigurator] configureSigninPromoView:signinPromoCell.signinPromoView]; __weak BookmarkFolderCollectionView* weakSelf = self;
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm index 185abc0d..846b29fc3 100644 --- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm +++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -828,7 +828,9 @@ contentViewTopMargin = kSigninPromoViewTopMargin; SigninPromoView* signinPromoView = [[SigninPromoView alloc] initWithFrame:CGRectZero]; - signinPromoView.sendChromeCommand = YES; + [signinPromoView + enableChromeCommandWithAccessPoint:signin_metrics::AccessPoint:: + ACCESS_POINT_RECENT_TABS]; signinPromoView.textLabel.text = l10n_util::GetNSString(IDS_IOS_SIGNIN_PROMO_RECENT_TABS); signinPromoView.textLabel.preferredMaxLayoutWidth =
diff --git a/ios/web/web_state/navigation_context_impl.h b/ios/web/web_state/navigation_context_impl.h index 5756cedf..de9a9a7 100644 --- a/ios/web/web_state/navigation_context_impl.h +++ b/ios/web/web_state/navigation_context_impl.h
@@ -18,6 +18,12 @@ class NavigationContextImpl : public NavigationContext { public: // Creates navigation context for sucessful navigation to a different page. + // Response headers will ne null. + static std::unique_ptr<NavigationContextImpl> CreateNavigationContext( + WebState* web_state, + const GURL& url); + + // Creates navigation context for sucessful navigation to a different page. static std::unique_ptr<NavigationContextImpl> CreateNavigationContext( WebState* web_state, const GURL& url, @@ -47,6 +53,12 @@ net::HttpResponseHeaders* GetResponseHeaders() const override; ~NavigationContextImpl() override; + // Setters for navigation context data members. + void SetIsSameDocument(bool is_same_document); + void SetIsErrorPage(bool is_error_page); + void SetResponseHeaders( + const scoped_refptr<net::HttpResponseHeaders>& response_headers); + private: NavigationContextImpl( WebState* web_state,
diff --git a/ios/web/web_state/navigation_context_impl.mm b/ios/web/web_state/navigation_context_impl.mm index 4d6406f..39df2fa 100644 --- a/ios/web/web_state/navigation_context_impl.mm +++ b/ios/web/web_state/navigation_context_impl.mm
@@ -13,6 +13,16 @@ // static std::unique_ptr<NavigationContextImpl> +NavigationContextImpl::CreateNavigationContext(WebState* web_state, + const GURL& url) { + std::unique_ptr<NavigationContextImpl> result(new NavigationContextImpl( + web_state, url, false /* is_same_document */, false /* is_error_page */, + nullptr /* response_headers */)); + return result; +} + +// static +std::unique_ptr<NavigationContextImpl> NavigationContextImpl::CreateNavigationContext( WebState* web_state, const GURL& url, @@ -76,6 +86,19 @@ return response_headers_.get(); } +void NavigationContextImpl::SetIsSameDocument(bool is_same_document) { + is_same_document_ = is_same_document; +} + +void NavigationContextImpl::SetIsErrorPage(bool is_error_page) { + is_error_page_ = is_error_page; +} + +void NavigationContextImpl::SetResponseHeaders( + const scoped_refptr<net::HttpResponseHeaders>& response_headers) { + response_headers_ = response_headers; +} + NavigationContextImpl::NavigationContextImpl( WebState* web_state, const GURL& url,
diff --git a/ios/web/web_state/navigation_context_impl_unittest.mm b/ios/web/web_state/navigation_context_impl_unittest.mm index 65af1d16..9ffedf9a 100644 --- a/ios/web/web_state/navigation_context_impl_unittest.mm +++ b/ios/web/web_state/navigation_context_impl_unittest.mm
@@ -30,8 +30,8 @@ scoped_refptr<net::HttpResponseHeaders> response_headers_; }; -// Tests CreateNavigationContext factory method. -TEST_F(NavigationContextImplTest, NavigationContext) { +// Tests legacy CreateNavigationContext factory method. +TEST_F(NavigationContextImplTest, LegacyNavigationContext) { std::unique_ptr<NavigationContext> context = NavigationContextImpl::CreateNavigationContext(&web_state_, url_, response_headers_); @@ -44,6 +44,19 @@ EXPECT_EQ(response_headers_.get(), context->GetResponseHeaders()); } +// Tests CreateNavigationContext factory method. +TEST_F(NavigationContextImplTest, NavigationContext) { + std::unique_ptr<NavigationContext> context = + NavigationContextImpl::CreateNavigationContext(&web_state_, url_); + ASSERT_TRUE(context); + + EXPECT_EQ(&web_state_, context->GetWebState()); + EXPECT_EQ(url_, context->GetUrl()); + EXPECT_FALSE(context->IsSameDocument()); + EXPECT_FALSE(context->IsErrorPage()); + EXPECT_FALSE(context->GetResponseHeaders()); +} + // Tests CreateSameDocumentNavigationContext factory method. TEST_F(NavigationContextImplTest, SameDocumentNavigationContext) { std::unique_ptr<NavigationContext> context = @@ -72,4 +85,33 @@ EXPECT_EQ(response_headers_.get(), context->GetResponseHeaders()); } +// Tests NavigationContextImpl Setters. +TEST_F(NavigationContextImplTest, Setters) { + std::unique_ptr<NavigationContextImpl> context = + NavigationContextImpl::CreateNavigationContext(&web_state_, url_); + ASSERT_TRUE(context); + + ASSERT_FALSE(context->IsSameDocument()); + ASSERT_FALSE(context->IsErrorPage()); + ASSERT_NE(response_headers_.get(), context->GetResponseHeaders()); + + // SetSameDocument + context->SetIsSameDocument(true); + EXPECT_TRUE(context->IsSameDocument()); + EXPECT_FALSE(context->IsErrorPage()); + EXPECT_NE(response_headers_.get(), context->GetResponseHeaders()); + + // SetErrorPage + context->SetIsErrorPage(true); + EXPECT_TRUE(context->IsSameDocument()); + EXPECT_TRUE(context->IsErrorPage()); + EXPECT_NE(response_headers_.get(), context->GetResponseHeaders()); + + // SetResponseHeaders + context->SetResponseHeaders(response_headers_); + EXPECT_TRUE(context->IsSameDocument()); + EXPECT_TRUE(context->IsErrorPage()); + EXPECT_EQ(response_headers_.get(), context->GetResponseHeaders()); +} + } // namespace web
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index b6de64a2..8fcd483 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -222,6 +222,11 @@ const base::Feature kExternalClearKeyForTesting{ "external-clear-key-for-testing", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables Media Engagement Index recording in order to bypass autoplay +// policies. +const base::Feature kMediaEngagement{"media-engagement", + base::FEATURE_DISABLED_BY_DEFAULT}; + #if defined(OS_ANDROID) // Lock the screen orientation when a video goes fullscreen. const base::Feature kVideoFullscreenOrientationLock{
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index fbb8454..0d20303 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -107,6 +107,7 @@ MEDIA_EXPORT extern const base::Feature kUseNewMediaCache; MEDIA_EXPORT extern const base::Feature kVideoBlitColorAccuracy; MEDIA_EXPORT extern const base::Feature kVideoColorManagement; +MEDIA_EXPORT extern const base::Feature kMediaEngagement; #if defined(OS_ANDROID) MEDIA_EXPORT extern const base::Feature kAndroidMediaPlayerRenderer;
diff --git a/media/renderers/skcanvas_video_renderer.cc b/media/renderers/skcanvas_video_renderer.cc index 3c7cfb9..f8e8faa 100644 --- a/media/renderers/skcanvas_video_renderer.cc +++ b/media/renderers/skcanvas_video_renderer.cc
@@ -432,7 +432,7 @@ // sw image into the SkPicture. The long term solution is for Skia to provide // a SkPicture filter that makes a picture safe for multiple CPU raster // threads. (skbug.com/4321). - sk_sp<const SkImage> image; + sk_sp<SkImage> image; if (canvas->imageInfo().colorType() == kUnknown_SkColorType) image = last_image_->makeNonTextureImage(); else
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.cc b/net/quic/chromium/bidirectional_stream_quic_impl.cc index 6309e84..1afd2b60 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl.cc +++ b/net/quic/chromium/bidirectional_stream_quic_impl.cc
@@ -340,7 +340,7 @@ closed_stream_received_bytes_ = stream_->stream_bytes_read(); closed_stream_sent_bytes_ = stream_->stream_bytes_written(); closed_is_first_stream_ = stream_->IsFirstStream(); - stream_->SetDelegate(nullptr); + stream_->ClearDelegate(); stream_ = nullptr; }
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.h b/net/quic/chromium/bidirectional_stream_quic_impl.h index e9f58509..e8f5cfe 100644 --- a/net/quic/chromium/bidirectional_stream_quic_impl.h +++ b/net/quic/chromium/bidirectional_stream_quic_impl.h
@@ -78,7 +78,7 @@ void ResetStream(); const std::unique_ptr<QuicChromiumClientSession::Handle> session_; - QuicChromiumClientStream* stream_; // Non-owning. + std::unique_ptr<QuicChromiumClientStream::Handle> stream_; const BidirectionalStreamRequestInfo* request_info_; BidirectionalStreamImpl::Delegate* delegate_;
diff --git a/net/quic/chromium/quic_chromium_client_session.cc b/net/quic/chromium/quic_chromium_client_session.cc index 6d46a32..4c70e14 100644 --- a/net/quic/chromium/quic_chromium_client_session.cc +++ b/net/quic/chromium/quic_chromium_client_session.cc
@@ -301,13 +301,14 @@ return stream_request_->StartRequest(callback); } -QuicChromiumClientStream* QuicChromiumClientSession::Handle::ReleaseStream( +std::unique_ptr<QuicChromiumClientStream::Handle> +QuicChromiumClientSession::Handle::ReleaseStream( QuicChromiumClientStream::Delegate* delegate) { DCHECK(stream_request_); - auto* stream = stream_request_->ReleaseStream(delegate); + auto handle = stream_request_->ReleaseStream(delegate); stream_request_.reset(); - return stream; + return handle; } int QuicChromiumClientSession::Handle::WaitForHandshakeConfirmation( @@ -376,14 +377,13 @@ return rv; } -QuicChromiumClientStream* +std::unique_ptr<QuicChromiumClientStream::Handle> QuicChromiumClientSession::StreamRequest::ReleaseStream( QuicChromiumClientStream::Delegate* delegate) { DCHECK(stream_); QuicChromiumClientStream* stream = stream_; stream_ = nullptr; - stream->SetDelegate(delegate); - return stream; + return stream->CreateHandle(delegate); } void QuicChromiumClientSession::StreamRequest::OnRequestCompleteSuccess(
diff --git a/net/quic/chromium/quic_chromium_client_session.h b/net/quic/chromium/quic_chromium_client_session.h index 35a05fa..93f26b09 100644 --- a/net/quic/chromium/quic_chromium_client_session.h +++ b/net/quic/chromium/quic_chromium_client_session.h
@@ -90,8 +90,8 @@ int RequestStream(bool requires_confirmation, const CompletionCallback& callback); - // Releases |stream_| to the caller and sets |delegate| on it. - QuicChromiumClientStream* ReleaseStream( + // Releases |stream_| to the caller and sets |delegate| on the handle. + std::unique_ptr<QuicChromiumClientStream::Handle> ReleaseStream( QuicChromiumClientStream::Delegate* delegate); // Sends Rst for the stream, and makes sure that future calls to @@ -194,7 +194,7 @@ int StartRequest(const CompletionCallback& callback); // Releases |stream_| to the caller and sets |delegate| on it. - QuicChromiumClientStream* ReleaseStream( + std::unique_ptr<QuicChromiumClientStream::Handle> ReleaseStream( QuicChromiumClientStream::Delegate* delegate); private:
diff --git a/net/quic/chromium/quic_chromium_client_stream.cc b/net/quic/chromium/quic_chromium_client_stream.cc index 15f46431..5eb505a3 100644 --- a/net/quic/chromium/quic_chromium_client_stream.cc +++ b/net/quic/chromium/quic_chromium_client_stream.cc
@@ -21,13 +21,226 @@ namespace net { +QuicChromiumClientStream::Handle::Handle(QuicChromiumClientStream* stream, + Delegate* delegate) + : stream_(stream), delegate_(delegate) { + SaveState(); +} + +QuicChromiumClientStream::Handle::~Handle() { + if (stream_) { + stream_->ClearHandle(); + // TODO(rch): If stream_ is still valid, it should probably be Reset() + // so that it does not leak. + // stream_->Reset(QUIC_STREAM_CANCELLED); + } +} + +void QuicChromiumClientStream::Handle::ClearDelegate() { + delegate_ = nullptr; +} + +void QuicChromiumClientStream::Handle::OnInitialHeadersAvailable( + const SpdyHeaderBlock& headers, + size_t frame_len) { + delegate_->OnInitialHeadersAvailable(headers, frame_len); +} + +void QuicChromiumClientStream::Handle::OnTrailingHeadersAvailable( + const SpdyHeaderBlock& headers, + size_t frame_len) { + delegate_->OnTrailingHeadersAvailable(headers, frame_len); +} + +void QuicChromiumClientStream::Handle::OnDataAvailable() { + delegate_->OnDataAvailable(); +} + +void QuicChromiumClientStream::Handle::OnClose() { + if (stream_) + SaveState(); + stream_ = nullptr; + if (delegate_) { + auto* delegate = delegate_; + delegate_ = nullptr; + delegate->OnClose(); + } +} + +void QuicChromiumClientStream::Handle::OnError(int error) { + if (stream_) + SaveState(); + stream_ = nullptr; + if (delegate_) { + auto* delegate = delegate_; + delegate_ = nullptr; + delegate->OnError(error); + } +} + +size_t QuicChromiumClientStream::Handle::WriteHeaders( + SpdyHeaderBlock header_block, + bool fin, + QuicReferenceCountedPointer<QuicAckListenerInterface> + ack_notifier_delegate) { + if (!stream_) + return 0; + return stream_->WriteHeaders(std::move(header_block), fin, + ack_notifier_delegate); +} + +int QuicChromiumClientStream::Handle::WriteStreamData( + base::StringPiece data, + bool fin, + const CompletionCallback& callback) { + if (!stream_) + return ERR_CONNECTION_CLOSED; + return stream_->WriteStreamData(data, fin, callback); +} + +int QuicChromiumClientStream::Handle::WritevStreamData( + const std::vector<scoped_refptr<IOBuffer>>& buffers, + const std::vector<int>& lengths, + bool fin, + const CompletionCallback& callback) { + if (!stream_) + return ERR_CONNECTION_CLOSED; + return stream_->WritevStreamData(buffers, lengths, fin, callback); +} + +int QuicChromiumClientStream::Handle::Read(IOBuffer* buf, int buf_len) { + if (!stream_) + return ERR_CONNECTION_CLOSED; + return stream_->Read(buf, buf_len); +} + +void QuicChromiumClientStream::Handle::OnFinRead() { + if (stream_) + stream_->OnFinRead(); +} + +void QuicChromiumClientStream::Handle::DisableConnectionMigration() { + if (stream_) + stream_->DisableConnectionMigration(); +} + +void QuicChromiumClientStream::Handle::SetPriority(SpdyPriority priority) { + if (stream_) + stream_->SetPriority(priority); +} + +void QuicChromiumClientStream::Handle::Reset( + QuicRstStreamErrorCode error_code) { + if (stream_) + stream_->Reset(error_code); +} + +QuicStreamId QuicChromiumClientStream::Handle::id() const { + if (!stream_) + return id_; + return stream_->id(); +} + +QuicErrorCode QuicChromiumClientStream::Handle::connection_error() const { + if (!stream_) + return connection_error_; + return stream_->connection_error(); +} + +QuicRstStreamErrorCode QuicChromiumClientStream::Handle::stream_error() const { + if (!stream_) + return stream_error_; + return stream_->stream_error(); +} + +bool QuicChromiumClientStream::Handle::fin_sent() const { + if (!stream_) + return fin_sent_; + return stream_->fin_sent(); +} + +bool QuicChromiumClientStream::Handle::fin_received() const { + if (!stream_) + return fin_received_; + return stream_->fin_received(); +} + +uint64_t QuicChromiumClientStream::Handle::stream_bytes_read() const { + if (!stream_) + return stream_bytes_read_; + return stream_->stream_bytes_read(); +} + +uint64_t QuicChromiumClientStream::Handle::stream_bytes_written() const { + if (!stream_) + return stream_bytes_written_; + return stream_->stream_bytes_written(); +} + +size_t QuicChromiumClientStream::Handle::NumBytesConsumed() const { + if (!stream_) + return num_bytes_consumed_; + return stream_->sequencer()->NumBytesConsumed(); +} + +bool QuicChromiumClientStream::Handle::IsDoneReading() const { + if (!stream_) + return is_done_reading_; + return stream_->IsDoneReading(); +} + +bool QuicChromiumClientStream::Handle::IsFirstStream() const { + if (!stream_) + return is_first_stream_; + return stream_->IsFirstStream(); +} + +void QuicChromiumClientStream::Handle::OnPromiseHeaderList( + QuicStreamId promised_id, + size_t frame_len, + const QuicHeaderList& header_list) { + stream_->OnPromiseHeaderList(promised_id, frame_len, header_list); +} + +SpdyPriority QuicChromiumClientStream::Handle::priority() const { + if (!stream_) + return priority_; + return stream_->priority(); +} + +bool QuicChromiumClientStream::Handle::can_migrate() { + if (!stream_) + return false; + return stream_->can_migrate(); +} + +QuicChromiumClientStream::Delegate* +QuicChromiumClientStream::Handle::GetDelegate() { + return delegate_; +} + +void QuicChromiumClientStream::Handle::SaveState() { + DCHECK(stream_); + fin_sent_ = stream_->fin_sent(); + fin_received_ = stream_->fin_received(); + num_bytes_consumed_ = stream_->sequencer()->NumBytesConsumed(); + id_ = stream_->id(); + connection_error_ = stream_->connection_error(); + stream_error_ = stream_->stream_error(); + is_done_reading_ = stream_->IsDoneReading(); + is_first_stream_ = stream_->IsFirstStream(); + stream_bytes_read_ = stream_->stream_bytes_read(); + stream_bytes_written_ = stream_->stream_bytes_written(); + priority_ = stream_->priority(); +} + QuicChromiumClientStream::QuicChromiumClientStream( QuicStreamId id, QuicClientSessionBase* session, const NetLogWithSource& net_log) : QuicSpdyStream(id, session), net_log_(net_log), - delegate_(nullptr), + handle_(nullptr), headers_delivered_(false), initial_headers_sent_(false), session_(session), @@ -36,8 +249,8 @@ weak_factory_(this) {} QuicChromiumClientStream::~QuicChromiumClientStream() { - if (delegate_) - delegate_->OnClose(); + if (handle_) + handle_->OnClose(); } void QuicChromiumClientStream::OnInitialHeadersComplete( @@ -58,14 +271,14 @@ ConsumeHeaderList(); session_->OnInitialHeadersComplete(id(), header_block); - if (delegate_) { - // The delegate will receive the headers via a posted task. - NotifyDelegateOfInitialHeadersAvailableLater(std::move(header_block), - frame_len); + if (handle_) { + // The handle will receive the headers via a posted task. + NotifyHandleOfInitialHeadersAvailableLater(std::move(header_block), + frame_len); return; } - // Buffer the headers and deliver them when the delegate arrives. + // Buffer the headers and deliver them when the handle arrives. initial_headers_ = std::move(header_block); initial_headers_frame_len_ = frame_len; } @@ -75,8 +288,8 @@ size_t frame_len, const QuicHeaderList& header_list) { QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len, header_list); - NotifyDelegateOfTrailingHeadersAvailableLater(received_trailers().Clone(), - frame_len); + NotifyHandleOfTrailingHeadersAvailableLater(received_trailers().Clone(), + frame_len); } void QuicChromiumClientStream::OnPromiseHeaderList( @@ -109,16 +322,16 @@ return; } - // The delegate will read the data via a posted task, and + // The handle will read the data via a posted task, and // will be able to, potentially, read all data which has queued up. - if (delegate_) - NotifyDelegateOfDataAvailableLater(); + if (handle_) + NotifyHandleOfDataAvailableLater(); } void QuicChromiumClientStream::OnClose() { - if (delegate_) { - delegate_->OnClose(); - delegate_ = nullptr; + if (handle_) { + handle_->OnClose(); + handle_ = nullptr; } QuicStream::OnClose(); } @@ -192,25 +405,32 @@ return ERR_IO_PENDING; } -void QuicChromiumClientStream::SetDelegate( +std::unique_ptr<QuicChromiumClientStream::Handle> +QuicChromiumClientStream::CreateHandle( QuicChromiumClientStream::Delegate* delegate) { - DCHECK(!(delegate_ && delegate)); - delegate_ = delegate; - if (delegate == nullptr) - return; + DCHECK(!handle_); + auto handle = std::unique_ptr<QuicChromiumClientStream::Handle>( + new QuicChromiumClientStream::Handle(this, delegate)); + handle_ = handle.get(); // Should this perhaps be via PostTask to make reasoning simpler? if (!initial_headers_.empty()) { - delegate_->OnInitialHeadersAvailable(std::move(initial_headers_), - initial_headers_frame_len_); + handle_->OnInitialHeadersAvailable(std::move(initial_headers_), + initial_headers_frame_len_); } + + return handle; +} + +void QuicChromiumClientStream::ClearHandle() { + handle_ = nullptr; } void QuicChromiumClientStream::OnError(int error) { - if (delegate_) { - QuicChromiumClientStream::Delegate* delegate = delegate_; - delegate_ = nullptr; - delegate->OnError(error); + if (handle_) { + QuicChromiumClientStream::Handle* handle = handle_; + handle_ = nullptr; + handle->OnError(error); } } @@ -230,22 +450,22 @@ return bytes_read; } -void QuicChromiumClientStream::NotifyDelegateOfInitialHeadersAvailableLater( +void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailableLater( SpdyHeaderBlock headers, size_t frame_len) { - DCHECK(delegate_); + DCHECK(handle_); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind( - &QuicChromiumClientStream::NotifyDelegateOfInitialHeadersAvailable, + &QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable, weak_factory_.GetWeakPtr(), base::Passed(std::move(headers)), frame_len)); } -void QuicChromiumClientStream::NotifyDelegateOfInitialHeadersAvailable( +void QuicChromiumClientStream::NotifyHandleOfInitialHeadersAvailable( SpdyHeaderBlock headers, size_t frame_len) { - if (!delegate_) + if (!handle_) return; DCHECK(!headers_delivered_); @@ -254,50 +474,50 @@ NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_HEADERS, base::Bind(&SpdyHeaderBlockNetLogCallback, &headers)); - delegate_->OnInitialHeadersAvailable(headers, frame_len); + handle_->OnInitialHeadersAvailable(headers, frame_len); } -void QuicChromiumClientStream::NotifyDelegateOfTrailingHeadersAvailableLater( +void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailableLater( SpdyHeaderBlock headers, size_t frame_len) { - DCHECK(delegate_); + DCHECK(handle_); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind( - &QuicChromiumClientStream::NotifyDelegateOfTrailingHeadersAvailable, + &QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable, weak_factory_.GetWeakPtr(), base::Passed(std::move(headers)), frame_len)); } -void QuicChromiumClientStream::NotifyDelegateOfTrailingHeadersAvailable( +void QuicChromiumClientStream::NotifyHandleOfTrailingHeadersAvailable( SpdyHeaderBlock headers, size_t frame_len) { - if (!delegate_) + if (!handle_) return; DCHECK(headers_delivered_); // Only mark trailers consumed when we are about to notify delegate. MarkTrailersConsumed(); // Post an async task to notify delegate of the FIN flag. - NotifyDelegateOfDataAvailableLater(); + NotifyHandleOfDataAvailableLater(); net_log_.AddEvent( NetLogEventType::QUIC_CHROMIUM_CLIENT_STREAM_READ_RESPONSE_TRAILERS, base::Bind(&SpdyHeaderBlockNetLogCallback, &headers)); - delegate_->OnTrailingHeadersAvailable(headers, frame_len); + handle_->OnTrailingHeadersAvailable(headers, frame_len); } -void QuicChromiumClientStream::NotifyDelegateOfDataAvailableLater() { - DCHECK(delegate_); +void QuicChromiumClientStream::NotifyHandleOfDataAvailableLater() { + DCHECK(handle_); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, - base::Bind(&QuicChromiumClientStream::NotifyDelegateOfDataAvailable, + base::Bind(&QuicChromiumClientStream::NotifyHandleOfDataAvailable, weak_factory_.GetWeakPtr())); } -void QuicChromiumClientStream::NotifyDelegateOfDataAvailable() { - if (delegate_) - delegate_->OnDataAvailable(); +void QuicChromiumClientStream::NotifyHandleOfDataAvailable() { + if (handle_) + handle_->OnDataAvailable(); } void QuicChromiumClientStream::DisableConnectionMigration() {
diff --git a/net/quic/chromium/quic_chromium_client_stream.h b/net/quic/chromium/quic_chromium_client_stream.h index d65f2e5..e8d05e9 100644 --- a/net/quic/chromium/quic_chromium_client_stream.h +++ b/net/quic/chromium/quic_chromium_client_stream.h
@@ -32,6 +32,8 @@ // are owned by the QuicClientSession which created them. class NET_EXPORT_PRIVATE QuicChromiumClientStream : public QuicSpdyStream { public: + // TODO(rch): Remove this class completely in favor of async methods + // on the Handle. // Delegate handles protocol specific behavior of a quic stream. class NET_EXPORT_PRIVATE Delegate { public: @@ -61,6 +63,114 @@ DISALLOW_COPY_AND_ASSIGN(Delegate); }; + // Wrapper for interacting with the session in a restricted fashion. + class NET_EXPORT_PRIVATE Handle { + public: + ~Handle(); + + // Returns true if the stream is still connected. + bool IsOpen() { return stream_ != nullptr; } + + // Writes |header_block| to the peer. Closes the write side if |fin| is + // true. If non-null, |ack_notifier_delegate| will be notified when the + // headers are ACK'd by the peer. + size_t WriteHeaders(SpdyHeaderBlock header_block, + bool fin, + QuicReferenceCountedPointer<QuicAckListenerInterface> + ack_notifier_delegate); + + // Writes |data| to the peer. Closes the write side if |fin| is true. + // If the data could not be written immediately, returns ERR_IO_PENDING + // and invokes |callback| asynchronously when the write completes. + int WriteStreamData(base::StringPiece data, + bool fin, + const CompletionCallback& callback); + + // Same as WriteStreamData except it writes data from a vector of IOBuffers, + // with the length of each buffer at the corresponding index in |lengths|. + int WritevStreamData(const std::vector<scoped_refptr<IOBuffer>>& buffers, + const std::vector<int>& lengths, + bool fin, + const CompletionCallback& callback); + + // Reads at most |buf_len| bytes into |buf|. Returns the number of bytes + // read. + int Read(IOBuffer* buf, int buf_len); + + // Called to notify the stream when the final incoming data is read. + void OnFinRead(); + + // Prevents the connection from migrating to a new network while this + // stream is open. + void DisableConnectionMigration(); + + // Sets the priority of the stream to |priority|. + void SetPriority(SpdyPriority priority); + + // Sends a RST_STREAM frame to the peer and closes the streams. + void Reset(QuicRstStreamErrorCode error_code); + + // Clears |delegate_| from this Handle, but does not disconnect the Handle + // from |stream_|. + void ClearDelegate(); + + QuicStreamId id() const; + QuicErrorCode connection_error() const; + QuicRstStreamErrorCode stream_error() const; + bool fin_sent() const; + bool fin_received() const; + uint64_t stream_bytes_read() const; + uint64_t stream_bytes_written() const; + size_t NumBytesConsumed() const; + bool IsDoneReading() const; + bool IsFirstStream() const; + + // TODO(rch): Move these test-only methods to a peer, or else remove. + void OnPromiseHeaderList(QuicStreamId promised_id, + size_t frame_len, + const QuicHeaderList& header_list); + SpdyPriority priority() const; + bool can_migrate(); + + Delegate* GetDelegate(); + + private: + friend class QuicChromiumClientStream; + + // Constucts a new Handle for |stream| with |delegate| set to receive + // up calls on various events. + Handle(QuicChromiumClientStream* stream, Delegate* delegate); + + // Methods invoked by the stream. + void OnInitialHeadersAvailable(const SpdyHeaderBlock& headers, + size_t frame_len); + void OnTrailingHeadersAvailable(const SpdyHeaderBlock& headers, + size_t frame_len); + void OnDataAvailable(); + void OnClose(); + void OnError(int error); + + // Saves various fields from the stream before the stream goes away. + void SaveState(); + + QuicChromiumClientStream* stream_; // Unowned. + Delegate* delegate_; // Owns this. + + QuicStreamId id_; + QuicErrorCode connection_error_; + QuicRstStreamErrorCode stream_error_; + bool fin_sent_; + bool fin_received_; + uint64_t stream_bytes_read_; + uint64_t stream_bytes_written_; + bool is_done_reading_; + bool is_first_stream_; + size_t num_bytes_consumed_; + SpdyPriority priority_; + + DISALLOW_COPY_AND_ASSIGN(Handle); + }; + QuicChromiumClientStream(QuicStreamId id, QuicClientSessionBase* session, const NetLogWithSource& net_log); @@ -99,11 +209,15 @@ const std::vector<int>& lengths, bool fin, const CompletionCallback& callback); - // Set new |delegate|. |delegate| must not be NULL. - // If this stream has already received data, OnDataReceived() will be - // called on the delegate. - void SetDelegate(Delegate* delegate); - Delegate* GetDelegate() { return delegate_; } + + // Creates a new Handle for this stream and sets |delegate| on the handle. + // Must only be called once. + std::unique_ptr<QuicChromiumClientStream::Handle> CreateHandle( + QuicChromiumClientStream::Delegate* delegate); + + // Clears |handle_| from this stream. + void ClearHandle(); + void OnError(int error); // Reads at most |buf_len| bytes into |buf|. Returns the number of bytes read. @@ -124,19 +238,19 @@ using QuicStream::sequencer; private: - void NotifyDelegateOfInitialHeadersAvailableLater(SpdyHeaderBlock headers, - size_t frame_len); - void NotifyDelegateOfInitialHeadersAvailable(SpdyHeaderBlock headers, - size_t frame_len); - void NotifyDelegateOfTrailingHeadersAvailableLater(SpdyHeaderBlock headers, - size_t frame_len); - void NotifyDelegateOfTrailingHeadersAvailable(SpdyHeaderBlock headers, - size_t frame_len); - void NotifyDelegateOfDataAvailableLater(); - void NotifyDelegateOfDataAvailable(); + void NotifyHandleOfInitialHeadersAvailableLater(SpdyHeaderBlock headers, + size_t frame_len); + void NotifyHandleOfInitialHeadersAvailable(SpdyHeaderBlock headers, + size_t frame_len); + void NotifyHandleOfTrailingHeadersAvailableLater(SpdyHeaderBlock headers, + size_t frame_len); + void NotifyHandleOfTrailingHeadersAvailable(SpdyHeaderBlock headers, + size_t frame_len); + void NotifyHandleOfDataAvailableLater(); + void NotifyHandleOfDataAvailable(); NetLogWithSource net_log_; - Delegate* delegate_; + Handle* handle_; bool headers_delivered_;
diff --git a/net/quic/chromium/quic_chromium_client_stream_test.cc b/net/quic/chromium/quic_chromium_client_stream_test.cc index 4efac81..0a3888a 100644 --- a/net/quic/chromium/quic_chromium_client_stream_test.cc +++ b/net/quic/chromium/quic_chromium_client_stream_test.cc
@@ -206,7 +206,7 @@ stream_ = new QuicChromiumClientStream(kTestStreamId, &session_, NetLogWithSource()); session_.ActivateStream(base::WrapUnique(stream_)); - stream_->SetDelegate(&delegate_); + handle_ = stream_->CreateHandle(&delegate_); } void InitializeHeaders() { @@ -278,8 +278,10 @@ } QuicCryptoClientConfig crypto_config_; - testing::StrictMock<MockDelegate> delegate2_; + std::unique_ptr<QuicChromiumClientStream::Handle> handle_; testing::StrictMock<MockDelegate> delegate_; + std::unique_ptr<QuicChromiumClientStream::Handle> handle2_; + testing::StrictMock<MockDelegate> delegate2_; MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; MockQuicClientSessionBase session_; @@ -292,6 +294,105 @@ QuicChromiumClientStreamTest, ::testing::ValuesIn(AllSupportedVersions())); +TEST_P(QuicChromiumClientStreamTest, Handle) { + EXPECT_TRUE(handle_->IsOpen()); + EXPECT_EQ(kTestStreamId, handle_->id()); + EXPECT_EQ(QUIC_NO_ERROR, handle_->connection_error()); + EXPECT_EQ(QUIC_STREAM_NO_ERROR, handle_->stream_error()); + EXPECT_TRUE(handle_->IsFirstStream()); + EXPECT_FALSE(handle_->IsDoneReading()); + EXPECT_FALSE(handle_->fin_sent()); + EXPECT_FALSE(handle_->fin_received()); + EXPECT_EQ(0u, handle_->stream_bytes_read()); + EXPECT_EQ(0u, handle_->stream_bytes_written()); + EXPECT_EQ(0u, handle_->NumBytesConsumed()); + + InitializeHeaders(); + QuicStreamOffset offset = 0; + ProcessHeadersFull(headers_); + QuicStreamFrame frame2(kTestStreamId, true, offset, QuicStringPiece()); + EXPECT_CALL(delegate_, OnClose()); + stream_->OnStreamFrame(frame2); + EXPECT_TRUE(handle_->fin_received()); + handle_->OnFinRead(); + + const char kData1[] = "hello world"; + const size_t kDataLen = arraysize(kData1); + + // All data written. + EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _, _)) + .WillOnce(Return(QuicConsumedData(kDataLen, true))); + TestCompletionCallback callback; + EXPECT_EQ(OK, handle_->WriteStreamData(QuicStringPiece(kData1, kDataLen), + true, callback.callback())); + + EXPECT_FALSE(handle_->IsOpen()); + EXPECT_EQ(kTestStreamId, handle_->id()); + EXPECT_EQ(QUIC_NO_ERROR, handle_->connection_error()); + EXPECT_EQ(QUIC_STREAM_NO_ERROR, handle_->stream_error()); + EXPECT_TRUE(handle_->IsFirstStream()); + EXPECT_TRUE(handle_->IsDoneReading()); + EXPECT_TRUE(handle_->fin_sent()); + EXPECT_TRUE(handle_->fin_received()); + EXPECT_EQ(0u, handle_->stream_bytes_read()); + EXPECT_EQ(kDataLen, handle_->stream_bytes_written()); + EXPECT_EQ(0u, handle_->NumBytesConsumed()); + + EXPECT_EQ(ERR_CONNECTION_CLOSED, + handle_->WriteStreamData(QuicStringPiece(kData1, kDataLen), true, + callback.callback())); + + std::vector<scoped_refptr<IOBuffer>> buffers = { + scoped_refptr<IOBuffer>(new IOBuffer(10))}; + std::vector<int> lengths = {10}; + EXPECT_EQ( + ERR_CONNECTION_CLOSED, + handle_->WritevStreamData(buffers, lengths, true, callback.callback())); + + SpdyHeaderBlock headers; + EXPECT_EQ(0u, handle_->WriteHeaders(std::move(headers), true, nullptr)); +} + +TEST_P(QuicChromiumClientStreamTest, HandleAfterConnectionClose) { + // Verify that the delegate's OnClose is called after closing the connection. + EXPECT_CALL(delegate_, OnClose()); + EXPECT_CALL(session_, + SendRstStream(kTestStreamId, QUIC_RST_ACKNOWLEDGEMENT, 0)); + stream_->OnConnectionClosed(QUIC_INVALID_FRAME_DATA, + ConnectionCloseSource::FROM_PEER); + + EXPECT_FALSE(handle_->IsOpen()); + EXPECT_EQ(QUIC_INVALID_FRAME_DATA, handle_->connection_error()); +} + +TEST_P(QuicChromiumClientStreamTest, HandleAfterStreamReset) { + // Verify that the delegate's OnClose is called after the stream is reset, + // but that the Handle still behaves correctly. + EXPECT_CALL(delegate_, OnClose()); + QuicRstStreamFrame rst(kTestStreamId, QUIC_STREAM_CANCELLED, 0); + EXPECT_CALL(session_, + SendRstStream(kTestStreamId, QUIC_RST_ACKNOWLEDGEMENT, 0)); + stream_->OnStreamReset(rst); + + EXPECT_FALSE(handle_->IsOpen()); + EXPECT_EQ(QUIC_STREAM_CANCELLED, handle_->stream_error()); +} + +TEST_P(QuicChromiumClientStreamTest, HandleAfterClearDelegate) { + EXPECT_TRUE(handle_->IsOpen()); + handle_->ClearDelegate(); + + // Verify that the delegate's OnClose is not called after ClearDelegate. + EXPECT_CALL(delegate_, OnClose()).Times(0); + QuicRstStreamFrame rst(kTestStreamId, QUIC_STREAM_CANCELLED, 0); + EXPECT_CALL(session_, + SendRstStream(kTestStreamId, QUIC_RST_ACKNOWLEDGEMENT, 0)); + stream_->OnStreamReset(rst); + + EXPECT_FALSE(handle_->IsOpen()); + EXPECT_EQ(QUIC_STREAM_CANCELLED, handle_->stream_error()); +} + TEST_P(QuicChromiumClientStreamTest, OnFinRead) { InitializeHeaders(); QuicStreamOffset offset = 0; @@ -359,10 +460,10 @@ } TEST_P(QuicChromiumClientStreamTest, OnError) { - EXPECT_CALL(delegate_, OnError(ERR_INTERNET_DISCONNECTED)); + EXPECT_CALL(delegate_, OnError(ERR_INTERNET_DISCONNECTED)).Times(1); stream_->OnError(ERR_INTERNET_DISCONNECTED); - EXPECT_FALSE(stream_->GetDelegate()); + stream_->OnError(ERR_INTERNET_DISCONNECTED); } TEST_P(QuicChromiumClientStreamTest, OnTrailers) { @@ -640,7 +741,7 @@ // Now set the delegate and verify that the headers are delivered. EXPECT_CALL(delegate2_, OnInitialHeadersAvailableMock( _, header_list.uncompressed_header_bytes())); - stream2->SetDelegate(&delegate2_); + handle2_ = stream2->CreateHandle(&delegate2_); base::RunLoop().RunUntilIdle(); EXPECT_EQ(headers_, delegate2_.headers_); @@ -672,7 +773,7 @@ // not the data, which needs to be read explicitly. EXPECT_CALL(delegate2_, OnInitialHeadersAvailableMock( _, header_list.uncompressed_header_bytes())); - stream2->SetDelegate(&delegate2_); + handle2_ = stream2->CreateHandle(&delegate2_); base::RunLoop().RunUntilIdle(); EXPECT_EQ(headers_, delegate2_.headers_); base::RunLoop().RunUntilIdle();
diff --git a/net/quic/chromium/quic_http_stream.cc b/net/quic/chromium/quic_http_stream.cc index e28f01f..095f86b 100644 --- a/net/quic/chromium/quic_http_stream.cc +++ b/net/quic/chromium/quic_http_stream.cc
@@ -108,8 +108,8 @@ void QuicHttpStream::OnRendezvousResult(QuicSpdyStream* stream) { push_handle_ = nullptr; if (stream) { - stream_ = static_cast<QuicChromiumClientStream*>(stream); - stream_->SetDelegate(this); + stream_ = + static_cast<QuicChromiumClientStream*>(stream)->CreateHandle(this); } // callback_ should only be non-null in the case of asynchronous @@ -358,7 +358,7 @@ SaveResponseStatus(); // Note: the not_reusable flag has no meaning for QUIC streams. if (stream_) { - stream_->SetDelegate(nullptr); + stream_->ClearDelegate(); stream_->Reset(QUIC_STREAM_CANCELLED); } ResetStream(); @@ -378,10 +378,9 @@ // bytes. Change this to include QUIC overhead as well. int64_t total_received_bytes = headers_bytes_received_; if (stream_) { - DCHECK_LE(stream_->sequencer()->NumBytesConsumed(), - stream_->stream_bytes_read()); + DCHECK_LE(stream_->NumBytesConsumed(), stream_->stream_bytes_read()); // Only count the uniquely received bytes. - total_received_bytes += stream_->sequencer()->NumBytesConsumed(); + total_received_bytes += stream_->NumBytesConsumed(); } else { total_received_bytes += closed_stream_received_bytes_; } @@ -671,7 +670,7 @@ // |rv| is the result of read from the request body from the last call to // DoSendBody(). if (rv < 0) { - stream_->SetDelegate(nullptr); + stream_->ClearDelegate(); stream_->Reset(QUIC_ERROR_PROCESSING_STREAM); ResetStream(); return rv; @@ -764,7 +763,7 @@ if (null_stream) return rv; if (stream_->IsDoneReading()) { - stream_->SetDelegate(nullptr); + stream_->ClearDelegate(); stream_->OnFinRead(); SetResponseStatus(OK); ResetStream(); @@ -779,12 +778,12 @@ } if (!stream_) return; - DCHECK_LE(stream_->sequencer()->NumBytesConsumed(), - stream_->stream_bytes_read()); + DCHECK_LE(stream_->NumBytesConsumed(), stream_->stream_bytes_read()); // Only count the uniquely received bytes. - closed_stream_received_bytes_ = stream_->sequencer()->NumBytesConsumed(); + closed_stream_received_bytes_ = stream_->NumBytesConsumed(); closed_stream_sent_bytes_ = stream_->stream_bytes_written(); closed_is_first_stream_ = stream_->IsFirstStream(); + stream_->ClearDelegate(); stream_ = nullptr; // If |request_body_stream_| is non-NULL, Reset it, to abort any in progress
diff --git a/net/quic/chromium/quic_http_stream.h b/net/quic/chromium/quic_http_stream.h index fe240f8..eb49000 100644 --- a/net/quic/chromium/quic_http_stream.h +++ b/net/quic/chromium/quic_http_stream.h
@@ -81,6 +81,9 @@ bool CheckVary(const SpdyHeaderBlock& client_request, const SpdyHeaderBlock& promise_request, const SpdyHeaderBlock& promise_response) override; + // TODO(rch): QuicClientPushPromiseIndex::Delegate is part of shared code. + // Figure out how to make the QuicHttpStream receive a Handle in this + // case instead of a QuicSpdyStream. void OnRendezvousResult(QuicSpdyStream* stream) override; static HttpResponseInfo::ConnectionInfo ConnectionInfoFromQuicVersion( @@ -152,7 +155,7 @@ HttpServerProperties* http_server_properties_; // Unowned. - QuicChromiumClientStream* stream_; // Non-owning. + std::unique_ptr<QuicChromiumClientStream::Handle> stream_; // The following three fields are all owned by the caller and must // outlive this object, according to the HttpStream contract.
diff --git a/net/quic/chromium/quic_http_stream_test.cc b/net/quic/chromium/quic_http_stream_test.cc index 1b8af58..ff43b73 100644 --- a/net/quic/chromium/quic_http_stream_test.cc +++ b/net/quic/chromium/quic_http_stream_test.cc
@@ -178,9 +178,9 @@ class QuicHttpStreamPeer { public: - static QuicChromiumClientStream* GetQuicChromiumClientStream( + static QuicChromiumClientStream::Handle* GetQuicChromiumClientStream( QuicHttpStream* stream) { - return stream->stream_; + return stream->stream_.get(); } }; @@ -536,7 +536,7 @@ void ReceivePromise(QuicStreamId id) { auto headers = AsHeaderList(push_promise_); - QuicChromiumClientStream* stream = + QuicChromiumClientStream::Handle* stream = QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get()); stream->OnPromiseHeaderList(id, headers.uncompressed_header_bytes(), headers); @@ -631,7 +631,7 @@ EXPECT_EQ(OK, stream_->InitializeStream(&request_, DEFAULT_PRIORITY, net_log_.bound(), callback_.callback())); - QuicChromiumClientStream* client_stream = + QuicChromiumClientStream::Handle* client_stream = QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get()); EXPECT_FALSE(client_stream->can_migrate()); } @@ -1466,7 +1466,7 @@ callback_.callback())); // Check that priority is highest. - QuicChromiumClientStream* reliable_stream = + QuicChromiumClientStream::Handle* reliable_stream = QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get()); DCHECK(reliable_stream); DCHECK_EQ(kV3HighestPriority, reliable_stream->priority()); @@ -1517,7 +1517,7 @@ callback_.callback())); // Check that priority is highest. - QuicChromiumClientStream* reliable_stream = + QuicChromiumClientStream::Handle* reliable_stream = QuicHttpStreamPeer::GetQuicChromiumClientStream(stream_.get()); DCHECK(reliable_stream); QuicChromiumClientStream::Delegate* delegate = reliable_stream->GetDelegate(); @@ -1526,9 +1526,8 @@ // Set Delegate to nullptr and make sure Priority returns highest // priority. - reliable_stream->SetDelegate(nullptr); + reliable_stream->ClearDelegate(); DCHECK_EQ(kV3HighestPriority, reliable_stream->priority()); - reliable_stream->SetDelegate(delegate); EXPECT_EQ(0, stream_->GetTotalSentBytes()); EXPECT_EQ(0, stream_->GetTotalReceivedBytes());
diff --git a/net/reporting/reporting_cache.cc b/net/reporting/reporting_cache.cc index b3b6010..b8034c8 100644 --- a/net/reporting/reporting_cache.cc +++ b/net/reporting/reporting_cache.cc
@@ -61,6 +61,18 @@ reports_.insert(std::make_pair(report.get(), std::move(report))); DCHECK(inserted.second); + if (reports_.size() > context_->policy().max_report_count) { + // There should be at most one extra report (the one added above). + DCHECK_EQ(context_->policy().max_report_count + 1, reports_.size()); + const ReportingReport* to_evict = FindReportToEvict(); + DCHECK_NE(nullptr, to_evict); + // The newly-added report isn't pending, so even if all other reports are + // pending, the cache should have a report to evict. + DCHECK(!base::ContainsKey(pending_reports_, to_evict)); + size_t erased = reports_.erase(to_evict); + DCHECK_EQ(1u, erased); + } + context_->NotifyCacheUpdated(); } @@ -233,6 +245,21 @@ context_->NotifyCacheUpdated(); } +const ReportingReport* ReportingCache::FindReportToEvict() const { + const ReportingReport* earliest_queued = nullptr; + + for (const auto& it : reports_) { + const ReportingReport* report = it.first; + if (base::ContainsKey(pending_reports_, report)) + continue; + if (!earliest_queued || report->queued < earliest_queued->queued) { + earliest_queued = report; + } + } + + return earliest_queued; +} + void ReportingCache::MaybeAddWildcardClient(const ReportingClient* client) { if (client->subdomains != ReportingClient::Subdomains::INCLUDE) return;
diff --git a/net/reporting/reporting_cache.h b/net/reporting/reporting_cache.h index 30ad0429..122e0c81 100644 --- a/net/reporting/reporting_cache.h +++ b/net/reporting/reporting_cache.h
@@ -159,6 +159,8 @@ } private: + const ReportingReport* FindReportToEvict() const; + void MaybeAddWildcardClient(const ReportingClient* client); void MaybeRemoveWildcardClient(const ReportingClient* client);
diff --git a/net/reporting/reporting_cache_unittest.cc b/net/reporting/reporting_cache_unittest.cc index 7302340..19229db2 100644 --- a/net/reporting/reporting_cache_unittest.cc +++ b/net/reporting/reporting_cache_unittest.cc
@@ -7,6 +7,7 @@ #include <string> #include "base/memory/ptr_util.h" +#include "base/test/simple_test_tick_clock.h" #include "base/time/time.h" #include "base/values.h" #include "net/reporting/reporting_client.h" @@ -42,6 +43,12 @@ TestReportingObserver* observer() { return &observer_; } + size_t report_count() { + std::vector<const ReportingReport*> reports; + cache()->GetReports(&reports); + return reports.size(); + } + const GURL kUrl1_ = GURL("https://origin1/path"); const url::Origin kOrigin1_ = url::Origin(GURL("https://origin1/")); const url::Origin kOrigin2_ = url::Origin(GURL("https://origin2/")); @@ -400,5 +407,65 @@ EXPECT_EQ(kSuperOrigin, clients[0]->origin); } +TEST_F(ReportingCacheTest, EvictOldest) { + ASSERT_LT(0u, policy().max_report_count); + ASSERT_GT(std::numeric_limits<size_t>::max(), policy().max_report_count); + + base::TimeTicks earliest_queued = tick_clock()->NowTicks(); + + // Enqueue the maximum number of reports, spaced apart in time. + for (size_t i = 0; i < policy().max_report_count; ++i) { + cache()->AddReport(kUrl1_, kGroup1_, kType_, + base::MakeUnique<base::DictionaryValue>(), + tick_clock()->NowTicks(), 0); + tick_clock()->Advance(base::TimeDelta::FromMinutes(1)); + } + EXPECT_EQ(policy().max_report_count, report_count()); + + // Add one more report to force the cache to evict one. + cache()->AddReport(kUrl1_, kGroup1_, kType_, + base::MakeUnique<base::DictionaryValue>(), kNow_, 0); + + // Make sure the cache evicted a report to make room for the new one, and make + // sure the report evicted was the earliest-queued one. + std::vector<const ReportingReport*> reports; + cache()->GetReports(&reports); + EXPECT_EQ(policy().max_report_count, reports.size()); + for (const ReportingReport* report : reports) + EXPECT_NE(earliest_queued, report->queued); +} + +TEST_F(ReportingCacheTest, DontEvictPendingReports) { + ASSERT_LT(0u, policy().max_report_count); + ASSERT_GT(std::numeric_limits<size_t>::max(), policy().max_report_count); + + // Enqueue the maximum number of reports, spaced apart in time. + for (size_t i = 0; i < policy().max_report_count; ++i) { + cache()->AddReport(kUrl1_, kGroup1_, kType_, + base::MakeUnique<base::DictionaryValue>(), + tick_clock()->NowTicks(), 0); + tick_clock()->Advance(base::TimeDelta::FromMinutes(1)); + } + EXPECT_EQ(policy().max_report_count, report_count()); + + // Mark all of the queued reports pending. + std::vector<const ReportingReport*> queued_reports; + cache()->GetReports(&queued_reports); + cache()->SetReportsPending(queued_reports); + + // Add one more report to force the cache to evict one. Since the cache has + // only pending reports, it will be forced to evict the *new* report! + cache()->AddReport(kUrl1_, kGroup1_, kType_, + base::MakeUnique<base::DictionaryValue>(), kNow_, 0); + + // Make sure the cache evicted a report, and make sure the report evicted was + // the new, non-pending one. + std::vector<const ReportingReport*> reports; + cache()->GetReports(&reports); + EXPECT_EQ(policy().max_report_count, reports.size()); + for (const ReportingReport* report : reports) + EXPECT_TRUE(cache()->IsReportPendingForTesting(report)); +} + } // namespace } // namespace net
diff --git a/net/reporting/reporting_policy.cc b/net/reporting/reporting_policy.cc index e439fd7..11f58fd 100644 --- a/net/reporting/reporting_policy.cc +++ b/net/reporting/reporting_policy.cc
@@ -9,7 +9,8 @@ namespace net { ReportingPolicy::ReportingPolicy() - : delivery_interval(base::TimeDelta::FromMinutes(1)), + : max_report_count(100u), + delivery_interval(base::TimeDelta::FromMinutes(1)), persistence_interval(base::TimeDelta::FromMinutes(1)), persist_reports_across_restarts(false), persist_clients_across_restarts(true), @@ -28,7 +29,8 @@ } ReportingPolicy::ReportingPolicy(const ReportingPolicy& other) - : delivery_interval(base::TimeDelta::FromMinutes(1)), + : max_report_count(other.max_report_count), + delivery_interval(other.delivery_interval), endpoint_backoff_policy(other.endpoint_backoff_policy), persistence_interval(other.persistence_interval), persist_reports_across_restarts(other.persist_reports_across_restarts),
diff --git a/net/reporting/reporting_policy.h b/net/reporting/reporting_policy.h index c400bfff..98e1a4a 100644 --- a/net/reporting/reporting_policy.h +++ b/net/reporting/reporting_policy.h
@@ -18,6 +18,9 @@ ReportingPolicy(const ReportingPolicy& other); ~ReportingPolicy(); + // Maximum number of reports to queue before evicting the oldest. + size_t max_report_count; + // Minimum interval at which to attempt delivery of queued reports. base::TimeDelta delivery_interval;
diff --git a/remoting/client/chromoting_client_runtime.cc b/remoting/client/chromoting_client_runtime.cc index 9b12aace..ea71d70 100644 --- a/remoting/client/chromoting_client_runtime.cc +++ b/remoting/client/chromoting_client_runtime.cc
@@ -84,7 +84,6 @@ void ChromotingClientRuntime::SetDelegate( ChromotingClientRuntime::Delegate* delegate) { delegate_ = delegate; - delegate_->RequestAuthTokenForLogger(); } void ChromotingClientRuntime::CreateLogWriter() {
diff --git a/remoting/client/ios/BUILD.gn b/remoting/client/ios/BUILD.gn index 365b72b..91d7a2d1 100644 --- a/remoting/client/ios/BUILD.gn +++ b/remoting/client/ios/BUILD.gn
@@ -31,6 +31,8 @@ "key_input.h", "key_input.mm", "key_map_us.h", + "keychain_wrapper.h", + "keychain_wrapper.mm", ] if (!is_chrome_branded) {
diff --git a/remoting/client/ios/app/app_delegate.mm b/remoting/client/ios/app/app_delegate.mm index ae4b24f..7dc1369 100644 --- a/remoting/client/ios/app/app_delegate.mm +++ b/remoting/client/ios/app/app_delegate.mm
@@ -13,6 +13,7 @@ #include "ui/base/resource/resource_bundle.h" #import "remoting/client/ios/app/remoting_view_controller.h" +#import "remoting/client/ios/facade/remoting_authentication.h" #import "remoting/client/ios/facade/remoting_service.h" @implementation AppDelegate @@ -45,7 +46,7 @@ } NSString* authorizationCode = [components objectForKey:@"code"]; - [[RemotingService SharedInstance] + [[RemotingService SharedInstance].authentication authenticateWithAuthorizationCode:authorizationCode]; [self launchRemotingViewController];
diff --git a/remoting/client/ios/app/remoting_settings_view_controller.mm b/remoting/client/ios/app/remoting_settings_view_controller.mm index da3c0cd8..1db1db0 100644 --- a/remoting/client/ios/app/remoting_settings_view_controller.mm +++ b/remoting/client/ios/app/remoting_settings_view_controller.mm
@@ -10,6 +10,8 @@ #import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.h" #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h" +#import "remoting/client/ios/facade/remoting_authentication.h" +#import "remoting/client/ios/facade/remoting_service.h" #include "base/strings/stringprintf.h" #include "google_apis/google_api_keys.h" @@ -113,7 +115,7 @@ self.styler.cellStyle = MDCCollectionViewCellStyleCard; _content = [NSMutableArray array]; - [_content addObject:@[ @"Login" ]]; + [_content addObject:@[ @"Login", @"Logout" ]]; } #pragma mark - UICollectionViewDataSource @@ -146,10 +148,17 @@ forControlEvents:UIControlEventTouchUpInside]; accessCodeButton.translatesAutoresizingMaskIntoConstraints = NO; cell.accessoryView = accessCodeButton; - } else { - UISwitch* editingSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; - cell.accessoryView = editingSwitch; + } else if (indexPath.section == 0 && indexPath.item == 1) { + MDCRaisedButton* logoutButton = [[MDCRaisedButton alloc] init]; + [logoutButton setTitle:@"Logout" forState:UIControlStateNormal]; + [logoutButton sizeToFit]; + [logoutButton addTarget:self + action:@selector(didTapLogout:) + forControlEvents:UIControlEventTouchUpInside]; + logoutButton.translatesAutoresizingMaskIntoConstraints = NO; + cell.accessoryView = logoutButton; } + return cell; } @@ -192,4 +201,8 @@ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:authUri]]; } +- (void)didTapLogout:(id)sender { + [[RemotingService SharedInstance].authentication logout]; +} + @end
diff --git a/remoting/client/ios/app/remoting_view_controller.h b/remoting/client/ios/app/remoting_view_controller.h index fcf4bdd..f3188d7 100644 --- a/remoting/client/ios/app/remoting_view_controller.h +++ b/remoting/client/ios/app/remoting_view_controller.h
@@ -8,9 +8,7 @@ #import "ios/third_party/material_components_ios/src/components/FlexibleHeader/src/MaterialFlexibleHeader.h" #import "remoting/client/ios/facade/remoting_service.h" -@interface RemotingViewController - : MDCFlexibleHeaderContainerViewController<RemotingAuthenticationDelegate, - RemotingHostListDelegate> +@interface RemotingViewController : MDCFlexibleHeaderContainerViewController @end
diff --git a/remoting/client/ios/app/remoting_view_controller.mm b/remoting/client/ios/app/remoting_view_controller.mm index 25bb218..bb3c50f 100644 --- a/remoting/client/ios/app/remoting_view_controller.mm +++ b/remoting/client/ios/app/remoting_view_controller.mm
@@ -18,6 +18,7 @@ #import "remoting/client/ios/app/host_view_controller.h" #import "remoting/client/ios/app/remoting_settings_view_controller.h" #import "remoting/client/ios/domain/client_session_details.h" +#import "remoting/client/ios/facade/remoting_authentication.h" #import "remoting/client/ios/facade/remoting_service.h" #import "remoting/client/ios/session/remoting_client.h" @@ -59,7 +60,6 @@ self = [super initWithContentViewController:collectionVC]; if (self) { _remotingService = [RemotingService SharedInstance]; - [_remotingService setAuthenticationDelegate:self]; _collectionViewController = collectionVC; _collectionViewController.flexHeaderContainerViewController = self; @@ -100,10 +100,28 @@ - (void)viewDidLoad { [super viewDidLoad]; [_appBar addSubviewsToParent]; + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(hostsDidUpdateNotification:) + name:kHostsDidUpdate + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(userDidUpdateNotification:) + name:kUserDidUpdate + object:nil]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [self nowAuthenticated:_remotingService.authentication.user.isAuthenticated]; [self presentStatus]; } - (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; if (!_isAuthenticated) { // TODO(nicholss): This is used as a demo of the app functionality for the // moment but the real app will force the login flow if unauthenticated. @@ -112,6 +130,8 @@ MDCSnackbarMessage* message = [[MDCSnackbarMessage alloc] init]; message.text = @"Please login."; [MDCSnackbarManager showMessage:message]; + } else { + [_remotingService requestHostListFetch]; } } @@ -129,6 +149,16 @@ collectionHeight); } +#pragma mark - Remoting Service Notifications + +- (void)hostsDidUpdateNotification:(NSNotification*)notification { + [_collectionViewController.collectionView reloadData]; +} + +- (void)userDidUpdateNotification:(NSNotification*)notification { + [self nowAuthenticated:_remotingService.authentication.user.isAuthenticated]; +} + #pragma mark - RemotingAuthenticationDelegate - (void)nowAuthenticated:(BOOL)authenticated { @@ -136,12 +166,10 @@ MDCSnackbarMessage* message = [[MDCSnackbarMessage alloc] init]; message.text = @"Logged In!"; [MDCSnackbarManager showMessage:message]; - [_remotingService setHostListDelegate:self]; } else { MDCSnackbarMessage* message = [[MDCSnackbarMessage alloc] init]; message.text = @"Not logged in."; [MDCSnackbarManager showMessage:message]; - [_remotingService setHostListDelegate:nil]; } _isAuthenticated = authenticated; [_collectionViewController.collectionView reloadData]; @@ -176,7 +204,7 @@ completion:(void (^)())completionBlock { _client = [[RemotingClient alloc] init]; - [_remotingService + [_remotingService.authentication callbackWithAccessToken:base::BindBlockArc(^( remoting::OAuthTokenGetter::Status status, const std::string& user_email, @@ -198,13 +226,11 @@ } - (NSInteger)getHostCount { - NSArray<HostInfo*>* hosts = [_remotingService getHosts]; - return [hosts count]; + return _remotingService.hosts.count; } - (HostInfo*)getHostAtIndexPath:(NSIndexPath*)path { - NSArray<HostInfo*>* hosts = [_remotingService getHosts]; - return hosts[path.row]; + return _remotingService.hosts[path.row]; } #pragma mark - UIViewControllerTransitioningDelegate @@ -244,9 +270,9 @@ } - (void)didSelectRefresh { - // TODO(nicholss) implement this. - NSLog(@"Should refresh..."); - _dialogTransitionController = [[MDCDialogTransitionController alloc] init]; + // TODO(nicholss): Might want to rate limit this. Maybe remoting service + // controls that. + [_remotingService requestHostListFetch]; } - (void)didSelectSettings { @@ -260,9 +286,9 @@ - (void)presentStatus { MDCSnackbarMessage* message = [[MDCSnackbarMessage alloc] init]; if (_isAuthenticated) { - UserInfo* user = [_remotingService getUser]; message.text = [NSString - stringWithFormat:@"Currently signed in as %@.", [user userEmail]]; + stringWithFormat:@"Currently signed in as %@.", + _remotingService.authentication.user.userEmail]; [MDCSnackbarManager showMessage:message]; } }
diff --git a/remoting/client/ios/domain/host_info.h b/remoting/client/ios/domain/host_info.h index a897f8b..ad646a1b 100644 --- a/remoting/client/ios/domain/host_info.h +++ b/remoting/client/ios/domain/host_info.h
@@ -23,6 +23,8 @@ // True when |status| is @"ONLINE", anything else is False. @property(nonatomic, readonly) bool isOnline; +// Convert a json blob into a |HostInfo| object. Most useful for test. +// TODO(nicholss): Might move this out into a catagory. + (NSMutableArray<HostInfo*>*)parseListFromJSON:(NSMutableData*)data; // First consider if |isOnline| is greater than anything else, then consider by
diff --git a/remoting/client/ios/domain/user_info.h b/remoting/client/ios/domain/user_info.h index 5bbae71..8c463317 100644 --- a/remoting/client/ios/domain/user_info.h +++ b/remoting/client/ios/domain/user_info.h
@@ -14,9 +14,15 @@ @property(nonatomic, copy) NSString* userId; @property(nonatomic, copy) NSString* userFullName; @property(nonatomic, copy) NSString* userEmail; +@property(nonatomic, copy) NSString* refreshToken; +// Convert a json blob into a |UserInfo| object. Most useful for test. +// TODO(nicholss): Might move this out into a catagory. + (UserInfo*)parseListFromJSON:(NSMutableData*)data; +// This returns the authenticated state of the this user info object. +- (BOOL)isAuthenticated; +// Compare two |UserInfo| objects. - (NSComparisonResult)compare:(UserInfo*)user; @end
diff --git a/remoting/client/ios/domain/user_info.mm b/remoting/client/ios/domain/user_info.mm index ece9064..3257fd22 100644 --- a/remoting/client/ios/domain/user_info.mm +++ b/remoting/client/ios/domain/user_info.mm
@@ -13,6 +13,7 @@ @synthesize userId = _userId; @synthesize userFullName = _userFullName; @synthesize userEmail = _userEmail; +@synthesize refreshToken = _refreshToken; // Parse jsonData into Host list. + (UserInfo*)parseListFromJSON:(NSMutableData*)data { @@ -26,12 +27,26 @@ user.userId = [json objectForKey:@"userId"]; user.userFullName = [json objectForKey:@"userFullName"]; user.userEmail = [json objectForKey:@"userEmail"]; + user.refreshToken = [json objectForKey:@"refreshToken"]; return user; } +- (BOOL)isAuthenticated { + if (_userEmail && _userEmail.length > 0 && _refreshToken && + _refreshToken.length > 0) { + return YES; + } + return NO; +} + - (NSComparisonResult)compare:(UserInfo*)user { return [self.userId compare:user.userId]; } +- (NSString*)description { + return [NSString stringWithFormat:@"UserInfo: userEmail=%@ refreshToken=%@", + _userEmail, _refreshToken]; +} + @end
diff --git a/remoting/client/ios/facade/BUILD.gn b/remoting/client/ios/facade/BUILD.gn index db632c7..a02d423 100644 --- a/remoting/client/ios/facade/BUILD.gn +++ b/remoting/client/ios/facade/BUILD.gn
@@ -14,6 +14,8 @@ "host_list_fetcher.h", "ios_client_runtime_delegate.h", "ios_client_runtime_delegate.mm", + "remoting_authentication.h", + "remoting_authentication.mm", "remoting_service.h", "remoting_service.mm", ]
diff --git a/remoting/client/ios/facade/host_list_fetcher.cc b/remoting/client/ios/facade/host_list_fetcher.cc index 6c1bb00..e7c4f38 100644 --- a/remoting/client/ios/facade/host_list_fetcher.cc +++ b/remoting/client/ios/facade/host_list_fetcher.cc
@@ -29,6 +29,8 @@ // that. For the moment it will work to make progress in the app. void HostListFetcher::RetrieveHostlist(const std::string& access_token, const HostlistCallback& callback) { + // TODO(nicholss): There is a bug here if two host list fetches are happening + // at the same time there will be a dcheck thrown. Fix this for release. DCHECK(!access_token.empty()); DCHECK(callback); DCHECK(!hostlist_callback_);
diff --git a/remoting/client/ios/facade/ios_client_runtime_delegate.mm b/remoting/client/ios/facade/ios_client_runtime_delegate.mm index 8bd90fc0..b773b2a 100644 --- a/remoting/client/ios/facade/ios_client_runtime_delegate.mm +++ b/remoting/client/ios/facade/ios_client_runtime_delegate.mm
@@ -9,6 +9,7 @@ #include "remoting/client/ios/facade/ios_client_runtime_delegate.h" #import "base/mac/bind_objc_block.h" +#import "remoting/client/ios/facade/remoting_authentication.h" #import "remoting/client/ios/facade/remoting_service.h" #include "base/bind.h" @@ -43,18 +44,24 @@ base::Unretained(this))); return; } - // TODO(nicholss): Need to work out how to provide the logger with auth token - // at the correct time in the app. This was hanging the app bootup. Removing - // for now but this needs to happen the correct way soon. - // if ([[RemotingService SharedInstance] getUser]) { - // [[RemotingService SharedInstance] - // callbackWithAccessToken:base::BindBlockArc( - // ^(remoting::OAuthTokenGetter::Status status, - // const std::string& user_email, const std::string& access_token) { - // // TODO(nicholss): Check status. - // runtime_->log_writer()->SetAuthToken(access_token); - // })]; - // } + if ([[RemotingService SharedInstance].authentication.user isAuthenticated]) { + [[RemotingService SharedInstance].authentication + callbackWithAccessToken:base::BindBlockArc(^( + remoting::OAuthTokenGetter::Status status, + const std::string& user_email, + const std::string& access_token) { + if (status == remoting::OAuthTokenGetter::Status::SUCCESS) { + // Set the new auth token for the log writer on the network thread. + runtime_->network_task_runner()->PostTask( + FROM_HERE, base::BindBlockArc(^{ + runtime_->log_writer()->SetAuthToken(access_token); + })); + } else { + LOG(ERROR) << "Failed to fetch access token for log writer. (" + << status << ")"; + } + })]; + } } base::WeakPtr<IosClientRuntimeDelegate> IosClientRuntimeDelegate::GetWeakPtr() {
diff --git a/remoting/client/ios/facade/remoting_authentication.h b/remoting/client/ios/facade/remoting_authentication.h new file mode 100644 index 0000000..1ab7e33 --- /dev/null +++ b/remoting/client/ios/facade/remoting_authentication.h
@@ -0,0 +1,51 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_CLIENT_IOS_FACADE_REMOTING_AUTHENTICATION_H_ +#define REMOTING_CLIENT_IOS_FACADE_REMOTING_AUTHENTICATION_H_ + +#import "remoting/client/chromoting_client_runtime.h" +#import "remoting/client/ios/domain/user_info.h" + +#include "base/memory/weak_ptr.h" +#include "remoting/base/oauth_token_getter.h" + +// |RemotingAuthenticationDelegate|s are interested in authentication related +// notifications. +@protocol RemotingAuthenticationDelegate<NSObject> + +// Notifies the delegate that the user has been updated. +- (void)userDidUpdate:(UserInfo*)user; + +@end + +// This is the class that will manage the details around authentication +// management and currently active user. It will make sure the user object is +// saved to the keychain correctly and loaded on startup. It also is the entry +// point for gaining access to an auth token for authrized calls. +@interface RemotingAuthentication : NSObject + +// Provide an |authorizationCode| to authenticate a user as the first time user +// of the application or OAuth Flow. +- (void)authenticateWithAuthorizationCode:(NSString*)authorizationCode; + +// Fetches an OAuth Access Token and passes it back to the callback if +// the user is authenticated. Otherwise does nothing. +// TODO(nicholss): We might want to throw an error or add error message to +// the callback sig to be able to react to the un-authed case. +- (void)callbackWithAccessToken: + (const remoting::OAuthTokenGetter::TokenCallback&)onAccessToken; + +// Forget the current user. +- (void)logout; + +// Returns the currently logged in user or nil. +@property(strong, nonatomic) UserInfo* user; + +// Delegate recieves updates on user changes. +@property(weak, nonatomic) id<RemotingAuthenticationDelegate> delegate; + +@end + +#endif // REMOTING_CLIENT_IOS_FACADE_REMOTING_AUTHENTICATION_H_
diff --git a/remoting/client/ios/facade/remoting_authentication.mm b/remoting/client/ios/facade/remoting_authentication.mm new file mode 100644 index 0000000..5abe68fb --- /dev/null +++ b/remoting/client/ios/facade/remoting_authentication.mm
@@ -0,0 +1,195 @@ +// 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. + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "remoting/client/ios/facade/remoting_authentication.h" + +#import <Foundation/Foundation.h> +#import <Security/Security.h> + +#import "base/mac/bind_objc_block.h" +#import "remoting/client/ios/facade/host_info.h" +#import "remoting/client/ios/facade/host_list_fetcher.h" +#import "remoting/client/ios/facade/ios_client_runtime_delegate.h" +#import "remoting/client/ios/facade/remoting_service.h" +#import "remoting/client/ios/keychain_wrapper.h" + +#include "base/logging.h" +#include "base/strings/sys_string_conversions.h" +#include "net/url_request/url_request_context_getter.h" +#include "remoting/base/oauth_token_getter.h" +#include "remoting/base/oauth_token_getter_impl.h" + +static NSString* const kCRDAuthenticatedUserEmailKey = + @"kCRDAuthenticatedUserEmailKey"; + +const char kOauthRedirectUrl[] = + "https://chromoting-oauth.talkgadget." + "google.com/talkgadget/oauth/chrome-remote-desktop/dev"; + +std::unique_ptr<remoting::OAuthTokenGetter> +CreateOAuthTokenGetterWithAuthorizationCode( + const std::string& auth_code, + const remoting::OAuthTokenGetter::CredentialsUpdatedCallback& + on_credentials_update) { + std::unique_ptr<remoting::OAuthTokenGetter::OAuthIntermediateCredentials> + oauth_credentials( + new remoting::OAuthTokenGetter::OAuthIntermediateCredentials( + auth_code, /*is_service_account=*/false)); + oauth_credentials->oauth_redirect_uri = kOauthRedirectUrl; + + std::unique_ptr<remoting::OAuthTokenGetter> oauth_tokenGetter( + new remoting::OAuthTokenGetterImpl( + std::move(oauth_credentials), on_credentials_update, + [RemotingService SharedInstance].runtime->url_requester(), + /*auto_refresh=*/true)); + return oauth_tokenGetter; +} + +std::unique_ptr<remoting::OAuthTokenGetter> CreateOAuthTokenWithRefreshToken( + const std::string& refresh_token, + const std::string& email) { + std::unique_ptr<remoting::OAuthTokenGetter::OAuthAuthorizationCredentials> + oauth_credentials( + new remoting::OAuthTokenGetter::OAuthAuthorizationCredentials( + email, refresh_token, /*is_service_account=*/false)); + + std::unique_ptr<remoting::OAuthTokenGetter> oauth_tokenGetter( + new remoting::OAuthTokenGetterImpl( + std::move(oauth_credentials), + [RemotingService SharedInstance].runtime->url_requester(), + /*auto_refresh=*/true)); + return oauth_tokenGetter; +} + +@interface RemotingAuthentication () { + std::unique_ptr<remoting::OAuthTokenGetter> _tokenGetter; + KeychainWrapper* _keychainWrapper; + BOOL _firstLoadUserAttempt; +} +@end + +@implementation RemotingAuthentication + +@synthesize user = _user; +@synthesize delegate = _delegate; + +- (instancetype)init { + self = [super init]; + if (self) { + _keychainWrapper = [[KeychainWrapper alloc] init]; + _user = nil; + _firstLoadUserAttempt = YES; + } + return self; +} + +#pragma mark - Property Overrides + +- (UserInfo*)user { + if (_firstLoadUserAttempt && _user == nil) { + _firstLoadUserAttempt = NO; + [self setUser:[self loadUserInfo]]; + } + return _user; +} + +- (void)setUser:(UserInfo*)user { + _user = user; + [self storeUserInfo:_user]; + [_delegate userDidUpdate:_user]; +} + +#pragma mark - Class Implementation + +- (void)authenticateWithAuthorizationCode:(NSString*)authorizationCode { + __weak RemotingAuthentication* weakSelf = self; + _tokenGetter = CreateOAuthTokenGetterWithAuthorizationCode( + std::string(base::SysNSStringToUTF8(authorizationCode)), + base::BindBlockArc( + ^(const std::string& user_email, const std::string& refresh_token) { + // TODO(nicholss): Do something with these new creds. + VLOG(1) << "New Creds: " << user_email << " " << refresh_token; + UserInfo* user = [[UserInfo alloc] init]; + user.userEmail = base::SysUTF8ToNSString(user_email); + user.refreshToken = base::SysUTF8ToNSString(refresh_token); + [weakSelf setUser:user]; + })); + // Stimulate the oAuth Token Getter to fetch and access token, this forces it + // to convert the authorization code into a refresh token, and saving the + // refresh token will happen automaticly in the above block. + [self callbackWithAccessToken:base::BindBlockArc(^( + remoting::OAuthTokenGetter::Status status, + const std::string& user_email, + const std::string& access_token) { + if (status == remoting::OAuthTokenGetter::Status::SUCCESS) { + VLOG(1) << "Success fetching access token from authorization code."; + } else { + LOG(ERROR) + << "Failed to fetch access token from authorization code. (" + << status << ")"; + // TODO(nicholss): Deal with the sad path for a bad auth token. + } + })]; +} + +#pragma mark - Private + +// Provide the |refreshToken| and |email| to authenticate a user as a returning +// user of the application. +- (void)authenticateWithRefreshToken:(NSString*)refreshToken + email:(NSString*)email { + _tokenGetter = CreateOAuthTokenWithRefreshToken( + std::string(base::SysNSStringToUTF8(refreshToken)), + base::SysNSStringToUTF8(email)); +} + +- (void)callbackWithAccessToken: + (const remoting::OAuthTokenGetter::TokenCallback&)onAccessToken { + // TODO(nicholss): Be careful here since a failure to reset onAccessToken + // will end up with retain cycle and memory leakage. + if (_tokenGetter) { + _tokenGetter->CallWithToken(onAccessToken); + } +} + +- (void)logout { + [self storeUserInfo:nil]; + [self setUser:nil]; +} + +#pragma mark - Persistence + +- (void)storeUserInfo:(UserInfo*)user { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + if (user) { + [defaults setObject:user.userEmail forKey:kCRDAuthenticatedUserEmailKey]; + // TODO(nicholss): Need to match the token with the email. + [_keychainWrapper setRefreshToken:user.refreshToken]; + } else { + [defaults removeObjectForKey:kCRDAuthenticatedUserEmailKey]; + [_keychainWrapper resetKeychainItem]; + } + [defaults synchronize]; +} + +- (UserInfo*)loadUserInfo { + UserInfo* user = [[UserInfo alloc] init]; + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + user.userEmail = [defaults objectForKey:kCRDAuthenticatedUserEmailKey]; + // TODO(nicholss): Need to match the token with the email. + user.refreshToken = [_keychainWrapper refreshToken]; + + if (!user || ![user isAuthenticated]) { + user = nil; + } else { + [self authenticateWithRefreshToken:user.refreshToken email:user.userEmail]; + } + return user; +} + +@end
diff --git a/remoting/client/ios/facade/remoting_service.h b/remoting/client/ios/facade/remoting_service.h index 2f27fba..2a65639c 100644 --- a/remoting/client/ios/facade/remoting_service.h +++ b/remoting/client/ios/facade/remoting_service.h
@@ -6,29 +6,22 @@ #define REMOTING_CLIENT_IOS_FACADE_REMOTING_SERVICE_H_ #import "remoting/client/chromoting_client_runtime.h" -#import "remoting/client/ios/domain/host_info.h" -#import "remoting/client/ios/domain/user_info.h" #include "base/memory/weak_ptr.h" #include "remoting/base/oauth_token_getter.h" -// |RemotingAuthenticationDelegate|s are interested in authentication related -// notifications. -@protocol RemotingAuthenticationDelegate<NSObject> +@class HostInfo; +@class UserInfo; +@class RemotingAuthentication; -// Notifies the delegate that the authentication status of the current user has -// changed to a new state. -- (void)nowAuthenticated:(BOOL)authenticated; +// Eventing related keys: -@end - -// |RemotingHostListDelegate|s are interested in notifications related to host -// list. -@protocol RemotingHostListDelegate<NSObject> - -- (void)hostListUpdated; - -@end +// Hosts did update event. +extern NSString* const kHostsDidUpdate; +// User did update event name. +extern NSString* const kUserDidUpdate; +// Map key for UserInfo object. +extern NSString* const kUserInfo; // |RemotingService| is the centralized place to ask for information about // authentication or query the remote services. It also helps deal with the @@ -39,38 +32,18 @@ // Access to the singleton shared instance from this method. + (RemotingService*)SharedInstance; -// Access to the current |ChromotingClientRuntime| from this method. -- (remoting::ChromotingClientRuntime*)runtime; +// Start a request to fetch the host list. This will produce an notification on +// |kHostsDidUpdate| when a new host is ready. +- (void)requestHostListFetch; -// Register to be a |RemotingAuthenticationDelegate|. -- (void)setAuthenticationDelegate:(id<RemotingAuthenticationDelegate>)delegate; +@property(nonatomic, readonly) RemotingAuthentication* authentication; -// A cached answer if there is a currently authenticated user. -- (BOOL)isAuthenticated; +// Returns the current host list. +@property(nonatomic, readonly) NSArray<HostInfo*>* hosts; -// Provide an |authorizationCode| to authenticate a user as the first time user -// of the application or OAuth Flow. -- (void)authenticateWithAuthorizationCode:(NSString*)authorizationCode; - -// Provide the |refreshToken| and |email| to authenticate a user as a returning -// user of the application. -- (void)authenticateWithRefreshToken:(NSString*)refreshToken - email:(NSString*)email; - -// Returns the currently logged in user info from cache, or nil if no -// currently authenticated user. -- (UserInfo*)getUser; - -// Register to be a |RemotingHostListDelegate|. Side effect of setting this -// delegate is the application will attempt to fetch a fresh host list. -- (void)setHostListDelegate:(id<RemotingHostListDelegate>)delegate; - -// Returns the currently cached host list or nil if none exist. -- (NSArray<HostInfo*>*)getHosts; - -// Fetches an OAuth Access Token and passes it back to the callback. -- (void)callbackWithAccessToken: - (const remoting::OAuthTokenGetter::TokenCallback&)onAccessToken; +// The Chromoting Client Runtime, this holds the threads and other shared +// resources used by the Chromoting clients +@property(nonatomic, readonly) remoting::ChromotingClientRuntime* runtime; @end
diff --git a/remoting/client/ios/facade/remoting_service.mm b/remoting/client/ios/facade/remoting_service.mm index f30a823..20f499fa 100644 --- a/remoting/client/ios/facade/remoting_service.mm +++ b/remoting/client/ios/facade/remoting_service.mm
@@ -9,78 +9,44 @@ #import "remoting/client/ios/facade/remoting_service.h" #import <Foundation/Foundation.h> +#import <Security/Security.h> #import "base/mac/bind_objc_block.h" +#import "remoting/client/ios/domain/host_info.h" +#import "remoting/client/ios/domain/user_info.h" +#import "remoting/client/ios/facade/host_info.h" +#import "remoting/client/ios/facade/host_list_fetcher.h" +#import "remoting/client/ios/facade/ios_client_runtime_delegate.h" +#import "remoting/client/ios/facade/remoting_authentication.h" +#import "remoting/client/ios/facade/remoting_service.h" +#import "remoting/client/ios/keychain_wrapper.h" #include "base/logging.h" #include "base/strings/sys_string_conversions.h" #include "net/url_request/url_request_context_getter.h" #include "remoting/base/oauth_token_getter.h" #include "remoting/base/oauth_token_getter_impl.h" -#include "remoting/client/ios/facade/host_info.h" -#include "remoting/client/ios/facade/host_list_fetcher.h" -#include "remoting/client/ios/facade/ios_client_runtime_delegate.h" -const char kOauthRedirectUrl[] = - "https://chromoting-oauth.talkgadget." - "google.com/talkgadget/oauth/chrome-remote-desktop/dev"; +static NSString* const kCRDAuthenticatedUserEmailKey = + @"kCRDAuthenticatedUserEmailKey"; -std::unique_ptr<remoting::OAuthTokenGetter> -CreateOAuthTokenGetterWithAuthorizationCode( - const std::string& auth_code, - const remoting::OAuthTokenGetter::CredentialsUpdatedCallback& - on_credentials_update) { - std::unique_ptr<remoting::OAuthTokenGetter::OAuthIntermediateCredentials> - oauth_credentials( - new remoting::OAuthTokenGetter::OAuthIntermediateCredentials( - auth_code, /*is_service_account=*/false)); - oauth_credentials->oauth_redirect_uri = kOauthRedirectUrl; +NSString* const kHostsDidUpdate = @"kHostsDidUpdate"; - std::unique_ptr<remoting::OAuthTokenGetter> oauth_tokenGetter( - new remoting::OAuthTokenGetterImpl( - std::move(oauth_credentials), on_credentials_update, - [[RemotingService SharedInstance] runtime]->url_requester(), - /*auto_refresh=*/true)); - return oauth_tokenGetter; -} +NSString* const kUserDidUpdate = @"kUserDidUpdate"; +NSString* const kUserInfo = @"kUserInfo"; -std::unique_ptr<remoting::OAuthTokenGetter> CreateOAuthTokenWithRefreshToken( - const std::string& refresh_token, - const std::string& email) { - std::unique_ptr<remoting::OAuthTokenGetter::OAuthAuthorizationCredentials> - oauth_credentials( - new remoting::OAuthTokenGetter::OAuthAuthorizationCredentials( - email, refresh_token, /*is_service_account=*/false)); - - std::unique_ptr<remoting::OAuthTokenGetter> oauth_tokenGetter( - new remoting::OAuthTokenGetterImpl( - std::move(oauth_credentials), - [[RemotingService SharedInstance] runtime]->url_requester(), - /*auto_refresh=*/true)); - return oauth_tokenGetter; -} - -@interface RemotingService () { +@interface RemotingService ()<RemotingAuthenticationDelegate> { std::unique_ptr<remoting::OAuthTokenGetter> _tokenGetter; - UserInfo* _user; - NSArray<HostInfo*>* _hosts; - id<RemotingAuthenticationDelegate> _authDelegate; - id<RemotingHostListDelegate> _hostListDelegate; remoting::HostListFetcher* _hostListFetcher; remoting::IosClientRuntimeDelegate* _clientRuntimeDelegate; } - @end -// -// RemodingService will act as the facade to the C++ layer that has not been -// implemented/integrated yet. -// TODO(nicholss): Implement/Integrate this class. At the moment it is being -// used to generate fake data to implement the UI of the app. -// Update: Half implemented now. User is still fake, but now real hosts lists. -// @implementation RemotingService +@synthesize authentication = _authentication; +@synthesize hosts = _hosts; + // RemotingService is a singleton. + (RemotingService*)SharedInstance { static RemotingService* sharedInstance = nil; @@ -94,10 +60,10 @@ - (instancetype)init { self = [super init]; if (self) { - _user = nil; + _authentication = [[RemotingAuthentication alloc] init]; + _authentication.delegate = self; _hosts = nil; - _hostListFetcher = new remoting::HostListFetcher( - remoting::ChromotingClientRuntime::GetInstance()->url_requester()); + _hostListFetcher = nil; // TODO(nicholss): This might need a pointer back to the service. _clientRuntimeDelegate = new remoting::IosClientRuntimeDelegate(); @@ -108,161 +74,103 @@ #pragma mark - RemotingService Implementation -// TODO(nicholss): isAuthenticated needs to just kick off a request to -// authenticate a user. and more than one controller might want to be a delegate -// for this info so need to change this to be more of the registration types. -// The remoting_service might also want to be registered for authentication -// changes and it can update it's cache as it needs. - -- (void)setAuthenticationDelegate:(id<RemotingAuthenticationDelegate>)delegate { - _authDelegate = delegate; - if (_authDelegate) { - [_authDelegate nowAuthenticated:[self isAuthenticated]]; - } - if (!_user && _tokenGetter) { - _tokenGetter->CallWithToken(base::BindBlockArc( - ^(remoting::OAuthTokenGetter::Status status, - const std::string& user_email, const std::string& access_token) { - if (status == remoting::OAuthTokenGetter::Status::SUCCESS) { - _user = [[UserInfo alloc] init]; - _user.userEmail = - [NSString stringWithCString:user_email.c_str() - encoding:[NSString defaultCStringEncoding]]; - } else { - _user = nil; - } - if (_authDelegate) { - [_authDelegate nowAuthenticated:[self isAuthenticated]]; - } - })); - } -} - -- (BOOL)isAuthenticated { - if (_user) { - return YES; - } - return NO; -} - - (void)startHostListFetchWith:(NSString*)accessToken { - NSLog(@"startHostListFetchWith : %@ %@", accessToken, _authDelegate); - if (_authDelegate) { - [_authDelegate nowAuthenticated:YES]; - - _hostListFetcher->RetrieveHostlist( - base::SysNSStringToUTF8(accessToken), - base::BindBlockArc(^(const std::vector<remoting::HostInfo>& hostlist) { - NSMutableArray<HostInfo*>* hosts = - [NSMutableArray arrayWithCapacity:hostlist.size()]; - std::string status; - for (const remoting::HostInfo& host_info : hostlist) { - remoting::HostStatus host_status = host_info.status; - switch (host_status) { - case remoting::kHostStatusOnline: - status = "ONLINE"; - break; - case remoting::kHostStatusOffline: - status = "OFFLINE"; - break; - default: - NOTREACHED(); - } - // TODO(nicholss): Not yet integrated: createdTime, hostVersion, - // kind, offlineReason. Add them as the app will need this info. - HostInfo* host = [[HostInfo alloc] init]; - host.hostId = - [NSString stringWithCString:host_info.host_id.c_str() - encoding:[NSString defaultCStringEncoding]]; - host.hostName = - [NSString stringWithCString:host_info.host_name.c_str() - encoding:[NSString defaultCStringEncoding]]; - host.jabberId = - [NSString stringWithCString:host_info.host_jid.c_str() - encoding:[NSString defaultCStringEncoding]]; - host.publicKey = - [NSString stringWithCString:host_info.public_key.c_str() - encoding:[NSString defaultCStringEncoding]]; - host.status = - [NSString stringWithCString:status.c_str() - encoding:[NSString defaultCStringEncoding]]; - [hosts addObject:host]; + if (!_hostListFetcher) { + _hostListFetcher = new remoting::HostListFetcher( + remoting::ChromotingClientRuntime::GetInstance()->url_requester()); + } + _hostListFetcher->RetrieveHostlist( + base::SysNSStringToUTF8(accessToken), + base::BindBlockArc(^(const std::vector<remoting::HostInfo>& hostlist) { + NSMutableArray<HostInfo*>* hosts = + [NSMutableArray arrayWithCapacity:hostlist.size()]; + std::string status; + for (const remoting::HostInfo& host_info : hostlist) { + remoting::HostStatus host_status = host_info.status; + switch (host_status) { + case remoting::kHostStatusOnline: + status = "ONLINE"; + break; + case remoting::kHostStatusOffline: + status = "OFFLINE"; + break; + default: + NOTREACHED(); } - _hosts = hosts; - [_hostListDelegate hostListUpdated]; - })); - } -} - -- (void)authenticateWithAuthorizationCode:(NSString*)authorizationCode { - _tokenGetter = CreateOAuthTokenGetterWithAuthorizationCode( - std::string(base::SysNSStringToUTF8(authorizationCode)), - base::BindBlockArc( - ^(const std::string& user_email, const std::string& refresh_token) { - // TODO(nicholss): Do something with these new creds. - VLOG(1) << "New Creds: " << user_email << " " << refresh_token; - })); -} - -- (void)authenticateWithRefreshToken:(NSString*)refreshToken - email:(NSString*)email { - _tokenGetter = CreateOAuthTokenWithRefreshToken( - std::string(base::SysNSStringToUTF8(refreshToken)), - base::SysNSStringToUTF8(email)); -} - -- (UserInfo*)getUser { - if (![self isAuthenticated]) { - return nil; - } - - NSMutableString* json = [[NSMutableString alloc] init]; - [json appendString:@"{"]; - [json appendString:@"\"userId\":\"AABBCC123\","]; - [json appendString:@"\"userFullName\":\"John Smith\","]; - [json appendString:@"\"userEmail\":\"john@example.com\","]; - [json appendString:@"}"]; - - NSMutableData* data = [NSMutableData - dataWithData:[[json copy] dataUsingEncoding:NSUTF8StringEncoding]]; - - UserInfo* user = [UserInfo parseListFromJSON:data]; - return user; -} - -- (void)setHostListDelegate:(id<RemotingHostListDelegate>)delegate { - bool attemptUpdate = (_hostListDelegate != delegate); - _hostListDelegate = delegate; - if (attemptUpdate && _hostListDelegate && _tokenGetter) { - // TODO(nicholss): It might be cleaner to set the delegate and then have - // them ask to refresh the host list rather than start this get hosts call. - _tokenGetter->CallWithToken(base::BindBlockArc( - ^(remoting::OAuthTokenGetter::Status status, - const std::string& user_email, const std::string& access_token) { - NSString* accessToken = - [NSString stringWithCString:access_token.c_str() + // TODO(nicholss): Not yet integrated: createdTime, hostVersion, + // kind, offlineReason. Add them as the app will need this info. + HostInfo* host = [[HostInfo alloc] init]; + host.hostId = + [NSString stringWithCString:host_info.host_id.c_str() encoding:[NSString defaultCStringEncoding]]; - [self startHostListFetchWith:accessToken]; - })); - } + host.hostName = + [NSString stringWithCString:host_info.host_name.c_str() + encoding:[NSString defaultCStringEncoding]]; + host.jabberId = + [NSString stringWithCString:host_info.host_jid.c_str() + encoding:[NSString defaultCStringEncoding]]; + host.publicKey = + [NSString stringWithCString:host_info.public_key.c_str() + encoding:[NSString defaultCStringEncoding]]; + host.status = + [NSString stringWithCString:status.c_str() + encoding:[NSString defaultCStringEncoding]]; + [hosts addObject:host]; + } + _hosts = hosts; + [self hostListUpdated]; + })); } -- (NSArray<HostInfo*>*)getHosts { - if (![self isAuthenticated]) { - return nil; +#pragma mark - Notifications + +- (void)hostListUpdated { + [[NSNotificationCenter defaultCenter] postNotificationName:kHostsDidUpdate + object:self + userInfo:nil]; +} + +#pragma mark - RemotingAuthenticationDelegate + +- (void)userDidUpdate:(UserInfo*)user { + NSDictionary* userInfo = nil; + if (user) { + userInfo = [NSDictionary dictionaryWithObject:user forKey:kUserInfo]; + } else { + _hosts = nil; + [self hostListUpdated]; } - return _hosts; + [[NSNotificationCenter defaultCenter] postNotificationName:kUserDidUpdate + object:self + userInfo:userInfo]; +} + +#pragma mark - Properties + +- (NSArray<HostInfo*>*)hosts { + if ([_authentication.user isAuthenticated]) { + return _hosts; + } + return nil; } - (remoting::ChromotingClientRuntime*)runtime { return remoting::ChromotingClientRuntime::GetInstance(); } -- (void)callbackWithAccessToken: - (const remoting::OAuthTokenGetter::TokenCallback&)onAccessToken { - if (_tokenGetter) { - _tokenGetter->CallWithToken(onAccessToken); - } +#pragma mark - Implementation + +- (void)requestHostListFetch { + [_authentication + callbackWithAccessToken:base::BindBlockArc(^( + remoting::OAuthTokenGetter::Status status, + const std::string& user_email, + const std::string& access_token) { + NSString* accessToken = + [NSString stringWithCString:access_token.c_str() + encoding:[NSString defaultCStringEncoding]]; + [self startHostListFetchWith:accessToken]; + })]; } @end
diff --git a/remoting/client/ios/keychain_wrapper.h b/remoting/client/ios/keychain_wrapper.h new file mode 100644 index 0000000..d92b6ae --- /dev/null +++ b/remoting/client/ios/keychain_wrapper.h
@@ -0,0 +1,26 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_CLIENT_IOS_KEYCHAIN_WRAPPER_H_ +#define REMOTING_CLIENT_IOS_KEYCHAIN_WRAPPER_H_ + +#import <Foundation/Foundation.h> + +@class UserInfo; + +// Class to abstract the details from how iOS wants to write to the keychain. +// TODO(nicholss): This will have to be futher refactored when we integrate +// with the private Google auth. +@interface KeychainWrapper : NSObject + +// Save a refresh token to the keychain. +- (void)setRefreshToken:(NSString*)refreshToken; +// Get the refresh token from the keychain, if there is one. +- (NSString*)refreshToken; +// Reset the keychain and the cache. +- (void)resetKeychainItem; + +@end + +#endif // REMOTING_CLIENT_IOS_KEYCHAIN_WRAPPER_H_
diff --git a/remoting/client/ios/keychain_wrapper.mm b/remoting/client/ios/keychain_wrapper.mm new file mode 100644 index 0000000..c1ae602 --- /dev/null +++ b/remoting/client/ios/keychain_wrapper.mm
@@ -0,0 +1,206 @@ +// 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. + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "remoting/client/ios/keychain_wrapper.h" + +#import "remoting/client/ios/domain/host_info.h" + +static const UInt8 kKeychainItemIdentifier[] = "org.chromium.RemoteDesktop\0"; + +@interface KeychainWrapper () { + NSMutableDictionary* _keychainData; + NSMutableDictionary* _userInfoQuery; +} +@end + +@implementation KeychainWrapper + +- (id)init { + if ((self = [super init])) { + OSStatus keychainErr = noErr; + _userInfoQuery = [[NSMutableDictionary alloc] init]; + [_userInfoQuery setObject:(__bridge id)kSecClassGenericPassword + forKey:(__bridge id)kSecClass]; + NSData* keychainItemID = + [NSData dataWithBytes:kKeychainItemIdentifier + length:strlen((const char*)kKeychainItemIdentifier)]; + [_userInfoQuery setObject:keychainItemID + forKey:(__bridge id)kSecAttrGeneric]; + [_userInfoQuery setObject:(__bridge id)kSecMatchLimitOne + forKey:(__bridge id)kSecMatchLimit]; + [_userInfoQuery setObject:(__bridge id)kCFBooleanTrue + forKey:(__bridge id)kSecReturnAttributes]; + + CFMutableDictionaryRef outDictionary = nil; + keychainErr = SecItemCopyMatching((__bridge CFDictionaryRef)_userInfoQuery, + (CFTypeRef*)&outDictionary); + if (keychainErr == noErr) { + _keychainData = [self + secItemFormatToDictionary:(__bridge_transfer NSMutableDictionary*) + outDictionary]; + } else if (keychainErr == errSecItemNotFound) { + [self resetKeychainItem]; + + if (outDictionary) { + CFRelease(outDictionary); + _keychainData = nil; + } + } else { + NSLog(@"Serious error."); + if (outDictionary) { + CFRelease(outDictionary); + _keychainData = nil; + } + } + } + return self; +} + +- (void)setRefreshToken:(NSString*)refreshToken { + [self setObject:refreshToken forKey:(__bridge id)kSecValueData]; +} + +- (NSString*)refreshToken { + return [self objectForKey:(__bridge id)kSecValueData]; +} + +// Implement the mySetObject:forKey method, which writes attributes to the +// keychain: +- (void)setObject:(id)inObject forKey:(id)key { + if (inObject == nil) + return; + id currentObject = [_keychainData objectForKey:key]; + if (![currentObject isEqual:inObject]) { + [_keychainData setObject:inObject forKey:key]; + [self writeToKeychain]; + } +} + +// Implement the myObjectForKey: method, which reads an attribute value from a +// dictionary: +- (id)objectForKey:(id)key { + return [_keychainData objectForKey:key]; +} + +- (void)resetKeychainItem { + if (!_keychainData) { + _keychainData = [[NSMutableDictionary alloc] init]; + } else if (_keychainData) { + NSMutableDictionary* tmpDictionary = + [self dictionaryToSecItemFormat:_keychainData]; + OSStatus errorcode = SecItemDelete((__bridge CFDictionaryRef)tmpDictionary); + if (errorcode == errSecItemNotFound) { + // this is ok. + } else if (errorcode != noErr) { + NSLog(@"Problem deleting current keychain item."); + } + } + + [_keychainData setObject:@"gaia_refresh_token" + forKey:(__bridge id)kSecAttrLabel]; + [_keychainData setObject:@"Gaia fresh token" + forKey:(__bridge id)kSecAttrDescription]; + [_keychainData setObject:@"" forKey:(__bridge id)kSecValueData]; +} + +- (NSMutableDictionary*)dictionaryToSecItemFormat: + (NSDictionary*)dictionaryToConvert { + NSMutableDictionary* returnDictionary = + [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; + + NSData* keychainItemID = + [NSData dataWithBytes:kKeychainItemIdentifier + length:strlen((const char*)kKeychainItemIdentifier)]; + [returnDictionary setObject:keychainItemID + forKey:(__bridge id)kSecAttrGeneric]; + [returnDictionary setObject:(__bridge id)kSecClassGenericPassword + forKey:(__bridge id)kSecClass]; + + NSString* passwordString = + [dictionaryToConvert objectForKey:(__bridge id)kSecValueData]; + [returnDictionary + setObject:[passwordString dataUsingEncoding:NSUTF8StringEncoding] + forKey:(__bridge id)kSecValueData]; + return returnDictionary; +} + +- (NSMutableDictionary*)secItemFormatToDictionary: + (NSDictionary*)dictionaryToConvert { + NSMutableDictionary* returnDictionary = + [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; + + [returnDictionary setObject:(__bridge id)kCFBooleanTrue + forKey:(__bridge id)kSecReturnData]; + [returnDictionary setObject:(__bridge id)kSecClassGenericPassword + forKey:(__bridge id)kSecClass]; + + CFDataRef passwordData = NULL; + OSStatus keychainError = noErr; + keychainError = SecItemCopyMatching( + (__bridge CFDictionaryRef)returnDictionary, (CFTypeRef*)&passwordData); + if (keychainError == noErr) { + [returnDictionary removeObjectForKey:(__bridge id)kSecReturnData]; + + NSString* password = [[NSString alloc] + initWithBytes:[(__bridge_transfer NSData*)passwordData bytes] + length:[(__bridge NSData*)passwordData length] + encoding:NSUTF8StringEncoding]; + [returnDictionary setObject:password forKey:(__bridge id)kSecValueData]; + } else if (keychainError == errSecItemNotFound) { + NSLog(@"Nothing was found in the keychain."); + if (passwordData) { + CFRelease(passwordData); + passwordData = nil; + } + } else { + NSLog(@"Serious error.\n"); + if (passwordData) { + CFRelease(passwordData); + passwordData = nil; + } + } + return returnDictionary; +} + +- (void)writeToKeychain { + CFDictionaryRef attributes = nil; + NSMutableDictionary* updateItem = nil; + + if (SecItemCopyMatching((__bridge CFDictionaryRef)_userInfoQuery, + (CFTypeRef*)&attributes) == noErr) { + updateItem = [NSMutableDictionary + dictionaryWithDictionary:(__bridge_transfer NSDictionary*)attributes]; + + [updateItem setObject:[_userInfoQuery objectForKey:(__bridge id)kSecClass] + forKey:(__bridge id)kSecClass]; + + NSMutableDictionary* tempCheck = + [self dictionaryToSecItemFormat:_keychainData]; + [tempCheck removeObjectForKey:(__bridge id)kSecClass]; + + OSStatus errorcode = SecItemUpdate((__bridge CFDictionaryRef)updateItem, + (__bridge CFDictionaryRef)tempCheck); + if (errorcode != noErr) { + NSLog(@"Couldn't update the Keychain Item. %d", (int)errorcode); + } + } else { + OSStatus errorcode = + SecItemAdd((__bridge CFDictionaryRef) + [self dictionaryToSecItemFormat:_keychainData], + NULL); + if (errorcode != noErr) { + NSLog(@"Couldn't add the Keychain Item. %d", (int)errorcode); + } + if (attributes) { + CFRelease(attributes); + attributes = nil; + } + } +} + +@end
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json index fd58647a..061f659 100644 --- a/testing/buildbot/chromium.perf.fyi.json +++ b/testing/buildbot/chromium.perf.fyi.json
@@ -1598,124 +1598,6 @@ }, { "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=android-chromium" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "android_devices": "1", - "id": "build249-m4--device6", - "os": "Android", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "android_devices": "1", - "id": "build249-m4--device6", - "os": "Android", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=android-chromium" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "android_devices": "1", - "id": "build245-m4--device5", - "os": "Android", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "android_devices": "1", - "id": "build245-m4--device5", - "os": "Android", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -7906,183 +7788,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build142-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build142-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build141-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build141-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build148-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build148-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -8201,65 +7906,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build149-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:22b1", - "id": "build149-b1", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -14351,183 +13997,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build206-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build206-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build205-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build205-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build212-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build212-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -14646,65 +14115,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build213-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:9874", - "id": "build213-b4", - "os": "Windows-10-10586", - "pool": "Chrome-perf-fyi" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results",
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index c66990f..3f311cb 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -1665,124 +1665,6 @@ }, { "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=android-chromium" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "android_devices": "1", - "id": "build75-b1--device6", - "os": "Android", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "android_devices": "1", - "id": "build75-b1--device6", - "os": "Android", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=android-chromium" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "android_devices": "1", - "id": "build73-b1--device5", - "os": "Android", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "android_devices": "1", - "id": "build73-b1--device5", - "os": "Android", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -7953,183 +7835,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build151-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build151-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build152-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build152-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build149-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build149-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -8248,65 +7953,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build149-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build149-m1", - "os": "Ubuntu-14.04", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -14398,183 +14044,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build105-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build105-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build106-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build106-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build103-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build103-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -14693,65 +14162,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build103-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0166", - "id": "build103-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -20823,183 +20233,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build161-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build161-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build162-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build162-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build159-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build159-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -21118,65 +20351,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build159-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a2e", - "id": "build159-m1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -27228,183 +26402,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build126-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build126-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build127-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build127-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build124-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build124-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -27523,65 +26520,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build124-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1626", - "id": "build124-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -33633,183 +32571,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build27-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build27-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build28-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build28-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build25-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build25-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -33928,65 +32689,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build25-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0a26", - "id": "build25-b1", - "os": "Mac-10.12", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -40038,183 +38740,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build131-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build131-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build132-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build132-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build129-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build129-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -40333,65 +38858,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build129-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6821", - "id": "build129-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -46443,183 +44909,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build7-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build7-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build8-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build8-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build5-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build5-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -46738,65 +45027,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build5-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:0d26", - "id": "build5-b1", - "os": "Mac-10.11", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -52848,183 +51078,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build120-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build120-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build180-b4", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build180-b4", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build118-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build118-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -53143,65 +51196,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build118-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:1616", - "id": "build118-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -59253,183 +57247,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build135-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build135-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build136-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build136-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build133-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build133-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -59548,65 +57365,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build133-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0534", - "id": "build133-m1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -65718,183 +63476,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build104-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build104-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build105-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build105-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build102-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build102-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -66013,65 +63594,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build102-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "1002:6613", - "id": "build102-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -72203,183 +69725,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build167-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build167-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build168-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build168-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build165-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build165-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -72498,65 +69843,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build165-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:041a", - "id": "build165-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -78668,183 +75954,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build95-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build95-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build96-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build96-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build93-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build93-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -78963,65 +76072,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build93-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "10de:104a", - "id": "build93-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -85133,183 +82183,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build188-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build188-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build189-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build189-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build186-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build186-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -85428,65 +82301,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build186-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build186-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -91598,183 +88412,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build141-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build141-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build142-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build142-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build139-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build139-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -91893,65 +88530,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build139-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build139-m1", - "os": "Windows-2008ServerR2-SP1", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -98043,183 +94621,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build146-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build146-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build147-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build147-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build144-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build144-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -98338,65 +94739,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build144-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "102b:0532", - "id": "build144-m1", - "os": "Windows-2012ServerR2-SP0", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results", @@ -104488,183 +100830,6 @@ }, { "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:161e", - "id": "build33-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.android.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.android.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:161e", - "id": "build33-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:161e", - "id": "build34-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:161e", - "id": "build34-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:161e", - "id": "build31-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.chromeOS4kOnly.tough_video_cases", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.chromeOS4kOnly.tough_video_cases.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:161e", - "id": "build31-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.mse_cases", "-v", "--upload-results", @@ -104783,65 +100948,6 @@ }, { "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=release_x64" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:161e", - "id": "build31-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": false, - "io_timeout": 3600 - } - }, - { - "args": [ - "media.tough_video_cases_extra", - "-v", - "--upload-results", - "--output-format=chartjson", - "--browser=reference", - "--output-trace-tag=_ref" - ], - "isolate_name": "telemetry_perf_tests", - "name": "media.tough_video_cases_extra.reference", - "override_compile_targets": [ - "telemetry_perf_tests" - ], - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "gpu": "8086:161e", - "id": "build31-b1", - "os": "Windows-10-10240", - "pool": "Chrome-perf" - } - ], - "expiration": 36000, - "hard_timeout": 7200, - "ignore_task_failure": true, - "io_timeout": 3600 - } - }, - { - "args": [ "media.tough_video_cases_tbmv2", "-v", "--upload-results",
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations index 8a9f527..1346078 100644 --- a/third_party/WebKit/LayoutTests/W3CImportExpectations +++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -291,6 +291,8 @@ external/wpt/imagebitmap-renderingcontext [ Skip ] ## Owners: smcgruer@chromium.org # external/wpt/infrastructure [ Pass ] +## Owners: none; No tests in the directory. +# external/wpt/interfaces [ Pass ] ## Owners: dom-dev@chromium.org # external/wpt/innerText [ Pass ] external/wpt/js [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/credential-management/idl.https.html b/third_party/WebKit/LayoutTests/external/wpt/credential-management/idl.https.html index bc779d0..5ccc0c9 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/credential-management/idl.https.html +++ b/third_party/WebKit/LayoutTests/external/wpt/credential-management/idl.https.html
@@ -14,26 +14,25 @@ readonly attribute DOMString type; }; - dictionary SiteBoundCredentialData : CredentialData { - USVString name; - USVString iconURL; - }; - [NoInterfaceObject, SecureContext] interface CredentialUserData { readonly attribute USVString name; readonly attribute USVString iconURL; }; - dictionary PasswordCredentialData : SiteBoundCredentialData { - USVString password; + dictionary PasswordCredentialData : CredentialData { + USVString name; + USVString iconURL; + required USVString password; }; typedef (FormData or URLSearchParams) CredentialBodyType; - dictionary FederatedCredentialData : SiteBoundCredentialData { - USVString provider; + dictionary FederatedCredentialInit : CredentialData { + USVString name; + USVString iconURL; + required USVString provider; DOMString protocol; }; @@ -69,7 +68,7 @@ }; PasswordCredential implements CredentialUserData; - [Constructor(FederatedCredentialData data), + [Constructor(FederatedCredentialInit data), Exposed=Window, SecureContext] interface FederatedCredential : Credential {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/remoteplayback.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/remoteplayback.idl new file mode 100644 index 0000000..598bf30b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/remoteplayback.idl
@@ -0,0 +1,23 @@ +enum RemotePlaybackState { + "connecting", + "connected", + "disconnected" +}; + +callback RemotePlaybackAvailabilityCallback = void(boolean available); + +interface RemotePlayback : EventTarget { + readonly attribute RemotePlaybackState state; + attribute EventHandler onconnecting; + attribute EventHandler onconnect; + attribute EventHandler ondisconnect; + + Promise<long> watchAvailability(RemotePlaybackAvailabilityCallback callback); + Promise<void> cancelWatchAvailability(optional long id); + Promise<void> prompt(); +}; + +partial interface HTMLMediaElement { + readonly attribute RemotePlayback remote; + attribute boolean disableRemotePlayback; +};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html index 9d68b21..bb6dcc42 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html +++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html
@@ -32,9 +32,11 @@ }); on_event(target0, "pointerleave", function (event) { - detected_pointertypes[event.pointerType] = true; - check_PointerEvent(event); count++; + detected_pointertypes[event.pointerType] = true; + if (count == 1) + check_PointerEvent(event); + test_pointerEvent.step(function () { assert_equals(event.pointerType, "pen", "Test should be run using a pen as input"); assert_equals(event.type, "pointerleave", "The " + event.type + " event was received"); @@ -59,7 +61,7 @@ </h4> <br /> <div id="target0"> - Use a pen to hover over then lift up away from this element. + Use a pen to hover over then lift up away from this element, and repeat it again. </div> <div id="complete-notice"> <p>Test complete: Scroll to Summary to view Pass/Fail Results.</p> @@ -67,4 +69,4 @@ </div> <div id="log"></div> </body> -</html> \ No newline at end of file +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/remote-playback/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/idlharness.html new file mode 100644 index 0000000..bd9cbf6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/remote-playback/idlharness.html
@@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Remote Playback API IDL tests</title> +<link rel="help" href="https://w3c.github.io/remoteplayback/"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/WebIDLParser.js"></script> +<script src="/resources/idlharness.js"></script> +</head> +<body> +<h1>Remote Playback API IDL tests</h1> +<video id='media' width=10 height=10></video> +<pre id='untested_idl' style='display:none'> +interface EventHandler {}; +interface HTMLMediaElement : HTMLElement {}; +interface EventTarget {}; +</pre> +<script> +"use strict" +var idl_array = new IdlArray(); +function doTest(idl) { + idl_array.add_untested_idls(document.getElementById("untested_idl").textContent); + idl_array.add_idls(idl); + idl_array.add_objects({ + HTMLVideoElement: [document.getElementById("media")], + RemotePlayback: [document.getElementById("media").remote] + }); + idl_array.test(); +} + +promise_test(function() { + return fetch("/interfaces/remoteplayback.idl") + .then(response => response.text()) + .then(doTest); +}, "Test driver"); +</script> +<div id="log"></div> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OWNERS b/third_party/WebKit/LayoutTests/fast/canvas/OWNERS index 4af0e95a..14ca7d4e 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/OWNERS +++ b/third_party/WebKit/LayoutTests/fast/canvas/OWNERS
@@ -1 +1,2 @@ -# TEAM: graphics-dev@chromium.org +# TEAM: paint-dev@chromium.org +# COMPONENT: Blink>Canvas
diff --git a/third_party/WebKit/LayoutTests/web-animations-api/animation-ready-reject-script-forbidden.html b/third_party/WebKit/LayoutTests/web-animations-api/animation-ready-reject-script-forbidden.html new file mode 100644 index 0000000..a40fa0e --- /dev/null +++ b/third_party/WebKit/LayoutTests/web-animations-api/animation-ready-reject-script-forbidden.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<div id=element>x</div> +<style> + #element { + transition: transform 2000ms; + } +</style> +<script> + async_test(function(t) { + element.offsetTop; // Force recalc + element.style.transform = "rotateX(180deg)"; + element.offsetTop; // Force recalc + var animation = element.getAnimations()[0]; + return animation.ready.catch(function() { t.done(); }); + }); +</script> +<style> + * { content: ""; } +</style>
diff --git a/third_party/WebKit/Source/core/animation/Animation.cpp b/third_party/WebKit/Source/core/animation/Animation.cpp index b6aa9fa..1cbacd8 100644 --- a/third_party/WebKit/Source/core/animation/Animation.cpp +++ b/third_party/WebKit/Source/core/animation/Animation.cpp
@@ -1038,9 +1038,11 @@ if (new_play_state == kIdle) { if (animation_->ready_promise_->GetState() == AnimationPromise::kPending) { - animation_->ready_promise_->Reject(DOMException::Create(kAbortError)); + animation_->RejectAndResetPromiseMaybeAsync( + animation_->ready_promise_.Get()); + } else { + animation_->ready_promise_->Reset(); } - animation_->ready_promise_->Reset(); animation_->ResolvePromiseMaybeAsync(animation_->ready_promise_.Get()); } else if (old_play_state == kPending) { animation_->ResolvePromiseMaybeAsync(animation_->ready_promise_.Get()); @@ -1055,10 +1057,11 @@ if (new_play_state == kIdle) { if (animation_->finished_promise_->GetState() == AnimationPromise::kPending) { - animation_->finished_promise_->Reject( - DOMException::Create(kAbortError)); + animation_->RejectAndResetPromiseMaybeAsync( + animation_->finished_promise_.Get()); + } else { + animation_->finished_promise_->Reset(); } - animation_->finished_promise_->Reset(); } else if (new_play_state == kFinished) { animation_->ResolvePromiseMaybeAsync(animation_->finished_promise_.Get()); } else if (old_play_state == kFinished) { @@ -1150,6 +1153,22 @@ } } +void Animation::RejectAndResetPromise(AnimationPromise* promise) { + promise->Reject(DOMException::Create(kAbortError)); + promise->Reset(); +} + +void Animation::RejectAndResetPromiseMaybeAsync(AnimationPromise* promise) { + if (ScriptForbiddenScope::IsScriptForbidden()) { + TaskRunnerHelper::Get(TaskType::kDOMManipulation, GetExecutionContext()) + ->PostTask(BLINK_FROM_HERE, + WTF::Bind(&Animation::RejectAndResetPromise, + WrapPersistent(this), WrapPersistent(promise))); + } else { + RejectAndResetPromise(promise); + } +} + DEFINE_TRACE(Animation) { visitor->Trace(content_); visitor->Trace(timeline_);
diff --git a/third_party/WebKit/Source/core/animation/Animation.h b/third_party/WebKit/Source/core/animation/Animation.h index 32a9121..d95c92a0 100644 --- a/third_party/WebKit/Source/core/animation/Animation.h +++ b/third_party/WebKit/Source/core/animation/Animation.h
@@ -238,6 +238,8 @@ Member<Animation>, Member<DOMException>>; void ResolvePromiseMaybeAsync(AnimationPromise*); + void RejectAndResetPromise(AnimationPromise*); + void RejectAndResetPromiseMaybeAsync(AnimationPromise*); String id_;
diff --git a/third_party/WebKit/Source/core/exported/BUILD.gn b/third_party/WebKit/Source/core/exported/BUILD.gn index d7df8835..3ecd359 100644 --- a/third_party/WebKit/Source/core/exported/BUILD.gn +++ b/third_party/WebKit/Source/core/exported/BUILD.gn
@@ -7,6 +7,9 @@ sources = [ "SharedWorkerRepositoryClientImpl.cpp", "SharedWorkerRepositoryClientImpl.h", + "WebArrayBuffer.cpp", + "WebArrayBufferConverter.cpp", + "WebArrayBufferView.cpp", "WebAssociatedURLLoaderImpl.cpp", "WebAssociatedURLLoaderImpl.h", "WebBlob.cpp",
diff --git a/third_party/WebKit/Source/web/WebArrayBuffer.cpp b/third_party/WebKit/Source/core/exported/WebArrayBuffer.cpp similarity index 100% rename from third_party/WebKit/Source/web/WebArrayBuffer.cpp rename to third_party/WebKit/Source/core/exported/WebArrayBuffer.cpp
diff --git a/third_party/WebKit/Source/web/WebArrayBufferConverter.cpp b/third_party/WebKit/Source/core/exported/WebArrayBufferConverter.cpp similarity index 100% rename from third_party/WebKit/Source/web/WebArrayBufferConverter.cpp rename to third_party/WebKit/Source/core/exported/WebArrayBufferConverter.cpp
diff --git a/third_party/WebKit/Source/web/WebArrayBufferView.cpp b/third_party/WebKit/Source/core/exported/WebArrayBufferView.cpp similarity index 100% rename from third_party/WebKit/Source/web/WebArrayBufferView.cpp rename to third_party/WebKit/Source/core/exported/WebArrayBufferView.cpp
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.cpp index b3f3a4f..221aca3 100644 --- a/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.cpp +++ b/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.cpp
@@ -68,7 +68,7 @@ } // namespace ImageResourceContent::ImageResourceContent(PassRefPtr<blink::Image> image) - : image_(std::move(image)), is_refetchable_data_from_disk_cache_(true) { + : is_refetchable_data_from_disk_cache_(true), image_(std::move(image)) { DEFINE_STATIC_LOCAL(NullImageResourceInfo, null_info, (new NullImageResourceInfo())); info_ = &null_info;
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.h b/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.h index 6351b931..cd70475 100644 --- a/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.h +++ b/third_party/WebKit/Source/core/loader/resource/ImageResourceContent.h
@@ -202,22 +202,23 @@ : AutoReset(&content->is_add_remove_observer_prohibited_, true) {} }; - Member<ImageResourceInfo> info_; ResourceStatus content_status_ = ResourceStatus::kNotStarted; - RefPtr<blink::Image> image_; - - HashCountedSet<ImageResourceObserver*> observers_; - HashCountedSet<ImageResourceObserver*> finished_observers_; - - Image::SizeAvailability size_available_ = Image::kSizeUnavailable; - // Indicates if this resource's encoded image data can be purged and refetched // from disk cache to save memory usage. See crbug/664437. bool is_refetchable_data_from_disk_cache_; mutable bool is_add_remove_observer_prohibited_ = false; + Image::SizeAvailability size_available_ = Image::kSizeUnavailable; + + Member<ImageResourceInfo> info_; + + RefPtr<blink::Image> image_; + + HashCountedSet<ImageResourceObserver*> observers_; + HashCountedSet<ImageResourceObserver*> finished_observers_; + #if DCHECK_IS_ON() bool is_update_image_being_called_ = false; #endif
diff --git a/third_party/WebKit/Source/devtools/front_end/devices/DevicesView.js b/third_party/WebKit/Source/devtools/front_end/devices/DevicesView.js index 7dc3609..082c942 100644 --- a/third_party/WebKit/Source/devtools/front_end/devices/DevicesView.js +++ b/third_party/WebKit/Source/devtools/front_end/devices/DevicesView.js
@@ -151,10 +151,8 @@ * @param {!Common.Event} event */ _devicesDiscoveryConfigChanged(event) { - var discoverUsbDevices = /** @type {boolean} */ (event.data['discoverUsbDevices']); - var portForwardingEnabled = /** @type {boolean} */ (event.data['portForwardingEnabled']); - var portForwardingConfig = /** @type {!Adb.PortForwardingConfig} */ (event.data['portForwardingConfig']); - this._discoveryView.discoveryConfigChanged(discoverUsbDevices, portForwardingEnabled, portForwardingConfig); + var config = /** @type {!Adb.Config} */ (event.data); + this._discoveryView.discoveryConfigChanged(config); } /** @@ -186,6 +184,9 @@ */ wasShown() { super.wasShown(); + // Retrigger notification first time. + if (Runtime.queryParam('nodeFrontend')) + InspectorFrontendHost.setDevicesUpdatesEnabled(false); InspectorFrontendHost.setDevicesUpdatesEnabled(true); } @@ -194,13 +195,13 @@ */ willHide() { super.wasShown(); - InspectorFrontendHost.setDevicesUpdatesEnabled(false); + if (!Runtime.queryParam('nodeFrontend')) + InspectorFrontendHost.setDevicesUpdatesEnabled(false); } }; /** - * @implements {UI.ListWidget.Delegate} * @unrestricted */ Devices.DevicesView.DiscoveryView = class extends UI.VBox { @@ -216,7 +217,10 @@ discoverUsbDevicesCheckbox.classList.add('usb-checkbox'); this.element.appendChild(discoverUsbDevicesCheckbox); this._discoverUsbDevicesCheckbox = discoverUsbDevicesCheckbox.checkboxElement; - this._discoverUsbDevicesCheckbox.addEventListener('click', this._updateDiscoveryConfig.bind(this), false); + this._discoverUsbDevicesCheckbox.addEventListener('click', () => { + this._config.discoverUsbDevices = this._discoverUsbDevicesCheckbox.checked; + InspectorFrontendHost.setDevicesDiscoveryConfig(this._config); + }, false); var help = this.element.createChild('div', 'discovery-help'); help.createChild('span').textContent = Common.UIString('Need help? Read Chrome '); @@ -224,12 +228,56 @@ 'https://developers.google.com/chrome-developer-tools/docs/remote-debugging', Common.UIString('remote debugging documentation.'))); + /** @type {!Adb.Config} */ + this._config; + + this._portForwardingView = new Devices.DevicesView.PortForwardingView((enabled, config) => { + this._config.portForwardingEnabled = enabled; + this._config.portForwardingConfig = {}; + for (var rule of config) + this._config.portForwardingConfig[rule.port] = rule.address; + InspectorFrontendHost.setDevicesDiscoveryConfig(this._config); + }); + this._portForwardingView.show(this.element); + + this._networkDiscoveryView = new Devices.DevicesView.NetworkDiscoveryView(false, (enabled, config) => { + this._config.networkDiscoveryEnabled = enabled; + this._config.networkDiscoveryConfig = config; + InspectorFrontendHost.setDevicesDiscoveryConfig(this._config); + }); + this._networkDiscoveryView.show(this.element); + } + + /** + * @param {!Adb.Config} config + */ + discoveryConfigChanged(config) { + this._config = config; + this._discoverUsbDevicesCheckbox.checked = config.discoverUsbDevices; + this._portForwardingView.discoveryConfigChanged(config.portForwardingEnabled, config.portForwardingConfig); + this._networkDiscoveryView.discoveryConfigChanged(config.networkDiscoveryEnabled, config.networkDiscoveryConfig); + } +}; + +/** + * @implements {UI.ListWidget.Delegate} + * @unrestricted + */ +Devices.DevicesView.PortForwardingView = class extends UI.VBox { + /** + * @param {function(boolean, !Array<!Adb.PortForwardingRule>)} callback + */ + constructor(callback) { + super(); + this._callback = callback; + this.element.classList.add('port-forwarding-view'); + var portForwardingHeader = this.element.createChild('div', 'port-forwarding-header'); var portForwardingEnabledCheckbox = UI.CheckboxLabel.create(Common.UIString('Port forwarding')); portForwardingEnabledCheckbox.classList.add('port-forwarding-checkbox'); portForwardingHeader.appendChild(portForwardingEnabledCheckbox); this._portForwardingEnabledCheckbox = portForwardingEnabledCheckbox.checkboxElement; - this._portForwardingEnabledCheckbox.addEventListener('click', this._updateDiscoveryConfig.bind(this), false); + this._portForwardingEnabledCheckbox.addEventListener('click', this._update.bind(this), false); var portForwardingFooter = this.element.createChild('div', 'port-forwarding-footer'); portForwardingFooter.createChild('span').textContent = Common.UIString( @@ -252,19 +300,20 @@ this._portForwardingConfig = []; } + _update() { + this._callback.call(null, this._portForwardingEnabledCheckbox.checked, this._portForwardingConfig); + } + _addRuleButtonClicked() { this._list.addNewItem(this._portForwardingConfig.length, {port: '', address: ''}); } /** - * @param {boolean} discoverUsbDevices * @param {boolean} portForwardingEnabled * @param {!Adb.PortForwardingConfig} portForwardingConfig */ - discoveryConfigChanged(discoverUsbDevices, portForwardingEnabled, portForwardingConfig) { - this._discoverUsbDevicesCheckbox.checked = discoverUsbDevices; + discoveryConfigChanged(portForwardingEnabled, portForwardingConfig) { this._portForwardingEnabledCheckbox.checked = portForwardingEnabled; - this._portForwardingConfig = []; this._list.clear(); for (var key of Object.keys(portForwardingConfig)) { @@ -299,7 +348,7 @@ removeItemRequested(item, index) { this._portForwardingConfig.splice(index, 1); this._list.removeItem(index); - this._updateDiscoveryConfig(); + this._update(); } /** @@ -314,7 +363,7 @@ rule.address = editor.control('address').value.trim(); if (isNew) this._portForwardingConfig.push(rule); - this._updateDiscoveryConfig(); + this._update(); } /** @@ -352,7 +401,7 @@ * @param {*} item * @param {number} index * @param {!HTMLInputElement|!HTMLSelectElement} input - * @this {Devices.DevicesView.DiscoveryView} + * @this {Devices.DevicesView.PortForwardingView} * @return {boolean} */ function portValidator(item, index, input) { @@ -384,13 +433,178 @@ return port <= 65535; } } +}; - _updateDiscoveryConfig() { - var configMap = /** @type {!Adb.PortForwardingConfig} */ ({}); - for (var rule of this._portForwardingConfig) - configMap[rule.port] = rule.address; - InspectorFrontendHost.setDevicesDiscoveryConfig( - this._discoverUsbDevicesCheckbox.checked, this._portForwardingEnabledCheckbox.checked, configMap); +/** + * @implements {UI.ListWidget.Delegate} + * @unrestricted + */ +Devices.DevicesView.NetworkDiscoveryView = class extends UI.VBox { + /** + * @param {boolean} nodeFrontend + * @param {function(boolean, !Adb.NetworkDiscoveryConfig)} callback + */ + constructor(nodeFrontend, callback) { + super(); + this._nodeFrontend = nodeFrontend; + this._callback = callback; + this.element.classList.add('network-discovery-view'); + + var networkDiscoveryHeader = this.element.createChild('div', 'network-discovery-header'); + var networkDiscoveryEnabledCheckbox = UI.CheckboxLabel.create(Common.UIString('Network targets')); + networkDiscoveryEnabledCheckbox.classList.add('network-discovery-checkbox'); + networkDiscoveryHeader.appendChild(networkDiscoveryEnabledCheckbox); + this._networkDiscoveryEnabledCheckbox = networkDiscoveryEnabledCheckbox.checkboxElement; + this._networkDiscoveryEnabledCheckbox.disabled = !!Runtime.queryParam('nodeFrontend'); + this._networkDiscoveryEnabledCheckbox.checked = !!Runtime.queryParam('nodeFrontend'); + this._networkDiscoveryEnabledCheckbox.addEventListener('click', this._enabledCheckboxClicked.bind(this), false); + + var networkDiscoveryFooter = this.element.createChild('div', 'network-discovery-footer'); + if (nodeFrontend) { + networkDiscoveryFooter.createChild('span').textContent = + Common.UIString('Specify network endpoint and DevTools will connect to it automatically. '); + var link = networkDiscoveryFooter.createChild('span', 'link'); + link.textContent = Common.UIString('Learn more'); + link.addEventListener('click', () => InspectorFrontendHost.openInNewTab('https://nodejs.org/en/docs/inspector/')); + } else { + networkDiscoveryFooter.createChild('span').textContent = Common.UIString('Define the target connection address'); + } + + this._list = new UI.ListWidget(this); + this._list.registerRequiredCSS('devices/devicesView.css'); + this._list.element.classList.add('network-discovery-list'); + var placeholder = createElementWithClass('div', 'network-discovery-list-empty'); + placeholder.textContent = + nodeFrontend ? Common.UIString('No connections specified') : Common.UIString('No addresses defined'); + this._list.setEmptyPlaceholder(placeholder); + this._list.show(this.element); + + var addButton = UI.createTextButton( + nodeFrontend ? Common.UIString('Add connection') : Common.UIString('Add address'), + this._addNetworkTargetButtonClicked.bind(this), 'add-network-target-button'); + this.element.appendChild(addButton); + + /** @type {!Array<{address: string}>} */ + this._networkDiscoveryConfig = []; + this._networkDiscoveryEnabled = false; + + if (nodeFrontend) { + this.element.classList.add('node-frontend'); + this._list.element.classList.add('node-frontend'); + addButton.classList.add('material-button', 'default'); + } + } + + _update() { + var config = this._networkDiscoveryConfig.map(item => item.address); + this._callback.call(null, this._networkDiscoveryEnabled, config); + } + + _addNetworkTargetButtonClicked() { + this._list.addNewItem(this._networkDiscoveryConfig.length, {address: ''}); + } + + /** + * @param {boolean} networkDiscoveryEnabled + * @param {!Adb.NetworkDiscoveryConfig} networkDiscoveryConfig + */ + discoveryConfigChanged(networkDiscoveryEnabled, networkDiscoveryConfig) { + this._networkDiscoveryEnabled = networkDiscoveryEnabled; + if (!Runtime.queryParam('nodeFrontend')) + this._networkDiscoveryEnabledCheckbox.checked = networkDiscoveryEnabled; + this._networkDiscoveryConfig = []; + this._list.clear(); + for (var address of networkDiscoveryConfig) { + var item = {address: address}; + this._networkDiscoveryConfig.push(item); + this._list.appendItem(item, true); + } + } + + _enabledCheckboxClicked() { + if (!Runtime.queryParam('nodeFrontend')) { + this._networkDiscoveryEnabled = this._networkDiscoveryEnabledCheckbox.checked; + this._update(); + } + } + + /** + * @override + * @param {*} item + * @param {boolean} editable + * @return {!Element} + */ + renderItem(item, editable) { + var element = createElementWithClass('div', 'network-discovery-list-item'); + element.createChild('div', 'network-discovery-value network-discovery-address').textContent = + /** @type {string} */ (item.address); + return element; + } + + /** + * @override + * @param {*} item + * @param {number} index + */ + removeItemRequested(item, index) { + this._networkDiscoveryConfig.splice(index, 1); + this._list.removeItem(index); + this._update(); + } + + /** + * @override + * @param {*} item + * @param {!UI.ListWidget.Editor} editor + * @param {boolean} isNew + */ + commitEdit(item, editor, isNew) { + item.address = editor.control('address').value.trim(); + if (isNew) + this._networkDiscoveryConfig.push(/** @type {{address: string}} */ (item)); + this._update(); + } + + /** + * @override + * @param {*} item + * @return {!UI.ListWidget.Editor} + */ + beginEdit(item) { + var editor = this._createEditor(); + editor.control('address').value = item.address; + return editor; + } + + /** + * @return {!UI.ListWidget.Editor} + */ + _createEditor() { + if (this._editor) + return this._editor; + + var editor = new UI.ListWidget.Editor(); + editor.setMaterial(this._nodeFrontend); + this._editor = editor; + var content = editor.contentElement(); + var fields = content.createChild('div', 'network-discovery-edit-row'); + var input = editor.createInput('address', 'text', 'Network address (e.g. localhost:9229)', addressValidator); + fields.createChild('div', 'network-discovery-value network-discovery-address').appendChild(input); + return editor; + + /** + * @param {*} item + * @param {number} index + * @param {!HTMLInputElement|!HTMLSelectElement} input + * @return {boolean} + */ + function addressValidator(item, index, input) { + var match = input.value.trim().match(/^([a-zA-Z0-9\.\-_]+):(\d+)$/); + if (!match) + return false; + var port = parseInt(match[2], 10); + return port <= 65535; + } } }; @@ -683,3 +897,46 @@ /** @typedef {!{page: ?Adb.Page, element: !Element, title: !Element, url: !Element, inspect: !Element}} */ Devices.DevicesView.PageSection; + + +Devices.DevicesView.Panel = class extends UI.Panel { + constructor() { + super('node-connection'); + this.registerRequiredCSS('devices/devicesView.css'); + this.contentElement.classList.add('devices-view-panel'); + + var container = this.contentElement.createChild('div', 'devices-view-panel-center'); + + var image = container.createChild('img', 'devices-view-panel-logo'); + image.src = 'https://nodejs.org/static/images/logos/nodejs-new-pantone-black.png'; + + InspectorFrontendHost.events.addEventListener( + InspectorFrontendHostAPI.Events.DevicesDiscoveryConfigChanged, this._devicesDiscoveryConfigChanged, this); + + /** @type {!Adb.Config} */ + this._config; + + this.contentElement.tabIndex = 0; + this.setDefaultFocusedElement(this.contentElement); + + // Trigger notification once. + InspectorFrontendHost.setDevicesUpdatesEnabled(false); + InspectorFrontendHost.setDevicesUpdatesEnabled(true); + + this._networkDiscoveryView = new Devices.DevicesView.NetworkDiscoveryView(true, (enabled, config) => { + this._config.networkDiscoveryEnabled = enabled; + this._config.networkDiscoveryConfig = config; + InspectorFrontendHost.setDevicesDiscoveryConfig(this._config); + }); + this._networkDiscoveryView.show(container); + } + + /** + * @param {!Common.Event} event + */ + _devicesDiscoveryConfigChanged(event) { + this._config = /** @type {!Adb.Config} */ (event.data); + this._networkDiscoveryView.discoveryConfigChanged( + this._config.networkDiscoveryEnabled, this._config.networkDiscoveryConfig); + } +};
diff --git a/third_party/WebKit/Source/devtools/front_end/devices/devicesView.css b/third_party/WebKit/Source/devtools/front_end/devices/devicesView.css index c0a7eef..1fec4e6 100644 --- a/third_party/WebKit/Source/devtools/front_end/devices/devicesView.css +++ b/third_party/WebKit/Source/devtools/front_end/devices/devicesView.css
@@ -189,6 +189,73 @@ white-space: pre-wrap; } +.network-discovery-header { + display: flex; + align-items: center; + flex-direction: row; + margin-top: 5px; +} + +.add-network-target-button { + margin: 10px 25px; + align-self: flex-start; +} + +.network-discovery-list { + margin: 10px 0 0 25px; + max-width: 500px; + flex: none; +} + +.network-discovery-list-empty { + flex: auto; + height: 30px; + display: flex; + align-items: center; + justify-content: center; +} + +.network-discovery-list-item { + padding: 3px 5px 3px 5px; + height: 30px; + display: flex; + align-items: center; + position: relative; + flex: auto 1 1; +} + +.network-discovery-value { + white-space: nowrap; + text-overflow: ellipsis; + -webkit-user-select: none; + color: #222; + flex: 3 1 0; + overflow: hidden; +} + +.network-discovery-edit-row { + flex: none; + display: flex; + flex-direction: row; + margin: 6px 5px; + align-items: center; +} + +.network-discovery-edit-row input { + width: 100%; + text-align: inherit; +} + +.network-discovery-footer { + overflow: hidden; + margin: 15px 0 0 25px; + max-width: 500px; +} + +.network-discovery-footer > * { + white-space: pre-wrap; +} + .device-view { overflow: auto; -webkit-user-select: text; @@ -333,3 +400,65 @@ transform: scale(1.2); background-color: orange; } + +.node-frontend .network-discovery-header { + display: none; +} + +.devices-view-panel { + align-items: center; + justify-content: flex-start; +} + +.node-frontend.network-discovery-view { + min-width: 400px; + flex: auto; +} + +.node-frontend .add-network-target-button { + align-self: center; +} + +:host-context(.node-frontend) .network-discovery-list-empty { + height: 40px; +} + +:host-context(.node-frontend) .network-discovery-list-item { + padding: 3px 15px; + height: 40px; +} + +.node-frontend .network-discovery-list { + margin: 20px 0 5px 0; + max-width: 600px; + max-height: 202px; +} + +.node-frontend .network-discovery-footer { + margin: 0; +} + +.devices-view-panel-center { + display: flex; + align-items: stretch; + justify-content: center; + max-width: 600px; + flex-direction: column; + padding-top: 50px; +} + +.devices-view-panel-logo { + align-self: center; + width: 400px; + margin-bottom: 50px; + flex: none; +} + +:host-context(.node-frontend) .network-discovery-edit-row input { + height: 30px; + padding-left: 5px; +} + +:host-context(.node-frontend) .network-discovery-edit-row { + margin: 6px 9px; +}
diff --git a/third_party/WebKit/Source/devtools/front_end/devices/module.json b/third_party/WebKit/Source/devtools/front_end/devices/module.json index 4231f0a..f632719 100644 --- a/third_party/WebKit/Source/devtools/front_end/devices/module.json +++ b/third_party/WebKit/Source/devtools/front_end/devices/module.json
@@ -8,7 +8,18 @@ "persistence": "closeable", "order": 50, "className": "Devices.DevicesView", + "condition": "!v8only", "tags": "usb, android, mobile" + }, + { + "type": "view", + "location": "panel", + "id": "node-connection", + "title": "Connection", + "order": 0, + "className": "Devices.DevicesView.Panel", + "condition": "nodeFrontend", + "tags": "node" } ], "dependencies": ["platform", "ui", "host", "components"],
diff --git a/third_party/WebKit/Source/devtools/front_end/devtools_compatibility.js b/third_party/WebKit/Source/devtools/front_end/devtools_compatibility.js index 05a6c5e8..bcaef60d 100644 --- a/third_party/WebKit/Source/devtools/front_end/devtools_compatibility.js +++ b/third_party/WebKit/Source/devtools/front_end/devtools_compatibility.js
@@ -107,13 +107,10 @@ } /** - * @param {boolean} discoverUsbDevices - * @param {boolean} portForwardingEnabled - * @param {!Adb.PortForwardingConfig} portForwardingConfig + * @param {!Adb.Config} config */ - devicesDiscoveryConfigChanged(discoverUsbDevices, portForwardingEnabled, portForwardingConfig) { - this._dispatchOnInspectorFrontendAPI( - 'devicesDiscoveryConfigChanged', [discoverUsbDevices, portForwardingEnabled, portForwardingConfig]); + devicesDiscoveryConfigChanged(config) { + this._dispatchOnInspectorFrontendAPI('devicesDiscoveryConfigChanged', [config]); } /** @@ -667,14 +664,16 @@ /** * @override - * @param {boolean} discoverUsbDevices - * @param {boolean} portForwardingEnabled - * @param {!Adb.PortForwardingConfig} portForwardingConfig + * @param {!Adb.Config} config */ - setDevicesDiscoveryConfig(discoverUsbDevices, portForwardingEnabled, portForwardingConfig) { + setDevicesDiscoveryConfig(config) { DevToolsAPI.sendMessageToEmbedder( 'setDevicesDiscoveryConfig', - [discoverUsbDevices, portForwardingEnabled, JSON.stringify(portForwardingConfig)], null); + [ + config.discoverUsbDevices, config.portForwardingEnabled, JSON.stringify(config.portForwardingConfig), + config.networkDiscoveryEnabled, JSON.stringify(config.networkDiscoveryConfig) + ], + null); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/module.json b/third_party/WebKit/Source/devtools/front_end/emulation/module.json index fdf5ad24..254857c 100644 --- a/third_party/WebKit/Source/devtools/front_end/emulation/module.json +++ b/third_party/WebKit/Source/devtools/front_end/emulation/module.json
@@ -130,6 +130,7 @@ "type": "@UI.ActionDelegate", "actionId": "emulation.show-sensors", "title": "Sensors", + "condition": "!v8only", "className": "Emulation.SensorsView.ShowActionDelegate" }, { @@ -137,6 +138,7 @@ "location": "drawer-view", "id": "sensors", "title": "Sensors", + "condition": "!v8only", "persistence": "closeable", "order": 100, "className": "Emulation.SensorsView",
diff --git a/third_party/WebKit/Source/devtools/front_end/externs.js b/third_party/WebKit/Source/devtools/front_end/externs.js index a05f31f..67fe898 100644 --- a/third_party/WebKit/Source/devtools/front_end/externs.js +++ b/third_party/WebKit/Source/devtools/front_end/externs.js
@@ -344,6 +344,18 @@ Adb.DevicePortForwardingStatus; /** @typedef {!Object<string, !Adb.DevicePortForwardingStatus>} */ Adb.PortForwardingStatus; +/** @typedef {!Array<string>} */ +Adb.NetworkDiscoveryConfig; +/** + * @typedef {!{ + * discoverUsbDevices: boolean, + * portForwardingEnabled: boolean, + * portForwardingConfig: !Adb.PortForwardingConfig, + * networkDiscoveryEnabled: boolean, + * networkDiscoveryConfig: !Adb.NetworkDiscoveryConfig + * }} + */ +Adb.Config; /** @const */ var module = {};
diff --git a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHost.js b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHost.js index 94f8b8a..197b438 100644 --- a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHost.js +++ b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHost.js
@@ -375,11 +375,9 @@ /** * @override - * @param {boolean} discoverUsbDevices - * @param {boolean} portForwardingEnabled - * @param {!Adb.PortForwardingConfig} portForwardingConfig + * @param {!Adb.Config} config */ - setDevicesDiscoveryConfig(discoverUsbDevices, portForwardingEnabled, portForwardingConfig) { + setDevicesDiscoveryConfig(config) { } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js index d00516af..c79e142 100644 --- a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js +++ b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
@@ -63,10 +63,7 @@ [InspectorFrontendHostAPI.Events.ContextMenuCleared, 'contextMenuCleared', []], [InspectorFrontendHostAPI.Events.ContextMenuItemSelected, 'contextMenuItemSelected', ['id']], [InspectorFrontendHostAPI.Events.DeviceCountUpdated, 'deviceCountUpdated', ['count']], - [ - InspectorFrontendHostAPI.Events.DevicesDiscoveryConfigChanged, 'devicesDiscoveryConfigChanged', - ['discoverUsbDevices', 'portForwardingEnabled', 'portForwardingConfig'] - ], + [InspectorFrontendHostAPI.Events.DevicesDiscoveryConfigChanged, 'devicesDiscoveryConfigChanged', ['config']], [ InspectorFrontendHostAPI.Events.DevicesPortForwardingStatusChanged, 'devicesPortForwardingStatusChanged', ['status'] ], @@ -250,11 +247,9 @@ sendMessageToBackend(message) {}, /** - * @param {boolean} discoverUsbDevices - * @param {boolean} portForwardingEnabled - * @param {!Adb.PortForwardingConfig} portForwardingConfig + * @param {!Adb.Config} config */ - setDevicesDiscoveryConfig(discoverUsbDevices, portForwardingEnabled, portForwardingConfig) {}, + setDevicesDiscoveryConfig(config) {}, /** * @param {boolean} enabled
diff --git a/third_party/WebKit/Source/devtools/front_end/inspector.json b/third_party/WebKit/Source/devtools/front_end/inspector.json index 597a0bf..73ec761 100644 --- a/third_party/WebKit/Source/devtools/front_end/inspector.json +++ b/third_party/WebKit/Source/devtools/front_end/inspector.json
@@ -26,7 +26,7 @@ { "name": "resources", "condition": "!v8only" }, { "name": "audits", "condition": "!v8only" }, { "name": "audits2", "condition": "!v8only" }, - { "name": "devices", "condition": "!v8only" }, + { "name": "devices" }, { "name": "security", "condition": "!v8only" }, { "name": "console" }, { "name": "source_frame" },
diff --git a/third_party/WebKit/Source/devtools/front_end/main/module.json b/third_party/WebKit/Source/devtools/front_end/main/module.json index 40cee054..2a7f138 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/module.json +++ b/third_party/WebKit/Source/devtools/front_end/main/module.json
@@ -367,6 +367,7 @@ "title": "Rendering", "persistence": "closeable", "order": 50, + "condition": "!v8only", "className": "Main.RenderingOptionsView" }, {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js index a3f59f1..cc8ee55f 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
@@ -410,13 +410,31 @@ if (Runtime.experiments.isEnabled('autoAttachToCrossProcessSubframes')) this._targetAgent.setAttachToFrames(true); - if (!parentTarget.parentTarget()) { - this._targetAgent.setRemoteLocations([{host: 'localhost', port: 9229}]); + if (!parentTarget.parentTarget()) this._targetAgent.setDiscoverTargets(true); + + if (Runtime.queryParam('nodeFrontend') && !this._parentTarget.parentTarget()) { + InspectorFrontendHost.setDevicesUpdatesEnabled(true); + InspectorFrontendHost.events.addEventListener( + InspectorFrontendHostAPI.Events.DevicesDiscoveryConfigChanged, this._devicesDiscoveryConfigChanged, this); } } /** + * @param {!Common.Event} event + */ + _devicesDiscoveryConfigChanged(event) { + var config = /** @type {!Adb.Config} */ (event.data); + var locations = []; + for (var address of config.networkDiscoveryConfig) { + var parts = address.split(':'); + var port = parseInt(parts[1], 10); + locations.push({host: parts[0] || 'localhost', port: port || 9229}); + } + this._targetAgent.setRemoteLocations(locations); + } + + /** * @return {!Promise} */ suspend() { @@ -431,6 +449,11 @@ } dispose() { + if (Runtime.queryParam('nodeFrontend') && !this._parentTarget.parentTarget()) { + InspectorFrontendHost.events.removeEventListener( + InspectorFrontendHostAPI.Events.DevicesDiscoveryConfigChanged, this._devicesDiscoveryConfigChanged, this); + } + // TODO(dgozman): this is O(n^2) when removing main target. var childTargets = this._targetManager._targets.filter(child => child.parentTarget() === this._parentTarget); for (var child of childTargets) @@ -508,6 +531,9 @@ debuggerModel.pause(); } target.runtimeAgent().runIfWaitingForDebugger(); + + if (Runtime.queryParam('nodeFrontend')) + InspectorFrontendHost.bringToFront(); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js b/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js index 2d1aa06..d96d1c6 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js
@@ -308,6 +308,16 @@ } /** + * @param {boolean} material + */ + setMaterial(material) { + this._commitButton.classList.toggle('material-button', material); + this._commitButton.classList.toggle('default', material); + this._cancelButton.classList.toggle('material-button', material); + this.element.classList.toggle('material', material); + } + + /** * @param {string} name * @param {string} type * @param {string} title
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css b/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css index c14b144..18ecc33a 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css
@@ -83,6 +83,10 @@ padding: 5px; } +.material .editor-buttons { + padding: 5px 9px 9px 9px; +} + .editor-buttons > button { flex: none; margin-right: 10px;
diff --git a/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.cpp b/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.cpp index e72270f..de43bcd7 100644 --- a/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.cpp +++ b/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.cpp
@@ -5,7 +5,7 @@ #include "modules/credentialmanager/FederatedCredential.h" #include "bindings/core/v8/ExceptionState.h" -#include "modules/credentialmanager/FederatedCredentialData.h" +#include "modules/credentialmanager/FederatedCredentialInit.h" #include "platform/credentialmanager/PlatformFederatedCredential.h" #include "platform/weborigin/SecurityOrigin.h" #include "public/platform/WebFederatedCredential.h" @@ -18,7 +18,7 @@ } FederatedCredential* FederatedCredential::Create( - const FederatedCredentialData& data, + const FederatedCredentialInit& data, ExceptionState& exception_state) { if (data.id().IsEmpty()) { exception_state.ThrowTypeError("'id' must not be empty.");
diff --git a/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.h b/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.h index 9da44cf3..3285ad7f 100644 --- a/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.h +++ b/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.h
@@ -14,14 +14,14 @@ namespace blink { -class FederatedCredentialData; +class FederatedCredentialInit; class WebFederatedCredential; class MODULES_EXPORT FederatedCredential final : public CredentialUserData { DEFINE_WRAPPERTYPEINFO(); public: - static FederatedCredential* Create(const FederatedCredentialData&, + static FederatedCredential* Create(const FederatedCredentialInit&, ExceptionState&); static FederatedCredential* Create(WebFederatedCredential*);
diff --git a/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.idl b/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.idl index 9e421aa..efd7e22b 100644 --- a/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.idl +++ b/third_party/WebKit/Source/modules/credentialmanager/FederatedCredential.idl
@@ -6,7 +6,7 @@ [ RaisesException=Constructor, - Constructor(FederatedCredentialData data), + Constructor(FederatedCredentialInit data), Exposed=Window, SecureContext ] interface FederatedCredential : Credential {
diff --git a/third_party/WebKit/Source/modules/credentialmanager/FederatedCredentialData.idl b/third_party/WebKit/Source/modules/credentialmanager/FederatedCredentialData.idl deleted file mode 100644 index e9c92cb..0000000 --- a/third_party/WebKit/Source/modules/credentialmanager/FederatedCredentialData.idl +++ /dev/null
@@ -1,9 +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. - -// https://w3c.github.io/webappsec/specs/credentialmanagement/#dictdef-federatedcredentialdata - -dictionary FederatedCredentialData : LocallyStoredCredentialData { - USVString provider; -};
diff --git a/third_party/WebKit/Source/modules/credentialmanager/FederatedCredentialInit.idl b/third_party/WebKit/Source/modules/credentialmanager/FederatedCredentialInit.idl new file mode 100644 index 0000000..4e4fff4 --- /dev/null +++ b/third_party/WebKit/Source/modules/credentialmanager/FederatedCredentialInit.idl
@@ -0,0 +1,12 @@ +// 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. + +// https://w3c.github.io/webappsec-credential-management/#dictdef-federatedcredentialinit + +dictionary FederatedCredentialInit : CredentialData { + USVString name; + USVString iconURL; + required USVString provider; + DOMString protocol; +};
diff --git a/third_party/WebKit/Source/modules/credentialmanager/LocallyStoredCredentialData.idl b/third_party/WebKit/Source/modules/credentialmanager/LocallyStoredCredentialData.idl deleted file mode 100644 index 2d127f9..0000000 --- a/third_party/WebKit/Source/modules/credentialmanager/LocallyStoredCredentialData.idl +++ /dev/null
@@ -1,10 +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. - -// https://w3c.github.io/webappsec/specs/credentialmanagement/#dictdef-locallystoredcredentialdata - -dictionary LocallyStoredCredentialData : CredentialData { - DOMString name; - DOMString iconURL; -};
diff --git a/third_party/WebKit/Source/modules/credentialmanager/PasswordCredentialData.idl b/third_party/WebKit/Source/modules/credentialmanager/PasswordCredentialData.idl index 8739fe66..3c6b2d9 100644 --- a/third_party/WebKit/Source/modules/credentialmanager/PasswordCredentialData.idl +++ b/third_party/WebKit/Source/modules/credentialmanager/PasswordCredentialData.idl
@@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://w3c.github.io/webappsec/specs/credentialmanagement/#dictdef-passwordcredentialdata +// https://w3c.github.io/webappsec-credential-management/#dictdef-passwordcredentialdata -dictionary PasswordCredentialData : LocallyStoredCredentialData { - DOMString password; +dictionary PasswordCredentialData : CredentialData { + USVString name; + USVString iconURL; + required USVString password; };
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni index 2b0ab6a..bf0ef00 100644 --- a/third_party/WebKit/Source/modules/modules_idl_files.gni +++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -417,10 +417,9 @@ "canvas2d/HitRegionOptions.idl", "credentialmanager/CredentialData.idl", "credentialmanager/CredentialRequestOptions.idl", - "credentialmanager/FederatedCredentialData.idl", + "credentialmanager/FederatedCredentialInit.idl", "credentialmanager/FederatedCredentialRequestOptions.idl", "credentialmanager/FormDataOptions.idl", - "credentialmanager/LocallyStoredCredentialData.idl", "credentialmanager/PasswordCredentialData.idl", "device_orientation/DeviceAccelerationInit.idl", "device_orientation/DeviceMotionEventInit.idl", @@ -738,14 +737,12 @@ "$blink_modules_output_dir/credentialmanager/CredentialData.h", "$blink_modules_output_dir/credentialmanager/CredentialRequestOptions.cpp", "$blink_modules_output_dir/credentialmanager/CredentialRequestOptions.h", - "$blink_modules_output_dir/credentialmanager/FederatedCredentialData.cpp", - "$blink_modules_output_dir/credentialmanager/FederatedCredentialData.h", + "$blink_modules_output_dir/credentialmanager/FederatedCredentialInit.cpp", + "$blink_modules_output_dir/credentialmanager/FederatedCredentialInit.h", "$blink_modules_output_dir/credentialmanager/FederatedCredentialRequestOptions.cpp", "$blink_modules_output_dir/credentialmanager/FederatedCredentialRequestOptions.h", "$blink_modules_output_dir/credentialmanager/FormDataOptions.cpp", "$blink_modules_output_dir/credentialmanager/FormDataOptions.h", - "$blink_modules_output_dir/credentialmanager/LocallyStoredCredentialData.cpp", - "$blink_modules_output_dir/credentialmanager/LocallyStoredCredentialData.h", "$blink_modules_output_dir/credentialmanager/PasswordCredentialData.cpp", "$blink_modules_output_dir/credentialmanager/PasswordCredentialData.h", "$blink_modules_output_dir/device_orientation/DeviceAccelerationInit.cpp",
diff --git a/third_party/WebKit/Source/platform/DragImage.cpp b/third_party/WebKit/Source/platform/DragImage.cpp index 74203d82..78502c39 100644 --- a/third_party/WebKit/Source/platform/DragImage.cpp +++ b/third_party/WebKit/Source/platform/DragImage.cpp
@@ -73,13 +73,13 @@ } // anonymous namespace -sk_sp<SkImage> DragImage::ResizeAndOrientImage( - sk_sp<SkImage> image, +PaintImage DragImage::ResizeAndOrientImage( + const PaintImage& image, ImageOrientation orientation, FloatSize image_scale, float opacity, InterpolationQuality interpolation_quality) { - IntSize size(image->width(), image->height()); + IntSize size(image.sk_image()->width(), image.sk_image()->height()); size.Scale(image_scale.Width(), image_scale.Height()); AffineTransform transform; if (orientation != kDefaultImageOrientation) { @@ -90,19 +90,19 @@ transform.ScaleNonUniform(image_scale.Width(), image_scale.Height()); if (size.IsEmpty()) - return nullptr; + return PaintImage(); if (transform.IsIdentity() && opacity == 1) { // Nothing to adjust, just use the original. - ASSERT(image->width() == size.Width()); - ASSERT(image->height() == size.Height()); + DCHECK_EQ(image.sk_image()->width(), size.Width()); + DCHECK_EQ(image.sk_image()->height(), size.Height()); return image; } sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(size.Width(), size.Height()); if (!surface) - return nullptr; + return PaintImage(); SkPaint paint; ASSERT(opacity >= 0 && opacity <= 1); @@ -113,9 +113,10 @@ SkCanvas* canvas = surface->getCanvas(); canvas->concat(AffineTransformToSkMatrix(transform)); - canvas->drawImage(image, 0, 0, &paint); + canvas->drawImage(image.sk_image(), 0, 0, &paint); - return surface->makeImageSnapshot(); + return PaintImage(surface->makeImageSnapshot(), image.animation_type(), + image.completion_state()); } FloatSize DragImage::ClampedImageScale(const IntSize& image_size, @@ -150,8 +151,8 @@ if (!image) return nullptr; - sk_sp<SkImage> sk_image = image->ImageForCurrentFrame(); - if (!sk_image) + PaintImage paint_image = image->PaintImageForCurrentFrame(); + if (!paint_image) return nullptr; ImageOrientation orientation; @@ -160,12 +161,12 @@ orientation = ToBitmapImage(image)->CurrentFrameOrientation(); SkBitmap bm; - sk_sp<SkImage> resized_image = - ResizeAndOrientImage(std::move(sk_image), orientation, image_scale, - opacity, interpolation_quality); - if (!resized_image || - !resized_image->asLegacyBitmap(&bm, SkImage::kRO_LegacyBitmapMode)) + paint_image = ResizeAndOrientImage(paint_image, orientation, image_scale, + opacity, interpolation_quality); + if (!paint_image || !paint_image.sk_image()->asLegacyBitmap( + &bm, SkImage::kRO_LegacyBitmapMode)) { return nullptr; + } return WTF::WrapUnique( new DragImage(bm, device_scale_factor, interpolation_quality));
diff --git a/third_party/WebKit/Source/platform/DragImage.h b/third_party/WebKit/Source/platform/DragImage.h index 9008ad1..e09aa99 100644 --- a/third_party/WebKit/Source/platform/DragImage.h +++ b/third_party/WebKit/Source/platform/DragImage.h
@@ -32,13 +32,12 @@ #include "platform/graphics/GraphicsTypes.h" #include "platform/graphics/ImageOrientation.h" #include "platform/graphics/paint/DisplayItemClient.h" +#include "platform/graphics/paint/PaintImage.h" #include "platform/wtf/Allocator.h" #include "platform/wtf/Forward.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkRefCnt.h" -class SkImage; - namespace blink { class FontDescription; @@ -74,8 +73,8 @@ void Scale(float scale_x, float scale_y); - static sk_sp<SkImage> ResizeAndOrientImage( - sk_sp<SkImage>, + static PaintImage ResizeAndOrientImage( + const PaintImage&, ImageOrientation, FloatSize image_scale = FloatSize(1, 1), float opacity = 1.0,
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp index a4d09f3..9ea5db3b2 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
@@ -227,9 +227,12 @@ if (HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(range_data->buffer))) { start_index = glyph_info[last_change_position].cluster; if (glyph_index == num_glyphs) { - num_characters = current_queue_item.start_index_ + - current_queue_item.num_characters_ - - glyph_info[last_change_position].cluster; + // Clamp the end offsets of the queue item to the offsets representing + // the shaping window. + unsigned shape_end = + std::min(range_data->end, current_queue_item.start_index_ + + current_queue_item.num_characters_); + num_characters = shape_end - glyph_info[last_change_position].cluster; num_glyphs_to_insert = num_glyphs - last_change_position; } else { num_characters = glyph_info[glyph_index].cluster - @@ -240,9 +243,12 @@ // Direction Backwards start_index = glyph_info[glyph_index - 1].cluster; if (last_change_position == 0) { - num_characters = current_queue_item.start_index_ + - current_queue_item.num_characters_ - - glyph_info[glyph_index - 1].cluster; + // Clamp the end offsets of the queue item to the offsets representing + // the shaping window. + unsigned shape_end = + std::min(range_data->end, current_queue_item.start_index_ + + current_queue_item.num_characters_); + num_characters = shape_end - glyph_info[glyph_index - 1].cluster; } else { num_characters = glyph_info[last_change_position - 1].cluster - glyph_info[glyph_index - 1].cluster;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp index 120e2db..5a62bd3 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
@@ -30,6 +30,7 @@ FontDescription font_description; Font font; unsigned start_index = 0; + unsigned num_characters = 0; unsigned num_glyphs = 0; hb_script_t script = HB_SCRIPT_INVALID; }; @@ -225,6 +226,19 @@ RefPtr<ShapeResult> second = shaper.Shape(&font, direction, 6, 11); RefPtr<ShapeResult> third = shaper.Shape(&font, direction, 11, 12); + ASSERT_TRUE(TestInfo(first)->RunInfoForTesting(0, start_index, num_characters, + num_glyphs, script)); + EXPECT_EQ(0u, start_index); + EXPECT_EQ(6u, num_characters); + ASSERT_TRUE(TestInfo(second)->RunInfoForTesting( + 0, start_index, num_characters, num_glyphs, script)); + EXPECT_EQ(6u, start_index); + EXPECT_EQ(5u, num_characters); + ASSERT_TRUE(TestInfo(third)->RunInfoForTesting(0, start_index, num_characters, + num_glyphs, script)); + EXPECT_EQ(11u, start_index); + EXPECT_EQ(1u, num_characters); + HarfBuzzShaper shaper2(string.Characters16(), 6); RefPtr<ShapeResult> first_reference = shaper2.Shape(&font, direction);
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp index 6f8e240..c04d442 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp
@@ -15,10 +15,12 @@ bool ShapeResultTestInfo::RunInfoForTesting(unsigned run_index, unsigned& start_index, + unsigned& num_characters, unsigned& num_glyphs, hb_script_t& script) const { if (run_index < runs_.size() && runs_[run_index]) { start_index = runs_[run_index]->start_index_; + num_characters = runs_[run_index]->num_characters_; num_glyphs = runs_[run_index]->glyph_data_.size(); script = runs_[run_index]->script_; return true; @@ -26,6 +28,15 @@ return false; } +bool ShapeResultTestInfo::RunInfoForTesting(unsigned run_index, + unsigned& start_index, + unsigned& num_glyphs, + hb_script_t& script) const { + unsigned num_characters; + return RunInfoForTesting(run_index, start_index, num_characters, num_glyphs, + script); +} + uint16_t ShapeResultTestInfo::GlyphForTesting(unsigned run_index, size_t glyph_index) const { return runs_[run_index]->glyph_data_[glyph_index].glyph;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h index a0f1ae0..f95d543 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h
@@ -19,6 +19,11 @@ unsigned& start_index, unsigned& num_glyphs, hb_script_t&) const; + bool RunInfoForTesting(unsigned run_index, + unsigned& start_index, + unsigned& num_characters, + unsigned& num_glyphs, + hb_script_t&) const; uint16_t GlyphForTesting(unsigned run_index, size_t glyph_index) const; float AdvanceForTesting(unsigned run_index, size_t glyph_index) const; SimpleFontData* FontDataForTesting(unsigned run_index) const;
diff --git a/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp b/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp index a7b5a46a..f78253c 100644 --- a/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp +++ b/third_party/WebKit/Source/platform/graphics/AcceleratedStaticBitmapImage.cpp
@@ -94,6 +94,8 @@ } sk_sp<SkImage> AcceleratedStaticBitmapImage::ImageForCurrentFrame() { + // TODO(ccameron): This function should not ignore |colorBehavior|. + // https://crbug.com/672306 CheckThread(); if (!IsValid()) return nullptr; @@ -107,15 +109,11 @@ const FloatRect& src_rect, RespectImageOrientationEnum, ImageClampingMode image_clamping_mode) { - // TODO(ccameron): This function should not ignore |colorBehavior|. - // https://crbug.com/672306 - CheckThread(); - if (!IsValid()) + const auto& paint_image = PaintImageForCurrentFrame(); + if (!paint_image) return; - CreateImageFromMailboxIfNeeded(); - sk_sp<SkImage> image = texture_holder_->GetSkImage(); StaticBitmapImage::DrawHelper(canvas, flags, dst_rect, src_rect, - image_clamping_mode, image); + image_clamping_mode, paint_image); } bool AcceleratedStaticBitmapImage::IsValid() {
diff --git a/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp b/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp index f1524ed..2c8bbc3 100644 --- a/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp +++ b/third_party/WebKit/Source/platform/graphics/BitmapImage.cpp
@@ -73,17 +73,17 @@ : Image(observer), current_frame_(0), cached_frame_index_(0), - repetition_count_(kCAnimationNone), - repetition_count_status_(kUnknown), - repetitions_complete_(0), - desired_frame_start_time_(0), - frame_count_(0), animation_policy_(kImageAnimationPolicyAllowed), animation_finished_(false), all_data_received_(false), have_size_(false), size_available_(false), - have_frame_count_(false) {} + have_frame_count_(false), + repetition_count_status_(kUnknown), + repetition_count_(kCAnimationNone), + repetitions_complete_(0), + desired_frame_start_time_(0), + frame_count_(0) {} BitmapImage::BitmapImage(const SkBitmap& bitmap, ImageObserver* observer) : Image(observer), @@ -91,16 +91,16 @@ current_frame_(0), cached_frame_(SkImage::MakeFromBitmap(bitmap)), cached_frame_index_(0), - repetition_count_(kCAnimationNone), - repetition_count_status_(kUnknown), - repetitions_complete_(0), - frame_count_(1), animation_policy_(kImageAnimationPolicyAllowed), animation_finished_(true), all_data_received_(true), have_size_(true), size_available_(true), - have_frame_count_(true) { + have_frame_count_(true), + repetition_count_status_(kUnknown), + repetition_count_(kCAnimationNone), + repetitions_complete_(0), + frame_count_(1) { // Since we don't have a decoder, we can't figure out the image orientation. // Set m_sizeRespectingOrientation to be the same as m_size so it's not 0x0. size_respecting_orientation_ = size_; @@ -263,12 +263,12 @@ ImageClampingMode clamp_mode) { TRACE_EVENT0("skia", "BitmapImage::draw"); - sk_sp<SkImage> image = ImageForCurrentFrame(); + PaintImage image = PaintImageForCurrentFrame(); if (!image) return; // It's too early and we don't have an image yet. FloatRect adjusted_src_rect = src_rect; - adjusted_src_rect.Intersect(SkRect::Make(image->bounds())); + adjusted_src_rect.Intersect(SkRect::Make(image.sk_image()->bounds())); if (adjusted_src_rect.IsEmpty() || dst_rect.IsEmpty()) return; // Nothing to draw. @@ -299,18 +299,11 @@ } } - uint32_t unique_id = image->uniqueID(); - bool is_lazy_generated = image->isLazyGenerated(); - auto animation_type = MaybeAnimated() ? PaintImage::AnimationType::ANIMATED - : PaintImage::AnimationType::STATIC; - auto completion_state = CurrentFrameIsComplete() - ? PaintImage::CompletionState::DONE - : PaintImage::CompletionState::PARTIALLY_DONE; - - canvas->drawImageRect( - PaintImage(std::move(image), animation_type, completion_state), - adjusted_src_rect, adjusted_dst_rect, &flags, - WebCoreClampingModeToSkiaRectConstraint(clamp_mode)); + uint32_t unique_id = image.sk_image()->uniqueID(); + bool is_lazy_generated = image.sk_image()->isLazyGenerated(); + canvas->drawImageRect(std::move(image), adjusted_src_rect, adjusted_dst_rect, + &flags, + WebCoreClampingModeToSkiaRectConstraint(clamp_mode)); if (is_lazy_generated) PlatformInstrumentation::DidDrawLazyPixelRef(unique_id);
diff --git a/third_party/WebKit/Source/platform/graphics/BitmapImage.h b/third_party/WebKit/Source/platform/graphics/BitmapImage.h index 4ee77dc5..902550e 100644 --- a/third_party/WebKit/Source/platform/graphics/BitmapImage.h +++ b/third_party/WebKit/Source/platform/graphics/BitmapImage.h
@@ -99,7 +99,7 @@ void AdvanceAnimationForTesting() override { InternalAdvanceAnimation(); } private: - enum RepetitionCountStatus { + enum RepetitionCountStatus : uint8_t { kUnknown, // We haven't checked the source's repetition count. kUncertain, // We have a repetition count, but it might be wrong (some GIFs // have a count after the image data, and will report "loop @@ -193,15 +193,6 @@ size_t cached_frame_index_; // Index of the frame that is cached. std::unique_ptr<Timer<BitmapImage>> frame_timer_; - int repetition_count_; // How many total animation loops we should do. This - // will be cAnimationNone if this image type is - // incapable of animation. - RepetitionCountStatus repetition_count_status_; - int repetitions_complete_; // How many repetitions we've finished. - double desired_frame_start_time_; // The system time at which we hope to see - // the next call to startAnimation(). - - size_t frame_count_; ImageAnimationPolicy animation_policy_; // Whether or not we can play animation. @@ -215,6 +206,17 @@ bool size_available_ : 1; // Whether we can obtain the size of the first // image frame from ImageIO yet. mutable bool have_frame_count_ : 1; + + RepetitionCountStatus repetition_count_status_; + int repetition_count_; // How many total animation loops we should do. This + // will be cAnimationNone if this image type is + // incapable of animation. + int repetitions_complete_; // How many repetitions we've finished. + + double desired_frame_start_time_; // The system time at which we hope to see + // the next call to startAnimation(). + + size_t frame_count_; }; DEFINE_IMAGE_TYPE_CASTS(BitmapImage);
diff --git a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp index 4cd7ff8b..cedd523 100644 --- a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp +++ b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.cpp
@@ -84,9 +84,9 @@ DeferredImageDecoder::DeferredImageDecoder( std::unique_ptr<ImageDecoder> actual_decoder) - : all_data_received_(false), - actual_decoder_(std::move(actual_decoder)), + : actual_decoder_(std::move(actual_decoder)), repetition_count_(kCAnimationNone), + all_data_received_(false), can_yuv_decode_(false), has_hot_spot_(false) {}
diff --git a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h index 9a842c3a..73eafe8a 100644 --- a/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h +++ b/third_party/WebKit/Source/platform/graphics/DeferredImageDecoder.h
@@ -98,16 +98,16 @@ // Copy of the data that is passed in, used by deferred decoding. // Allows creating readonly snapshots that may be read in another thread. std::unique_ptr<SkRWBuffer> rw_buffer_; - bool all_data_received_; std::unique_ptr<ImageDecoder> actual_decoder_; String filename_extension_; IntSize size_; int repetition_count_; bool has_embedded_color_space_ = false; - sk_sp<SkColorSpace> color_space_for_sk_images_; + bool all_data_received_; bool can_yuv_decode_; bool has_hot_spot_; + sk_sp<SkColorSpace> color_space_for_sk_images_; IntPoint hot_spot_; // Caches frame state information.
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp index b683998..20054d2 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp +++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -1051,44 +1051,30 @@ void GraphicsLayer::SetContentsToImage( Image* image, RespectImageOrientationEnum respect_image_orientation) { - sk_sp<SkImage> sk_image; - PaintImage::AnimationType animation_type = PaintImage::AnimationType::UNKNOWN; - PaintImage::CompletionState completion_state = - PaintImage::CompletionState::UNKNOWN; - if (image) { - sk_image = image->ImageForCurrentFrame(); - animation_type = image->MaybeAnimated() - ? PaintImage::AnimationType::ANIMATED - : PaintImage::AnimationType::STATIC; - completion_state = image->CurrentFrameIsComplete() - ? PaintImage::CompletionState::DONE - : PaintImage::CompletionState::PARTIALLY_DONE; + PaintImage paint_image; + if (image) + paint_image = image->PaintImageForCurrentFrame(); + + if (paint_image && image->IsBitmapImage() && + respect_image_orientation == kRespectImageOrientation) { + ImageOrientation image_orientation = + ToBitmapImage(image)->CurrentFrameOrientation(); + paint_image = + DragImage::ResizeAndOrientImage(paint_image, image_orientation); } - if (image && sk_image && image->IsBitmapImage()) { - if (respect_image_orientation == kRespectImageOrientation) { - ImageOrientation image_orientation = - ToBitmapImage(image)->CurrentFrameOrientation(); - sk_image = DragImage::ResizeAndOrientImage(std::move(sk_image), - image_orientation); - } - } - - if (image && sk_image) { + if (paint_image) { if (!image_layer_) { image_layer_ = Platform::Current()->CompositorSupport()->CreateImageLayer(); RegisterContentsLayer(image_layer_->Layer()); } - image_layer_->SetImage( - PaintImage(std::move(sk_image), animation_type, completion_state)); + image_layer_->SetImage(std::move(paint_image)); image_layer_->Layer()->SetOpaque(image->CurrentFrameKnownToBeOpaque()); UpdateContentsRect(); - } else { - if (image_layer_) { - UnregisterContentsLayer(image_layer_->Layer()); - image_layer_.reset(); - } + } else if (image_layer_) { + UnregisterContentsLayer(image_layer_->Layer()); + image_layer_.reset(); } SetContentsTo(image_layer_ ? image_layer_->Layer() : 0);
diff --git a/third_party/WebKit/Source/platform/graphics/Image.cpp b/third_party/WebKit/Source/platform/graphics/Image.cpp index 232adc4..8af49d6 100644 --- a/third_party/WebKit/Source/platform/graphics/Image.cpp +++ b/third_party/WebKit/Source/platform/graphics/Image.cpp
@@ -52,7 +52,7 @@ namespace blink { Image::Image(ImageObserver* observer) - : image_observer_(observer), image_observer_disabled_(false) {} + : image_observer_disabled_(false), image_observer_(observer) {} Image::~Image() {} @@ -225,32 +225,24 @@ namespace { -sk_sp<PaintShader> CreatePatternShader(sk_sp<const SkImage> image, +sk_sp<PaintShader> CreatePatternShader(const PaintImage& image, const SkMatrix& shader_matrix, const PaintFlags& paint, const FloatSize& spacing, SkShader::TileMode tmx, - SkShader::TileMode tmy, - bool animated, - bool complete) { + SkShader::TileMode tmy) { if (spacing.IsZero()) - return MakePaintShaderImage(image, tmx, tmy, &shader_matrix); + return MakePaintShaderImage(image.sk_image(), tmx, tmy, &shader_matrix); // Arbitrary tiling is currently only supported for SkPictureShader, so we use // that instead of a plain bitmap shader to implement spacing. - const SkRect tile_rect = SkRect::MakeWH(image->width() + spacing.Width(), - image->height() + spacing.Height()); + const SkRect tile_rect = + SkRect::MakeWH(image.sk_image()->width() + spacing.Width(), + image.sk_image()->height() + spacing.Height()); PaintRecorder recorder; PaintCanvas* canvas = recorder.beginRecording(tile_rect); - auto animation_type = animated ? PaintImage::AnimationType::ANIMATED - : PaintImage::AnimationType::STATIC; - auto completion_state = complete - ? PaintImage::CompletionState::DONE - : PaintImage::CompletionState::PARTIALLY_DONE; - canvas->drawImage( - PaintImage(std::move(image), animation_type, completion_state), 0, 0, - &paint); + canvas->drawImage(image, 0, 0, &paint); return MakePaintShaderRecord(recorder.finishRecordingAsPicture(), tmx, tmy, &shader_matrix, nullptr); @@ -276,13 +268,14 @@ const FloatSize& repeat_spacing) { TRACE_EVENT0("skia", "Image::drawPattern"); - sk_sp<SkImage> image = ImageForCurrentFrame(); + PaintImage image = PaintImageForCurrentFrame(); if (!image) return; FloatRect norm_src_rect = float_src_rect; - norm_src_rect.Intersect(FloatRect(0, 0, image->width(), image->height())); + norm_src_rect.Intersect( + FloatRect(0, 0, image.sk_image()->width(), image.sk_image()->height())); if (dest_rect.IsEmpty() || norm_src_rect.IsEmpty()) return; // nothing to draw @@ -301,15 +294,17 @@ local_matrix.preScale(scale.Width(), scale.Height()); // Fetch this now as subsetting may swap the image. - auto image_id = image->uniqueID(); + auto image_id = image.sk_image()->uniqueID(); - image = image->makeSubset(EnclosingIntRect(norm_src_rect)); + image = + PaintImage(image.sk_image()->makeSubset(EnclosingIntRect(norm_src_rect)), + image.animation_type(), image.completion_state()); if (!image) return; const FloatSize tile_size( - image->width() * scale.Width() + repeat_spacing.Width(), - image->height() * scale.Height() + repeat_spacing.Height()); + image.sk_image()->width() * scale.Width() + repeat_spacing.Width(), + image.sk_image()->height() * scale.Height() + repeat_spacing.Height()); const auto tmx = ComputeTileMode(dest_rect.X(), dest_rect.MaxX(), adjusted_x, adjusted_x + tile_size.Width()); const auto tmy = ComputeTileMode(dest_rect.Y(), dest_rect.MaxY(), adjusted_y, @@ -322,10 +317,10 @@ context.ComputeFilterQuality(this, dest_rect, norm_src_rect)); flags.setAntiAlias(context.ShouldAntialias()); flags.setShader( - CreatePatternShader(std::move(image), local_matrix, flags, + CreatePatternShader(image, local_matrix, flags, FloatSize(repeat_spacing.Width() / scale.Width(), repeat_spacing.Height() / scale.Height()), - tmx, tmy, MaybeAnimated(), CurrentFrameIsComplete())); + tmx, tmy)); // If the shader could not be instantiated (e.g. non-invertible matrix), // draw transparent. // Note: we can't simply bail, because of arbitrary blend mode. @@ -344,6 +339,15 @@ return image.Release(); } +PaintImage Image::PaintImageForCurrentFrame() { + auto animation_type = MaybeAnimated() ? PaintImage::AnimationType::ANIMATED + : PaintImage::AnimationType::STATIC; + auto completion_state = CurrentFrameIsComplete() + ? PaintImage::CompletionState::DONE + : PaintImage::CompletionState::PARTIALLY_DONE; + return PaintImage(ImageForCurrentFrame(), animation_type, completion_state); +} + bool Image::ApplyShader(PaintFlags& flags, const SkMatrix& local_matrix) { // Default shader impl: attempt to build a shader based on the current frame // SkImage.
diff --git a/third_party/WebKit/Source/platform/graphics/Image.h b/third_party/WebKit/Source/platform/graphics/Image.h index 869a0477..64b4b264 100644 --- a/third_party/WebKit/Source/platform/graphics/Image.h +++ b/third_party/WebKit/Source/platform/graphics/Image.h
@@ -37,6 +37,7 @@ #include "platform/graphics/ImageOrientation.h" #include "platform/graphics/paint/PaintCanvas.h" #include "platform/graphics/paint/PaintFlags.h" +#include "platform/graphics/paint/PaintImage.h" #include "platform/wtf/Assertions.h" #include "platform/wtf/Noncopyable.h" #include "platform/wtf/PassRefPtr.h" @@ -154,6 +155,8 @@ virtual sk_sp<SkImage> ImageForCurrentFrame() = 0; virtual PassRefPtr<Image> ImageForDefaultFrame(); + PaintImage PaintImageForCurrentFrame(); + enum ImageClampingMode { kClampImageToSourceRect, kDoNotClampImageToSourceRect @@ -209,6 +212,7 @@ const FloatSize& repeat_spacing = FloatSize()); private: + bool image_observer_disabled_; RefPtr<SharedBuffer> encoded_image_data_; // TODO(Oilpan): consider having Image on the Oilpan heap and // turn this into a Member<>. @@ -216,7 +220,6 @@ // The observer (an ImageResourceContent) is an untraced member, with the // ImageResourceContent being responsible for clearing itself out. UntracedMember<ImageObserver> image_observer_; - bool image_observer_disabled_; }; #define DEFINE_IMAGE_TYPE_CASTS(typeName) \
diff --git a/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.cpp b/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.cpp index 4e9bd68..ffa76632 100644 --- a/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.cpp +++ b/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.cpp
@@ -29,22 +29,15 @@ const FloatRect& dst_rect, const FloatRect& src_rect, ImageClampingMode clamp_mode, - sk_sp<SkImage> image) { + const PaintImage& image) { FloatRect adjusted_src_rect = src_rect; - adjusted_src_rect.Intersect(SkRect::Make(image->bounds())); + adjusted_src_rect.Intersect(SkRect::Make(image.sk_image()->bounds())); if (dst_rect.IsEmpty() || adjusted_src_rect.IsEmpty()) return; // Nothing to draw. - auto animation_type = MaybeAnimated() ? PaintImage::AnimationType::ANIMATED - : PaintImage::AnimationType::STATIC; - auto completion_state = CurrentFrameIsComplete() - ? PaintImage::CompletionState::DONE - : PaintImage::CompletionState::PARTIALLY_DONE; - canvas->drawImageRect( - PaintImage(std::move(image), animation_type, completion_state), - adjusted_src_rect, dst_rect, &flags, - WebCoreClampingModeToSkiaRectConstraint(clamp_mode)); + canvas->drawImageRect(image, adjusted_src_rect, dst_rect, &flags, + WebCoreClampingModeToSkiaRectConstraint(clamp_mode)); } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.h b/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.h index 383fef2..6dbde204 100644 --- a/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.h +++ b/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.h
@@ -72,7 +72,7 @@ const FloatRect&, const FloatRect&, ImageClampingMode, - sk_sp<SkImage>); + const PaintImage&); // These two properties are here because the SkImage API doesn't expose the // info. They applied to both UnacceleratedStaticBitmapImage and
diff --git a/third_party/WebKit/Source/platform/graphics/UnacceleratedStaticBitmapImage.cpp b/third_party/WebKit/Source/platform/graphics/UnacceleratedStaticBitmapImage.cpp index ce8205ef..16c5f4eb 100644 --- a/third_party/WebKit/Source/platform/graphics/UnacceleratedStaticBitmapImage.cpp +++ b/third_party/WebKit/Source/platform/graphics/UnacceleratedStaticBitmapImage.cpp
@@ -36,7 +36,7 @@ RespectImageOrientationEnum, ImageClampingMode clamp_mode) { StaticBitmapImage::DrawHelper(canvas, flags, dst_rect, src_rect, clamp_mode, - image_); + PaintImageForCurrentFrame()); } sk_sp<SkImage> UnacceleratedStaticBitmapImage::ImageForCurrentFrame() {
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceStatus.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceStatus.h index 47f2f29..1758503 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceStatus.h +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceStatus.h
@@ -7,7 +7,7 @@ namespace blink { -enum class ResourceStatus { +enum class ResourceStatus : uint8_t { kNotStarted, kPending, // load in progress kCached, // load completed successfully
diff --git a/third_party/WebKit/Source/platform/mojo/KURLSecurityOriginTest.cpp b/third_party/WebKit/Source/platform/mojo/KURLSecurityOriginTest.cpp index 942c407..417f3234 100644 --- a/third_party/WebKit/Source/platform/mojo/KURLSecurityOriginTest.cpp +++ b/third_party/WebKit/Source/platform/mojo/KURLSecurityOriginTest.cpp
@@ -78,12 +78,22 @@ SecurityOrigin::Create("http", "www.google.com", 80); RefPtr<SecurityOrigin> output; EXPECT_TRUE(proxy->BounceOrigin(non_unique, &output)); + EXPECT_TRUE(non_unique->IsSameSchemeHostPortAndSuborigin(output.Get())); EXPECT_TRUE(non_unique->IsSameSchemeHostPort(output.Get())); - EXPECT_FALSE(non_unique->IsUnique()); + EXPECT_FALSE(output->HasSuborigin()); + EXPECT_FALSE(output->IsUnique()); RefPtr<SecurityOrigin> unique = SecurityOrigin::CreateUnique(); EXPECT_TRUE(proxy->BounceOrigin(unique, &output)); EXPECT_TRUE(output->IsUnique()); + + RefPtr<SecurityOrigin> with_sub_origin = + SecurityOrigin::Create("http", "www.google.com", 80, "suborigin"); + EXPECT_TRUE(proxy->BounceOrigin(with_sub_origin, &output)); + EXPECT_TRUE(with_sub_origin->IsSameSchemeHostPortAndSuborigin(output.Get())); + EXPECT_TRUE(with_sub_origin->IsSameSchemeHostPort(output.Get())); + EXPECT_TRUE(output->HasSuborigin()); + EXPECT_FALSE(output->IsUnique()); } } // namespace url
diff --git a/third_party/WebKit/Source/platform/mojo/SecurityOriginStructTraits.h b/third_party/WebKit/Source/platform/mojo/SecurityOriginStructTraits.h index e77529d..88551da 100644 --- a/third_party/WebKit/Source/platform/mojo/SecurityOriginStructTraits.h +++ b/third_party/WebKit/Source/platform/mojo/SecurityOriginStructTraits.h
@@ -23,6 +23,10 @@ static uint16_t port(const RefPtr<::blink::SecurityOrigin>& origin) { return origin->EffectivePort(); } + static WTF::String suborigin(const RefPtr<::blink::SecurityOrigin>& origin) { + WTF::String suborigin = origin->GetSuborigin()->GetName(); + return suborigin.IsNull() ? "" : suborigin; + } static bool unique(const RefPtr<::blink::SecurityOrigin>& origin) { return origin->IsUnique(); } @@ -33,10 +37,13 @@ } else { WTF::String scheme; WTF::String host; - if (!data.ReadScheme(&scheme) || !data.ReadHost(&host)) + WTF::String suborigin; + if (!data.ReadScheme(&scheme) || !data.ReadHost(&host) || + !data.ReadSuborigin(&suborigin)) return false; - *out = ::blink::SecurityOrigin::Create(scheme, host, data.port()); + *out = + ::blink::SecurityOrigin::Create(scheme, host, data.port(), suborigin); } // If a unique origin was created, but the unique flag wasn't set, then
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn index 0ea43ca..07257e5 100644 --- a/third_party/WebKit/Source/web/BUILD.gn +++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -123,9 +123,6 @@ "ValidationMessageClientImpl.cpp", "ValidationMessageClientImpl.h", "WebAXObject.cpp", - "WebArrayBuffer.cpp", - "WebArrayBufferConverter.cpp", - "WebArrayBufferView.cpp", "WebCSSParser.cpp", "WebColorSuggestion.cpp", "WebCryptoNormalize.cpp",
diff --git a/third_party/binutils/Linux_ia32/binutils.tar.bz2.sha1 b/third_party/binutils/Linux_ia32/binutils.tar.bz2.sha1 index 7fd1a938..c07eb32 100644 --- a/third_party/binutils/Linux_ia32/binutils.tar.bz2.sha1 +++ b/third_party/binutils/Linux_ia32/binutils.tar.bz2.sha1
@@ -1 +1 @@ -24f937cfdad77bdcd6ad8cacc542d806f3eb4b0f \ No newline at end of file +0ba2f98a7d104eabe3a21ad30a3045526d241602 \ No newline at end of file
diff --git a/third_party/binutils/Linux_x64/binutils.tar.bz2.sha1 b/third_party/binutils/Linux_x64/binutils.tar.bz2.sha1 index 1434c333..7ad0a65 100644 --- a/third_party/binutils/Linux_x64/binutils.tar.bz2.sha1 +++ b/third_party/binutils/Linux_x64/binutils.tar.bz2.sha1
@@ -1 +1 @@ -d9064388bed0e7225b1366d80b59289b1509d7c2 \ No newline at end of file +5e71702981e5f3b45632f2f209eb3a85d65ca764 \ No newline at end of file
diff --git a/third_party/binutils/README.chromium b/third_party/binutils/README.chromium index a95ae3e..85714a9b 100644 --- a/third_party/binutils/README.chromium +++ b/third_party/binutils/README.chromium
@@ -27,6 +27,10 @@ https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=d114b830426300f80302ca03ff4322942f63c615 (Landed upstream on 2.26 branch Thu, 5 May 2016, and on trunk Fri, 5 Feb 2016 - will be in 2.27) + * icf-align.patch for https://sourceware.org/bugzilla/show_bug.cgi?id=17704 + from upstream change + https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=ac423761af22f7858a1413cda5df3e1d5e88d4e4 + (Landed upstream Fri, 21 Oct 2016 - is in 2.28) * (build-all.sh|build-one.sh|upload.sh) scripts for building the binutils binaries and uploading them to Google storage.
diff --git a/third_party/binutils/build-all.sh b/third_party/binutils/build-all.sh index b203699f..1e3d4eb 100755 --- a/third_party/binutils/build-all.sh +++ b/third_party/binutils/build-all.sh
@@ -56,6 +56,11 @@ patch -p1 < ../icf-rel.patch echo "----------------------------------" echo + echo "icf-align.patch" + echo "==================================" + patch -p1 < ../icf-align.patch + echo "----------------------------------" + echo ) for ARCH in i386 amd64; do
diff --git a/third_party/binutils/icf-align.patch b/third_party/binutils/icf-align.patch new file mode 100644 index 0000000..719f019 --- /dev/null +++ b/third_party/binutils/icf-align.patch
@@ -0,0 +1,126 @@ +commit ac423761af22f7858a1413cda5df3e1d5e88d4e4 +Author: Gergely Nagy <ngg@tresorit.com> +Date: Fri Oct 21 11:08:20 2016 -0700 + + Fix PR 17704. + + This fix keeps the section with the highest alignment when folding sections with ICF. + + PR gold/17704 + * icf.cc (match_sections): Add new parameter section_addraligns. + Check section alignment and keep the section with the strictest + alignment. + (find_identical_sections): New local variable section_addraligns. + Store each section's alignment. + * testsuite/pr17704a_test.s: New file. + * testsuite/Makefile.am (pr17704a_test): New test. + * testsuite/Makefile.in: Regenerate. + +diff --git a/gold/icf.cc b/gold/icf.cc +index dce0b8b3e2..c09c746ae1 100644 +--- a/gold/icf.cc ++++ b/gold/icf.cc +@@ -590,6 +590,7 @@ match_sections(unsigned int iteration_num, + std::vector<unsigned int>* num_tracked_relocs, + std::vector<unsigned int>* kept_section_id, + const std::vector<Section_id>& id_section, ++ const std::vector<uint64_t>& section_addraligns, + std::vector<bool>* is_secn_or_group_unique, + std::vector<std::string>* section_contents) + { +@@ -630,13 +631,7 @@ match_sections(unsigned int iteration_num, + { + if ((*kept_section_id)[i] != i) + { +- // This section is already folded into something. See +- // if it should point to a different kept section. +- unsigned int kept_section = (*kept_section_id)[i]; +- if (kept_section != (*kept_section_id)[kept_section]) +- { +- (*kept_section_id)[i] = (*kept_section_id)[kept_section]; +- } ++ // This section is already folded into something. + continue; + } + this_secn_contents = get_section_contents(false, secn, i, NULL, +@@ -671,7 +666,25 @@ match_sections(unsigned int iteration_num, + this_secn_contents.c_str(), + this_secn_contents.length()) != 0) + continue; +- (*kept_section_id)[i] = kept_section; ++ ++ // Check section alignment here. ++ // The section with the larger alignment requirement ++ // should be kept. We assume alignment can only be ++ // zero or postive integral powers of two. ++ uint64_t align_i = section_addraligns[i]; ++ uint64_t align_kept = section_addraligns[kept_section]; ++ if (align_i <= align_kept) ++ { ++ (*kept_section_id)[i] = kept_section; ++ } ++ else ++ { ++ (*kept_section_id)[kept_section] = i; ++ it->second = i; ++ full_section_contents[kept_section].swap( ++ full_section_contents[i]); ++ } ++ + converged = false; + break; + } +@@ -688,6 +701,26 @@ match_sections(unsigned int iteration_num, + (*is_secn_or_group_unique)[i] = true; + } + ++ // If a section was folded into another section that was later folded ++ // again then the former has to be updated. ++ for (unsigned int i = 0; i < id_section.size(); i++) ++ { ++ // Find the end of the folding chain ++ unsigned int kept = i; ++ while ((*kept_section_id)[kept] != kept) ++ { ++ kept = (*kept_section_id)[kept]; ++ } ++ // Update every element of the chain ++ unsigned int current = i; ++ while ((*kept_section_id)[current] != kept) ++ { ++ unsigned int next = (*kept_section_id)[current]; ++ (*kept_section_id)[current] = kept; ++ current = next; ++ } ++ } ++ + return converged; + } + +@@ -719,6 +752,7 @@ Icf::find_identical_sections(const Input_objects* input_objects, + { + unsigned int section_num = 0; + std::vector<unsigned int> num_tracked_relocs; ++ std::vector<uint64_t> section_addraligns; + std::vector<bool> is_secn_or_group_unique; + std::vector<std::string> section_contents; + const Target& target = parameters->target(); +@@ -759,6 +793,7 @@ Icf::find_identical_sections(const Input_objects* input_objects, + this->section_id_[Section_id(*p, i)] = section_num; + this->kept_section_id_.push_back(section_num); + num_tracked_relocs.push_back(0); ++ section_addraligns.push_back((*p)->section_addralign(i)); + is_secn_or_group_unique.push_back(false); + section_contents.push_back(""); + section_num++; +@@ -779,8 +814,8 @@ Icf::find_identical_sections(const Input_objects* input_objects, + num_iterations++; + converged = match_sections(num_iterations, symtab, + &num_tracked_relocs, &this->kept_section_id_, +- this->id_section_, &is_secn_or_group_unique, +- §ion_contents); ++ this->id_section_, section_addraligns, ++ &is_secn_or_group_unique, §ion_contents); + } + + if (parameters->options().print_icf_sections())
diff --git a/tools/blink_rename_merge_helper/data/idl_blocklist.txt b/tools/blink_rename_merge_helper/data/idl_blocklist.txt index af7d04e5..d681352 100644 --- a/tools/blink_rename_merge_helper/data/idl_blocklist.txt +++ b/tools/blink_rename_merge_helper/data/idl_blocklist.txt
@@ -4867,8 +4867,6 @@ SharedWorkerGlobalScope:::setOnconnect:::1 SharedWorkerPerformance:::workerStart:::2 SharedWorker:::port:::0 -SiteBoundCredential:::iconURL:::0 -SiteBoundCredential:::name:::0 SourceBuffer:::abort:::1 SourceBuffer:::appendBuffer:::2 SourceBuffer:::appendWindowEnd:::0
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer.cc b/tools/ipc_fuzzer/fuzzer/fuzzer.cc index 159ee81f..a8d3c6c 100644 --- a/tools/ipc_fuzzer/fuzzer/fuzzer.cc +++ b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
@@ -1616,14 +1616,17 @@ std::string scheme = p->scheme(); std::string host = p->host(); uint16_t port = p->port(); + std::string suborigin = p->suborigin(); if (!FuzzParam(&scheme, fuzzer)) return false; if (!FuzzParam(&host, fuzzer)) return false; if (!FuzzParam(&port, fuzzer)) return false; + if (!FuzzParam(&suborigin, fuzzer)) + return false; *p = url::Origin::UnsafelyCreateOriginWithoutNormalization(scheme, host, - port); + port, suborigin); // Force a unique origin 1% of the time: if (RandInRange(100) == 1)
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 49b780c..eaf175f 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -1694,7 +1694,10 @@ 'goma': { # The MB code will properly escape goma_dir if necessary in the GYP # code path; the GN code path needs no escaping. - 'gn_args': 'use_goma=true', + # We also set strip_absolute_paths to ensure that we can get deterministic + # builds. This isn't just on by default when goma is on so that devs + # can do goma builds but still be able to debug by default. + 'gn_args': 'use_goma=true strip_absolute_paths_from_debug_symbols=true', }, 'gpu_fyi_tests': { @@ -1745,7 +1748,7 @@ }, 'minimal_symbols': { - 'gn_args': 'symbol_level=1 strip_absolute_paths_from_debug_symbols=true', + 'gn_args': 'symbol_level=1', }, 'mipsel': {
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index f6914c72..ae4e8be0 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -1122,6 +1122,38 @@ <description>User closed the Chrome Home bottom sheet.</description> </action> +<action name="Android.ChromeHome.ClosedByNTPCloseButton"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User closed the Chrome Home bottom sheet using the NTP's close button. + </description> +</action> + +<action name="Android.ChromeHome.ClosedByNavigation"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User closed the Chrome Home bottom sheet by navigating. + </description> +</action> + +<action name="Android.ChromeHome.ClosedBySwipe"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User closed the Chrome Home bottom sheet using a swipe gesture. + </description> +</action> + +<action name="Android.ChromeHome.ClosedByTapScrim"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User closed the Chrome Home bottom sheet tapping the scrim behind the sheet. + </description> +</action> + <action name="Android.ChromeHome.FullState"> <owner>mdjones@chromium.org</owner> <owner>twellington@chromium.org</owner> @@ -1142,6 +1174,42 @@ <owner>mdjones@chromium.org</owner> <owner>twellington@chromium.org</owner> <description>User opened the Chrome Home bottom sheet.</description> + <obsolete> + Deprecated 5/2017. Replaced by the versions with a suffix, which are more + descriptive. + </obsolete> +</action> + +<action name="Android.ChromeHome.OpenedByExpandButton"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User opened the Chrome Home bottom sheet using the expand button. + </description> +</action> + +<action name="Android.ChromeHome.OpenedByNTP"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User opened the Chrome Home bottom sheet by opening a new tab. + </description> +</action> + +<action name="Android.ChromeHome.OpenedByOmnibox"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User opened the Chrome Home bottom sheet by focusing the omnibox. + </description> +</action> + +<action name="Android.ChromeHome.OpenedBySwipe"> + <owner>mdjones@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <description> + User opened the Chrome Home bottom sheet using a swipe gesture. + </description> </action> <action name="Android.ChromeHome.ShowBookmarks"> @@ -15831,6 +15899,62 @@ <description>Please enter the description of this user action.</description> </action> +<action name="Suggestions.Card.ActionTapped"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description> + User tapped on a card's button in the content suggestions UI. + </description> +</action> + +<action name="Suggestions.Card.SwipedAway"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description> + User swiped a card away in the content suggestions UI. + </description> +</action> + +<action name="Suggestions.Card.Tapped"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description> + User tapped on a card in the content suggestions UI. + </description> +</action> + +<action name="Suggestions.Category.Dismissed"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description>User dismissed a content suggestions category.</description> +</action> + +<action name="Suggestions.Category.Fetch"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description>User requested fetching more content suggestions.</description> +</action> + +<action name="Suggestions.Category.ViewAll"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description> + User navigated to the complete view of a content suggestions section. + </description> +</action> + +<action name="Suggestions.Content.Dismissed"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description>User dismissed a content suggestion.</description> +</action> + +<action name="Suggestions.Content.Opened"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description>User opened a content suggestion.</description> +</action> + <action name="Suggestions.ContextMenu.DownloadItem"> <owner>mvanouwerkerk@chromium.org</owner> <owner>galinap@google.com</owner> @@ -15881,6 +16005,30 @@ </description> </action> +<action name="Suggestions.Site.RemovalUndone"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description>User reverted the removal of a suggested site.</description> +</action> + +<action name="Suggestions.Site.Removed"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description>User removed a suggested site.</description> +</action> + +<action name="Suggestions.SurfaceHidden"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description>User closed the content suggestions UI.</description> +</action> + +<action name="Suggestions.SurfaceVisible"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description>User opened the content suggestions UI.</description> +</action> + <action name="Suggestions.Tile.RemovalUndone"> <owner>mvanouwerkerk@chromium.org</owner> <owner>galinap@google.com</owner> @@ -15888,6 +16036,18 @@ Android: User tapped the undo button in the snackbar after removing a suggested item. </description> + <obsolete> + Deprecated as of 05/2017. Now recorded as + "Suggestions.Site.RemovalUndone". + </obsolete> +</action> + +<action name="Suggestions.Tile.Tapped"> + <owner>finkm@chromium.org</owner> + <owner>dgn@chromium.org</owner> + <description> + User tapped on a tile in the content suggestions UI. + </description> </action> <action name="SuspiciousExtensionBubbleDismissed"> @@ -16322,6 +16482,13 @@ <description>Please enter the description of this user action.</description> </action> +<action name="Tray_NightLight"> + <owner>afakhry@chromium.org</owner> + <description> + Records when the user toggles the Night Light feature on/off. + </description> +</action> + <action name="Tray_Overview"> <owner>bruthig@chromium.org</owner> <owner>tdanderson@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 4de19ab..b6c66639 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -12189,6 +12189,7 @@ <int value="1170" label="WEBRTC_AUDIO_PRIVATE_SET_AUDIO_EXPERIMENTS"/> <int value="1171" label="AUTOTESTPRIVATE_GETPLAYSTORESTATE"/> <int value="1172" label="AUTOTESTPRIVATE_SETPLAYSTOREENABLED"/> + <int value="1173" label="APP_CURRENTWINDOWINTERNAL_SETACTIVATEONPOINTER"/> </enum> <enum name="ExtensionIconState" type="int"> @@ -18748,6 +18749,7 @@ <int value="72" label="SEARCH_GEOLOCATION_DISCLOSURE_INFOBAR_DELEGATE"/> <int value="73" label="AUTOMATION_INFOBAR_DELEGATE"/> <int value="74" label="VR_SERVICES_UPGRADE_ANDROID"/> + <int value="75" label="READER_MODE_INFOBAR_ANDROID"/> </enum> <enum name="InfoBarResponse" type="int">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index ba76f7b..c309a7f 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -79006,6 +79006,17 @@ </summary> </histogram> +<histogram name="WebApk.Update.GooglePlayUpdateResult" + enum="WebApkGooglePlayInstallResult"> + <owner>hanxi@chromium.org</owner> + <owner>pkotwicz@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + Records whether updating a WebAPK from Google Play succeeded. If not, + records the reason that the update failed. + </summary> +</histogram> + <histogram name="WebApk.Update.RequestQueued" enum="WebApkUpdateRequestQueued"> <owner>hanxi@chromium.org</owner> <owner>pkotwicz@chromium.org</owner>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index 3acd28c3..06f9418 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -39,12 +39,9 @@ loading.mobile,"kouhei@chromium.org, ksakamoto@chromium.org", media.android.tough_video_cases,"crouleau@chromium.org, videostack-eng@google.com",Internals>Media media.android.tough_video_cases_tbmv2,"johnchen@chromium.org, crouleau@chromium.org",Internals>Media -media.chromeOS.tough_video_cases,crouleau@chromium.org,Internals>Media -media.chromeOS4kOnly.tough_video_cases,crouleau@chromium.org,Internals>Media media.media_cns_cases,"crouleau@chromium.org, videostack-eng@google.com",Internals>Media media.mse_cases,"crouleau@chromium.org, videostack-eng@google.com",Internals>Media>Source media.tough_video_cases,crouleau@chromium.org,Internals>Media -media.tough_video_cases_extra,"crouleau@chromium.org, videostack-eng@google.com",Internals>Media media.tough_video_cases_tbmv2,"johnchen@chromium.org, crouleau@chromium.org",Internals>Media media_perftests,crouleau@chromium.org, memory.blink_memory_mobile,bashi@chromium.org,
diff --git a/tools/perf/benchmarks/media.py b/tools/perf/benchmarks/media.py index e56c079..0469ca2c 100644 --- a/tools/perf/benchmarks/media.py +++ b/tools/perf/benchmarks/media.py
@@ -40,7 +40,6 @@ # android: See media.android.tough_video_cases below -# crbug.com/565180: Only include cases that report time_to_play @benchmark.Owner(emails=['crouleau@chromium.org'], component='Internals>Media') @benchmark.Disabled('android') @@ -54,6 +53,26 @@ return 'media.tough_video_cases' +@benchmark.Enabled('android') +@benchmark.Disabled('l', 'android-webview') # WebView: crbug.com/419689. +@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'], + component='Internals>Media') +class MediaAndroidToughVideoCases(perf_benchmark.PerfBenchmark): + """Obtains media metrics for key user scenarios on Android.""" + test = media.Media + tag = 'android' + page_set = page_sets.ToughVideoCasesPageSet + options = {'story_tag_filter_exclude': 'is_4k,is_50fps'} + + @classmethod + def ShouldDisable(cls, possible_browser): + return cls.IsSvelte(possible_browser) + + @classmethod + def Name(cls): + return 'media.android.tough_video_cases' + + class _MediaTBMv2Benchmark(perf_benchmark.PerfBenchmark): page_set = page_sets.ToughVideoCasesPageSet @@ -73,6 +92,7 @@ return options +# android: See media.android.tough_video_cases below @benchmark.Owner(emails=['johnchen@chromium.org', 'crouleau@chromium.org'], component='Internals>Media') @benchmark.Disabled('android') @@ -85,54 +105,6 @@ return 'media.tough_video_cases_tbmv2' -# crbug.com/565180: Only include cases that don't report time_to_play -@benchmark.Disabled('android') -@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'], - component='Internals>Media') -class MediaExtra(perf_benchmark.PerfBenchmark): - """Obtains extra media metrics for key user scenarios.""" - test = media.Media - page_set = page_sets.ToughVideoCasesExtraPageSet - - @classmethod - def Name(cls): - return 'media.tough_video_cases_extra' - - -@benchmark.Disabled('all') # crbug/676345 -@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'], - component='Internals>Media') -class MediaNetworkSimulation(perf_benchmark.PerfBenchmark): - """Obtains media metrics under different network simulations.""" - test = media.Media - page_set = page_sets.MediaCnsCasesPageSet - - @classmethod - def Name(cls): - return 'media.media_cns_cases' - - -@benchmark.Disabled('l', 'android-webview') # WebView: crbug.com/419689. -@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'], - component='Internals>Media') -class MediaAndroidToughVideoCases(perf_benchmark.PerfBenchmark): - """Obtains media metrics for key user scenarios on Android.""" - test = media.Media - tag = 'android' - page_set = page_sets.ToughVideoCasesPageSet - options = {'story_tag_filter_exclude': 'is_4k,is_50fps'} - - @classmethod - def ShouldDisable(cls, possible_browser): - if possible_browser.platform.GetOSName() != "android": - return True - return cls.IsSvelte(possible_browser) - - @classmethod - def Name(cls): - return 'media.android.tough_video_cases' - - @benchmark.Owner(emails=['johnchen@chromium.org', 'crouleau@chromium.org'], component='Internals>Media') @benchmark.Enabled('android') @@ -166,46 +138,17 @@ '--disable-gesture-requirement-for-media-playback']) -# This isn't running anywhere. See crbug/709161. -@benchmark.Enabled('chromeos') -@benchmark.Owner(emails=['crouleau@chromium.org'], +@benchmark.Disabled('all') # crbug/676345 +@benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'], component='Internals>Media') -class MediaChromeOS4kOnly(perf_benchmark.PerfBenchmark): - """Benchmark for media performance on ChromeOS using only is_4k test content. - """ +class MediaNetworkSimulation(perf_benchmark.PerfBenchmark): + """Obtains media metrics under different network simulations.""" test = media.Media - tag = 'chromeOS4kOnly' - page_set = page_sets.ToughVideoCasesPageSet - options = { - 'story_tag_filter': 'is_4k', - # Exclude is_50fps test files: crbug/331816 - 'story_tag_filter_exclude': 'is_50fps' - } + page_set = page_sets.MediaCnsCasesPageSet @classmethod def Name(cls): - return 'media.chromeOS4kOnly.tough_video_cases' - - -# This isn't running anywhere. See crbug/709161. -@benchmark.Enabled('chromeos') -@benchmark.Owner(emails=['crouleau@chromium.org'], - component='Internals>Media') -class MediaChromeOS(perf_benchmark.PerfBenchmark): - """Benchmark for media performance on all ChromeOS platforms. - - This benchmark does not run is_4k content, there's a separate benchmark for - that. - """ - test = media.Media - tag = 'chromeOS' - page_set = page_sets.ToughVideoCasesPageSet - # Exclude is_50fps test files: crbug/331816 - options = {'story_tag_filter_exclude': 'is_4k,is_50fps'} - - @classmethod - def Name(cls): - return 'media.chromeOS.tough_video_cases' + return 'media.media_cns_cases' @benchmark.Disabled('android-webview') # crbug.com/419689
diff --git a/tools/perf/page_sets/tough_video_cases.py b/tools/perf/page_sets/tough_video_cases.py index bc1004d6..52fee99 100644 --- a/tools/perf/page_sets/tough_video_cases.py +++ b/tools/perf/page_sets/tough_video_cases.py
@@ -22,6 +22,9 @@ # Other filter tags: 'is_50fps', 'is_4k', + # Play action + 'seek', + 'normal_play', ] @@ -75,7 +78,7 @@ super(Page4, self).__init__( url='file://tough_video_cases/video.html?src=crowd1080.webm', page_set=page_set, - tags=['is_50fps', 'vp8', 'vorbis', 'audio_video']) + tags=['is_50fps', 'vp8', 'vorbis', 'audio_video', 'normal_play']) self.add_browser_metrics = True @@ -89,7 +92,7 @@ super(Page7, self).__init__( url='file://tough_video_cases/video.html?src=tulip2.ogg&type=audio', page_set=page_set, - tags=['vorbis', 'audio_only']) + tags=['vorbis', 'audio_only', 'normal_play']) self.add_browser_metrics = True @@ -103,7 +106,7 @@ super(Page8, self).__init__( url='file://tough_video_cases/video.html?src=tulip2.wav&type=audio', page_set=page_set, - tags=['pcm', 'audio_only']) + tags=['pcm', 'audio_only', 'normal_play']) self.add_browser_metrics = True @@ -117,7 +120,7 @@ super(Page11, self).__init__( url='file://tough_video_cases/video.html?src=crowd1080.mp4', page_set=page_set, - tags=['is_50fps', 'h264', 'aac', 'audio_video']) + tags=['is_50fps', 'h264', 'aac', 'audio_video', 'normal_play']) self.add_browser_metrics = True @@ -131,7 +134,7 @@ super(Page12, self).__init__( url='file://tough_video_cases/video.html?src=crowd2160.mp4', page_set=page_set, - tags=['is_4k', 'is_50fps', 'h264', 'aac', 'audio_video']) + tags=['is_4k', 'is_50fps', 'h264', 'aac', 'audio_video', 'normal_play']) self.add_browser_metrics = True @@ -145,7 +148,7 @@ super(Page13, self).__init__( url='file://tough_video_cases/video.html?src=tulip2.mp3&type=audio', page_set=page_set, - tags=['mp3', 'audio_only']) + tags=['mp3', 'audio_only', 'normal_play']) self.add_browser_metrics = True @@ -159,7 +162,7 @@ super(Page14, self).__init__( url='file://tough_video_cases/video.html?src=tulip2.mp4', page_set=page_set, - tags=['h264', 'aac', 'audio_video']) + tags=['h264', 'aac', 'audio_video', 'normal_play']) self.add_browser_metrics = True @@ -173,7 +176,7 @@ super(Page15, self).__init__( url='file://tough_video_cases/video.html?src=tulip2.m4a&type=audio', page_set=page_set, - tags=['aac', 'audio_only']) + tags=['aac', 'audio_only', 'normal_play']) self.add_browser_metrics = True @@ -187,7 +190,7 @@ super(Page16, self).__init__( url='file://tough_video_cases/video.html?src=garden2_10s.webm', page_set=page_set, - tags=['is_4k', 'vp8', 'vorbis', 'audio_video']) + tags=['is_4k', 'vp8', 'vorbis', 'audio_video', 'normal_play']) self.add_browser_metrics = True @@ -201,7 +204,7 @@ super(Page17, self).__init__( url='file://tough_video_cases/video.html?src=garden2_10s.mp4', page_set=page_set, - tags=['is_4k', 'h264', 'aac', 'audio_video']) + tags=['is_4k', 'h264', 'aac', 'audio_video', 'normal_play']) self.add_browser_metrics = True @@ -213,9 +216,9 @@ def __init__(self, page_set): super(Page19, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.ogg&type=audio', + url='file://tough_video_cases/video.html?src=tulip2.ogg&type=audio&seek', page_set=page_set, - tags=['vorbis', 'audio_only']) + tags=['vorbis', 'audio_only', 'seek']) self.skip_basic_metrics = True @@ -227,9 +230,9 @@ def __init__(self, page_set): super(Page20, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.wav&type=audio', + url='file://tough_video_cases/video.html?src=tulip2.wav&type=audio&seek', page_set=page_set, - tags=['pcm', 'audio_only']) + tags=['pcm', 'audio_only', 'seek']) self.skip_basic_metrics = True @@ -241,9 +244,9 @@ def __init__(self, page_set): super(Page23, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.mp3&type=audio', + url='file://tough_video_cases/video.html?src=tulip2.mp3&type=audio&seek', page_set=page_set, - tags=['mp3', 'audio_only']) + tags=['mp3', 'audio_only', 'seek']) self.skip_basic_metrics = True @@ -255,9 +258,9 @@ def __init__(self, page_set): super(Page24, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.mp4', + url='file://tough_video_cases/video.html?src=tulip2.mp4&seek', page_set=page_set, - tags=['h264', 'aac', 'audio_video']) + tags=['h264', 'aac', 'audio_video', 'seek']) self.skip_basic_metrics = True @@ -269,9 +272,9 @@ def __init__(self, page_set): super(Page25, self).__init__( - url='file://tough_video_cases/video.html?src=garden2_10s.webm', + url='file://tough_video_cases/video.html?src=garden2_10s.webm&seek', page_set=page_set, - tags=['is_4k', 'vp8', 'vorbis', 'audio_video']) + tags=['is_4k', 'vp8', 'vorbis', 'audio_video', 'seek']) self.skip_basic_metrics = True @@ -283,9 +286,9 @@ def __init__(self, page_set): super(Page26, self).__init__( - url='file://tough_video_cases/video.html?src=garden2_10s.mp4', + url='file://tough_video_cases/video.html?src=garden2_10s.mp4&seek', page_set=page_set, - tags=['is_4k', 'h264', 'aac', 'audio_video']) + tags=['is_4k', 'h264', 'aac', 'audio_video', 'seek']) self.skip_basic_metrics = True @@ -299,86 +302,92 @@ super(Page30, self).__init__( url='file://tough_video_cases/video.html?src=tulip2.vp9.webm', page_set=page_set, - tags=['vp9', 'opus', 'audio_video']) + tags=['vp9', 'opus', 'audio_video', 'normal_play']) self.add_browser_metrics = True def RunPageInteractions(self, action_runner): self.PlayAction(action_runner) + class Page31(ToughVideoCasesPage): def __init__(self, page_set): super(Page31, self).__init__( - url='file://tough_video_cases/video.html?src=tulip2.vp9.webm', + url='file://tough_video_cases/video.html?src=tulip2.vp9.webm&seek', page_set=page_set, - tags=['vp9', 'opus', 'audio_video']) + tags=['vp9', 'opus', 'audio_video', 'seek']) self.skip_basic_metrics = True def RunPageInteractions(self, action_runner): self.SeekBeforeAndAfterPlayhead(action_runner) + class Page32(ToughVideoCasesPage): def __init__(self, page_set): super(Page32, self).__init__( url='file://tough_video_cases/video.html?src=crowd1080_vp9.webm', page_set=page_set, - tags=['vp9', 'video_only']) + tags=['vp9', 'video_only', 'normal_play']) self.add_browser_metrics = True def RunPageInteractions(self, action_runner): self.PlayAction(action_runner) + class Page33(ToughVideoCasesPage): def __init__(self, page_set): super(Page33, self).__init__( - url='file://tough_video_cases/video.html?src=crowd1080_vp9.webm', + url='file://tough_video_cases/video.html?src=crowd1080_vp9.webm&seek', page_set=page_set, - tags=['vp9', 'video_only']) + tags=['vp9', 'video_only', 'seek']) self.skip_basic_metrics = True def RunPageInteractions(self, action_runner): self.SeekBeforeAndAfterPlayhead(action_runner) + class Page34(ToughVideoCasesPage): def __init__(self, page_set): super(Page34, self).__init__( url='file://tough_video_cases/video.html?src=crowd720_vp9.webm', page_set=page_set, - tags=['vp9', 'video_only']) + tags=['vp9', 'video_only', 'normal_play']) self.add_browser_metrics = True def RunPageInteractions(self, action_runner): self.PlayAction(action_runner) + class Page35(ToughVideoCasesPage): def __init__(self, page_set): super(Page35, self).__init__( - url='file://tough_video_cases/video.html?src=crowd720_vp9.webm', + url='file://tough_video_cases/video.html?src=crowd720_vp9.webm&seek', page_set=page_set, - tags=['vp9', 'video_only']) + tags=['vp9', 'video_only', 'seek']) self.skip_basic_metrics = True def RunPageInteractions(self, action_runner): self.SeekBeforeAndAfterPlayhead(action_runner) + class Page36(ToughVideoCasesPage): def __init__(self, page_set): super(Page36, self).__init__( url=('file://tough_video_cases/video.html?src=' - 'smpte_3840x2160_60fps_vp9.webm'), + 'smpte_3840x2160_60fps_vp9.webm&seek'), page_set=page_set, - tags=['is_4k', 'vp9', 'video_only']) + tags=['is_4k', 'vp9', 'video_only', 'seek']) self.add_browser_metrics = True @@ -389,17 +398,14 @@ class ToughVideoCasesPageSet(story.StorySet): """ - Description: Video Stack Perf pages that report time_to_play and many other - media-specific and generic metrics. + Description: Video Stack Perf pages that report time_to_play, seek time and + many other media-specific and generic metrics. """ def __init__(self): super(ToughVideoCasesPageSet, self).__init__( cloud_storage_bucket=story.PARTNER_BUCKET) - # TODO(crouleau): Page 36 is in ToughVideoCasesPageSet even though - # it both reports seek time instead of time_to_play. - # This may be a non-issue because we plan to merge these two page sets back - # together and use tags to allow teams to filter which pages they want. + # Normal play tests: self.AddStory(Page2(self)) self.AddStory(Page4(self)) self.AddStory(Page7(self)) @@ -414,17 +420,8 @@ self.AddStory(Page30(self)) self.AddStory(Page32(self)) self.AddStory(Page34(self)) - self.AddStory(Page36(self)) - -class ToughVideoCasesExtraPageSet(story.StorySet): - """ - Description: Video Stack Perf pages that only report seek time. - """ - def __init__(self): - super(ToughVideoCasesExtraPageSet, self).__init__( - cloud_storage_bucket=story.PARTNER_BUCKET) - + # Seek tests: self.AddStory(Page19(self)) self.AddStory(Page20(self)) self.AddStory(Page23(self)) @@ -434,3 +431,4 @@ self.AddStory(Page31(self)) self.AddStory(Page33(self)) self.AddStory(Page35(self)) + self.AddStory(Page36(self))
diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java index ce76c282..372bbfc 100644 --- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java +++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
@@ -169,7 +169,8 @@ boolean hasCameraPermission = mWindowAndroid.hasPermission(Manifest.permission.CAMERA); if (mSupportsImageCapture && hasCameraPermission) { // GetCameraIntentTask will call LaunchSelectFileWithCameraIntent later. - new GetCameraIntentTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new GetCameraIntentTask(false, mWindowAndroid, this) + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { launchSelectFileWithCameraIntent(hasCameraPermission, null); } @@ -272,18 +273,44 @@ break; case PHOTOS_SELECTED: - // TODO(finnur): Implement. - onFileNotSelected(); + if (photos.length == 0) { + onFileNotSelected(); + return; + } + + if (photos.length == 1) { + GetDisplayNameTask task = + new GetDisplayNameTask(ContextUtils.getApplicationContext(), false); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Uri.parse(photos[0])); + return; + } else { + Uri[] filePathArray = new Uri[photos.length]; + for (int i = 0; i < photos.length; ++i) { + filePathArray[i] = Uri.parse(photos[i]); + } + GetDisplayNameTask task = + new GetDisplayNameTask(ContextUtils.getApplicationContext(), true); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, filePathArray); + } break; case LAUNCH_GALLERY: - // TODO(finnur): Implement. - onFileNotSelected(); + Intent intent = new Intent(); + intent.setType("image/*"); + if (mAllowMultiple) intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); + intent.setAction(Intent.ACTION_GET_CONTENT); + Activity activity = mWindowAndroid.getActivity().get(); + if (activity != null) { + String label = + activity.getResources().getString(R.string.photo_picker_select_images); + activity.startActivityForResult( + Intent.createChooser(intent, label), PhotoPickerListener.SHOW_GALLERY); + } break; case LAUNCH_CAMERA: - // TODO(finnur): Implement. - onFileNotSelected(); + new GetCameraIntentTask(true, mWindowAndroid, this) + .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; } } @@ -294,6 +321,17 @@ } private class GetCameraIntentTask extends AsyncTask<Void, Void, Uri> { + private Boolean mDirectToCamera; + private WindowAndroid mWindow; + private WindowAndroid.IntentCallback mCallback; + + public GetCameraIntentTask(Boolean directToCamera, WindowAndroid window, + WindowAndroid.IntentCallback callback) { + mDirectToCamera = directToCamera; + mWindow = window; + mCallback = callback; + } + @Override public Uri doInBackground(Void...voids) { try { @@ -323,7 +361,11 @@ mWindowAndroid.getApplicationContext().getContentResolver(), UiUtils.IMAGE_FILE_PATH, mCameraOutputUri)); } - launchSelectFileWithCameraIntent(true, camera); + if (mDirectToCamera) { + mWindow.showIntent(camera, mCallback, R.string.low_memory_error); + } else { + launchSelectFileWithCameraIntent(true, camera); + } } }
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index e0686043..f54fb01 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn
@@ -97,6 +97,8 @@ "cocoa/constrained_window/constrained_window_animation.mm", "cocoa/controls/blue_label_button.h", "cocoa/controls/blue_label_button.mm", + "cocoa/controls/button_utils.h", + "cocoa/controls/button_utils.mm", "cocoa/controls/hover_image_menu_button.h", "cocoa/controls/hover_image_menu_button.mm", "cocoa/controls/hover_image_menu_button_cell.h", @@ -105,6 +107,8 @@ "cocoa/controls/hyperlink_button_cell.mm", "cocoa/controls/hyperlink_text_view.h", "cocoa/controls/hyperlink_text_view.mm", + "cocoa/controls/textfield_utils.h", + "cocoa/controls/textfield_utils.mm", "cocoa/defaults_utils.h", "cocoa/defaults_utils.mm", "cocoa/find_pasteboard.h",
diff --git a/ui/base/cocoa/controls/button_utils.h b/ui/base/cocoa/controls/button_utils.h new file mode 100644 index 0000000..8759436 --- /dev/null +++ b/ui/base/cocoa/controls/button_utils.h
@@ -0,0 +1,30 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_COCOA_CONTROLS_BUTTON_UTILS_H_ +#define UI_BASE_COCOA_CONTROLS_BUTTON_UTILS_H_ + +#include "ui/base/ui_base_export.h" + +#include <Cocoa/Cocoa.h> + +UI_BASE_EXPORT +@interface ButtonUtils : NSObject + +// These methods are a polyfill for convenience constructors that exist on +// NSButton in macOS 10.12+. +// TODO(ellyjones): once we target only 10.12+, delete these and migrate callers +// over to NSButton directly. ++ (NSButton*)buttonWithTitle:(NSString*)title + action:(SEL)action + target:(id)target; + ++ (NSButton*)checkboxWithTitle:(NSString*)title; + ++ (NSButton*)linkWithTitle:(NSString*)title + action:(SEL)action + target:(id)target; +@end + +#endif // UI_BASE_COCOA_CONTROLS_BUTTON_UTILS_H_
diff --git a/ui/base/cocoa/controls/button_utils.mm b/ui/base/cocoa/controls/button_utils.mm new file mode 100644 index 0000000..51a3b44 --- /dev/null +++ b/ui/base/cocoa/controls/button_utils.mm
@@ -0,0 +1,48 @@ +// 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 "ui/base/cocoa/controls/button_utils.h" + +#import "ui/base/cocoa/controls/hyperlink_button_cell.h" + +@implementation ButtonUtils + ++ (NSButton*)buttonWithTitle:(NSString*)title + action:(SEL)action + target:(id)target { + NSButton* button = [[[NSButton alloc] initWithFrame:NSZeroRect] autorelease]; + [button setAction:action]; + [button setButtonType:NSMomentaryLightButton]; + [button setFocusRingType:NSFocusRingTypeExterior]; + [button setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; + [button setTarget:target]; + [button setTitle:title]; + [[button cell] setBezelStyle:NSRoundedBezelStyle]; + return button; +} + ++ (NSButton*)checkboxWithTitle:(NSString*)title { + NSButton* button = [[[NSButton alloc] initWithFrame:NSZeroRect] autorelease]; + [button setButtonType:NSSwitchButton]; + [button setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; + [button setBezelStyle:NSRegularSquareBezelStyle]; + [button setTitle:title]; + return button; +} + ++ (NSButton*)linkWithTitle:(NSString*)title + action:(SEL)action + target:(id)target { + NSButton* button = [[[NSButton alloc] initWithFrame:NSZeroRect] autorelease]; + // The cell has to be replaced before doing any of the other setup, or it will + // not get the new configuration. + [button setCell:[[[HyperlinkButtonCell alloc] init] autorelease]]; + [button setAction:action]; + [button setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; + [button setTarget:target]; + [button setTitle:title]; + return button; +} + +@end
diff --git a/ui/base/cocoa/controls/textfield_utils.h b/ui/base/cocoa/controls/textfield_utils.h new file mode 100644 index 0000000..dea04b8 --- /dev/null +++ b/ui/base/cocoa/controls/textfield_utils.h
@@ -0,0 +1,22 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_COCOA_CONTROLS_TEXTFIELD_UTILS_H_ +#define UI_BASE_COCOA_CONTROLS_TEXTFIELD_UTILS_H_ + +#include "ui/base/ui_base_export.h" + +#include <Cocoa/Cocoa.h> + +UI_BASE_EXPORT +@interface TextFieldUtils : NSObject + +// This method is a polyfill for a method on NSTextField on macOS 10.12+. +// TODO(ellyjones): Once we target only 10.12+, delete this and convert uses +// over to NSTextField. ++ (NSTextField*)labelWithString:(NSString*)text; + +@end + +#endif // UI_BASE_COCOA_CONTROLS_TEXTFIELD_UTILS_H_
diff --git a/ui/base/cocoa/controls/textfield_utils.mm b/ui/base/cocoa/controls/textfield_utils.mm new file mode 100644 index 0000000..74f546b9 --- /dev/null +++ b/ui/base/cocoa/controls/textfield_utils.mm
@@ -0,0 +1,20 @@ +// 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 "ui/base/cocoa/controls/textfield_utils.h" + +@implementation TextFieldUtils + ++ (NSTextField*)labelWithString:(NSString*)text { + NSTextField* textfield = + [[[NSTextField alloc] initWithFrame:NSZeroRect] autorelease]; + [textfield setBezeled:NO]; + [textfield setDrawsBackground:NO]; + [textfield setEditable:NO]; + [textfield setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; + [textfield setStringValue:text]; + return textfield; +} + +@end
diff --git a/ui/views/controls/webview/webview_unittest.cc b/ui/views/controls/webview/webview_unittest.cc index 5436b29..1d9b617 100644 --- a/ui/views/controls/webview/webview_unittest.cc +++ b/ui/views/controls/webview/webview_unittest.cc
@@ -10,12 +10,10 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" -#include "base/test/scoped_task_scheduler.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/test/test_browser_context.h" -#include "content/public/test/test_browser_thread.h" +#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/web_contents_tester.h" #include "content/test/test_content_browser_client.h" #include "ui/events/event.h" @@ -132,13 +130,7 @@ // Provides functionality to test a WebView. class WebViewUnitTest : public views::test::WidgetTest { public: - WebViewUnitTest() - : ui_thread_(content::BrowserThread::UI, base::MessageLoop::current()), - scoped_task_scheduler_(base::MessageLoop::current()), - file_blocking_thread_(content::BrowserThread::FILE_USER_BLOCKING, - base::MessageLoop::current()), - io_thread_(content::BrowserThread::IO, base::MessageLoop::current()), - top_level_widget_(nullptr) {} + WebViewUnitTest() = default; ~WebViewUnitTest() override {} @@ -185,15 +177,12 @@ } private: - content::TestBrowserThread ui_thread_; - base::test::ScopedTaskScheduler scoped_task_scheduler_; - content::TestBrowserThread file_blocking_thread_; - content::TestBrowserThread io_thread_; + content::TestBrowserThreadBundle test_browser_thread_bundle_; std::unique_ptr<content::TestBrowserContext> browser_context_; content::TestContentBrowserClient test_browser_client_; - Widget* top_level_widget_; - WebView* web_view_; + Widget* top_level_widget_ = nullptr; + WebView* web_view_ = nullptr; DISALLOW_COPY_AND_ASSIGN(WebViewUnitTest); };
diff --git a/ui/views/test/views_test_base.cc b/ui/views/test/views_test_base.cc index 4147f01..f7d9563a 100644 --- a/ui/views/test/views_test_base.cc +++ b/ui/views/test/views_test_base.cc
@@ -48,7 +48,9 @@ } // namespace ViewsTestBase::ViewsTestBase() - : setup_called_(false), + : scoped_task_environment_( + base::test::ScopedTaskEnvironment::MainThreadType::UI), + setup_called_(false), teardown_called_(false), has_compositing_manager_(InitializeVisuals()) {}
diff --git a/ui/views/test/views_test_base.h b/ui/views/test/views_test_base.h index 96763d0..af9760e 100644 --- a/ui/views/test/views_test_base.h +++ b/ui/views/test/views_test_base.h
@@ -8,7 +8,7 @@ #include <memory> #include "base/macros.h" -#include "base/message_loop/message_loop.h" +#include "base/test/scoped_task_environment.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -58,14 +58,12 @@ views_delegate_for_setup_.swap(views_delegate); } - base::MessageLoopForUI* message_loop() { return &message_loop_; } - // Returns a context view. In aura builds, this will be the // RootWindow. Everywhere else, NULL. gfx::NativeWindow GetContext(); private: - base::MessageLoopForUI message_loop_; + base::test::ScopedTaskEnvironment scoped_task_environment_; std::unique_ptr<TestViewsDelegate> views_delegate_for_setup_; std::unique_ptr<ScopedViewsTestHelper> test_helper_; bool setup_called_;
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc index 9c16dd9..b1027cf 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/cursor_client.h" @@ -257,7 +258,7 @@ // |RunWithDispatcher()| below. base::RunLoop run_loop; base::Closure quit_runloop = run_loop.QuitClosure(); - message_loop()->task_runner()->PostTask( + base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&QuitNestedLoopAndCloseWidget, base::Passed(&widget), base::Unretained(&quit_runloop)));
diff --git a/url/mojo/origin.mojom b/url/mojo/origin.mojom index 884357ba..90d1ef8 100644 --- a/url/mojo/origin.mojom +++ b/url/mojo/origin.mojom
@@ -8,5 +8,6 @@ string scheme; string host; uint16 port; + string suborigin; bool unique; };
diff --git a/url/mojo/origin_struct_traits.h b/url/mojo/origin_struct_traits.h index 3a10a41..3b8d453 100644 --- a/url/mojo/origin_struct_traits.h +++ b/url/mojo/origin_struct_traits.h
@@ -18,6 +18,9 @@ static uint16_t port(const url::Origin& r) { return r.port(); } + static const std::string& suborigin(const url::Origin& r) { + return r.suborigin(); + } static bool unique(const url::Origin& r) { return r.unique(); } @@ -25,12 +28,13 @@ if (data.unique()) { *out = url::Origin(); } else { - base::StringPiece scheme, host; - if (!data.ReadScheme(&scheme) || !data.ReadHost(&host)) + base::StringPiece scheme, host, suborigin; + if (!data.ReadScheme(&scheme) || !data.ReadHost(&host) || + !data.ReadSuborigin(&suborigin)) return false; - *out = url::Origin::UnsafelyCreateOriginWithoutNormalization(scheme, host, - data.port()); + *out = url::Origin::UnsafelyCreateOriginWithoutNormalization( + scheme, host, data.port(), suborigin); } // If a unique origin was created, but the unique flag wasn't set, then
diff --git a/url/mojo/url_gurl_struct_traits_unittest.cc b/url/mojo/url_gurl_struct_traits_unittest.cc index 8556e0a..d5efe74 100644 --- a/url/mojo/url_gurl_struct_traits_unittest.cc +++ b/url/mojo/url_gurl_struct_traits_unittest.cc
@@ -76,15 +76,21 @@ // Test basic Origin serialization. Origin non_unique = Origin::UnsafelyCreateOriginWithoutNormalization( - "http", "www.google.com", 80); + "http", "www.google.com", 80, ""); Origin output; EXPECT_TRUE(proxy->BounceOrigin(non_unique, &output)); EXPECT_EQ(non_unique, output); - EXPECT_FALSE(non_unique.unique()); + EXPECT_FALSE(output.unique()); Origin unique; EXPECT_TRUE(proxy->BounceOrigin(unique, &output)); EXPECT_TRUE(output.unique()); + + Origin with_sub_origin = Origin::CreateFromNormalizedTupleWithSuborigin( + "http", "www.google.com", 80, "suborigin"); + EXPECT_TRUE(proxy->BounceOrigin(with_sub_origin, &output)); + EXPECT_EQ(with_sub_origin, output); + EXPECT_FALSE(output.unique()); } } // namespace url
diff --git a/url/origin.cc b/url/origin.cc index 53600b1..d15ba43f 100644 --- a/url/origin.cc +++ b/url/origin.cc
@@ -107,8 +107,10 @@ Origin Origin::UnsafelyCreateOriginWithoutNormalization( base::StringPiece scheme, base::StringPiece host, - uint16_t port) { - return Origin(scheme, host, port, "", SchemeHostPort::CHECK_CANONICALIZATION); + uint16_t port, + base::StringPiece suborigin) { + return Origin(scheme, host, port, suborigin, + SchemeHostPort::CHECK_CANONICALIZATION); } Origin Origin::CreateFromNormalizedTupleWithSuborigin( @@ -173,7 +175,8 @@ } bool Origin::operator<(const Origin& other) const { - return tuple_ < other.tuple_; + return tuple_ < other.tuple_ || + (tuple_.Equals(other.tuple_) && suborigin_ < other.suborigin_); } std::ostream& operator<<(std::ostream& out, const url::Origin& origin) {
diff --git a/url/origin.h b/url/origin.h index 4b838e4..9e6b492a 100644 --- a/url/origin.h +++ b/url/origin.h
@@ -89,9 +89,9 @@ // 3. 'file' URLs all parse as ("file", "", 0). explicit Origin(const GURL& url); - // Creates an Origin from a |scheme|, |host|, and |port|. All the parameters - // must be valid and canonicalized. Do not use this method to create unique - // origins. Use Origin() for that. + // Creates an Origin from a |scheme|, |host|, |port| and |suborigin|. All the + // parameters must be valid and canonicalized. Do not use this method to + // create unique origins. Use Origin() for that. // // This constructor should be used in order to pass 'Origin' objects back and // forth over IPC (as transitioning through GURL would risk potentially @@ -100,7 +100,8 @@ static Origin UnsafelyCreateOriginWithoutNormalization( base::StringPiece scheme, base::StringPiece host, - uint16_t port); + uint16_t port, + base::StringPiece suborigin); // Creates an origin without sanity checking that the host is canonicalized. // This should only be used when converting between already normalized types,
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc index 4e1139c..b179591 100644 --- a/url/origin_unittest.cc +++ b/url/origin_unittest.cc
@@ -363,7 +363,7 @@ SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":" << test.port); url::Origin origin = url::Origin::UnsafelyCreateOriginWithoutNormalization( - test.scheme, test.host, test.port); + test.scheme, test.host, test.port, ""); EXPECT_EQ(test.scheme, origin.scheme()); EXPECT_EQ(test.host, origin.host()); EXPECT_EQ(test.port, origin.port()); @@ -400,7 +400,7 @@ SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":" << test.port); url::Origin origin = url::Origin::UnsafelyCreateOriginWithoutNormalization( - test.scheme, test.host, test.port); + test.scheme, test.host, test.port, ""); EXPECT_EQ("", origin.scheme()); EXPECT_EQ("", origin.host()); EXPECT_EQ(0, origin.port()); @@ -430,7 +430,7 @@ << test.port); url::Origin origin = url::Origin::UnsafelyCreateOriginWithoutNormalization( std::string(test.scheme, test.scheme_length), - std::string(test.host, test.host_length), test.port); + std::string(test.host, test.host_length), test.port, ""); EXPECT_EQ("", origin.scheme()); EXPECT_EQ("", origin.host()); EXPECT_EQ(0, origin.port());